Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9cb67590 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Never scale nine-patches in ImageDecoder" into pi-dev

parents ec3f8260 7d940ba4
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -763,7 +763,6 @@ Landroid/graphics/GraphicBuffer;->createFromExisting(IIIIJ)Landroid/graphics/Gra
Landroid/graphics/GraphicBuffer;->CREATOR:Landroid/os/Parcelable$Creator;
Landroid/graphics/GraphicBuffer;-><init>(IIIIJ)V
Landroid/graphics/GraphicBuffer;->mNativeObject:J
Landroid/graphics/ImageDecoder;-><init>(JIIZ)V
Landroid/graphics/ImageDecoder;->postProcessAndRelease(Landroid/graphics/Canvas;)I
Landroid/graphics/LinearGradient;->mColors:[I
Landroid/graphics/Matrix;->native_instance:J
+9 −13
Original line number Diff line number Diff line
@@ -116,9 +116,10 @@ static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream, jobj
    const auto& info = decoder->mCodec->getInfo();
    const int width = info.width();
    const int height = info.height();
    const bool isNinePatch = decoder->mPeeker->mPatch != nullptr;
    return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID,
                          reinterpret_cast<jlong>(decoder.release()), width, height,
                          animated);
                          animated, isNinePatch);
}

static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
@@ -332,13 +333,6 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong
        }
    }

    float scaleX = 1.0f;
    float scaleY = 1.0f;
    if (scale) {
        scaleX = (float) desiredWidth  / decodeInfo.width();
        scaleY = (float) desiredHeight / decodeInfo.height();
    }

    jbyteArray ninePatchChunk = nullptr;
    jobject ninePatchInsets = nullptr;

@@ -346,9 +340,6 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong
    if (!jpostProcess) {
        // FIXME: Share more code with BitmapFactory.cpp.
        if (decoder->mPeeker->mPatch != nullptr) {
            if (scale) {
                decoder->mPeeker->scale(scaleX, scaleY, desiredWidth, desiredHeight);
            }
            size_t ninePatchArraySize = decoder->mPeeker->mPatch->serializedSize();
            ninePatchChunk = env->NewByteArray(ninePatchArraySize);
            if (ninePatchChunk == nullptr) {
@@ -408,7 +399,12 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong

        SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy);
        canvas.translate(translateX, translateY);
        if (scale) {
            float scaleX = (float) desiredWidth  / decodeInfo.width();
            float scaleY = (float) desiredHeight / decodeInfo.height();
            canvas.scale(scaleX, scaleY);
        }

        canvas.drawBitmap(bm, 0.0f, 0.0f, &paint);

        bm.swap(scaledBm);
@@ -532,7 +528,7 @@ static const JNINativeMethod gImageDecoderMethods[] = {

int register_android_graphics_ImageDecoder(JNIEnv* env) {
    gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder"));
    gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZ)V");
    gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZZ)V");
    gImageDecoder_postProcessMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "postProcessAndRelease", "(Landroid/graphics/Canvas;)I");

    gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size"));
+30 −12
Original line number Diff line number Diff line
@@ -748,6 +748,7 @@ public final class ImageDecoder implements AutoCloseable {
    private final int     mWidth;
    private final int     mHeight;
    private final boolean mAnimated;
    private final boolean mIsNinePatch;

    private int        mDesiredWidth;
    private int        mDesiredHeight;
@@ -778,13 +779,14 @@ public final class ImageDecoder implements AutoCloseable {
     */
    @SuppressWarnings("unused")
    private ImageDecoder(long nativePtr, int width, int height,
            boolean animated) {
            boolean animated, boolean isNinePatch) {
        mNativePtr = nativePtr;
        mWidth = width;
        mHeight = height;
        mDesiredWidth = width;
        mDesiredHeight = height;
        mAnimated = animated;
        mIsNinePatch = isNinePatch;
        mCloseGuard.open("close");
    }

@@ -1665,7 +1667,7 @@ public final class ImageDecoder implements AutoCloseable {

            // this call potentially manipulates the decoder so it must be performed prior to
            // decoding the bitmap and after decode set the density on the resulting bitmap
            final int srcDensity = computeDensity(src, decoder);
            final int srcDensity = decoder.computeDensity(src);
            if (decoder.mAnimated) {
                // AnimatedImageDrawable calls postProcessAndRelease only if
                // mPostProcessor exists.
@@ -1755,7 +1757,7 @@ public final class ImageDecoder implements AutoCloseable {

            // this call potentially manipulates the decoder so it must be performed prior to
            // decoding the bitmap
            final int srcDensity = computeDensity(src, decoder);
            final int srcDensity = decoder.computeDensity(src);
            Bitmap bm = decoder.decodeBitmapInternal();
            bm.setDensity(srcDensity);

@@ -1772,12 +1774,26 @@ public final class ImageDecoder implements AutoCloseable {
    }

    // This method may modify the decoder so it must be called prior to performing the decode
    private static int computeDensity(@NonNull Source src, @NonNull ImageDecoder decoder) {
    private int computeDensity(@NonNull Source src) {
        // if the caller changed the size then we treat the density as unknown
        if (decoder.requestedResize()) {
        if (this.requestedResize()) {
            return Bitmap.DENSITY_NONE;
        }

        final int srcDensity = src.getDensity();
        if (srcDensity == Bitmap.DENSITY_NONE) {
            return srcDensity;
        }

        // Scaling up nine-patch divs is imprecise and is better handled
        // at draw time. An app won't be relying on the internal Bitmap's
        // size, so it is safe to let NinePatchDrawable handle scaling.
        // mPostProcessor disables nine-patching, so behave normally if
        // it is present.
        if (mIsNinePatch && mPostProcessor == null) {
            return srcDensity;
        }

        // Special stuff for compatibility mode: if the target density is not
        // the same as the display density, but the resource -is- the same as
        // the display density, then don't scale it down to the target density.
@@ -1786,23 +1802,25 @@ public final class ImageDecoder implements AutoCloseable {
        // to the compatibility density only to have them scaled back up when
        // drawn to the screen.
        Resources res = src.getResources();
        final int srcDensity = src.getDensity();
        if (res != null && res.getDisplayMetrics().noncompatDensityDpi == srcDensity) {
            return srcDensity;
        }

        final int dstDensity = src.computeDstDensity();
        if (srcDensity == dstDensity) {
            return srcDensity;
        }

        // For P and above, only resize if it would be a downscale. Scale up prior
        // to P in case the app relies on the Bitmap's size without considering density.
        final int dstDensity = src.computeDstDensity();
        if (srcDensity == Bitmap.DENSITY_NONE || srcDensity == dstDensity
                || (srcDensity < dstDensity && sApiLevel >= Build.VERSION_CODES.P)) {
        if (srcDensity < dstDensity && sApiLevel >= Build.VERSION_CODES.P) {
            return srcDensity;
        }

        float scale = (float) dstDensity / srcDensity;
        int scaledWidth = (int) (decoder.mWidth * scale + 0.5f);
        int scaledHeight = (int) (decoder.mHeight * scale + 0.5f);
        decoder.setTargetSize(scaledWidth, scaledHeight);
        int scaledWidth = (int) (mWidth * scale + 0.5f);
        int scaledHeight = (int) (mHeight * scale + 0.5f);
        this.setTargetSize(scaledWidth, scaledHeight);
        return dstDensity;
    }