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

This commit is contained in:
TreeHugger Robot
2018-04-05 22:42:39 +00:00
committed by Android (Google) Code Review
3 changed files with 39 additions and 26 deletions

View File

@@ -763,7 +763,6 @@ Landroid/graphics/GraphicBuffer;->createFromExisting(IIIIJ)Landroid/graphics/Gra
Landroid/graphics/GraphicBuffer;->CREATOR:Landroid/os/Parcelable$Creator; Landroid/graphics/GraphicBuffer;->CREATOR:Landroid/os/Parcelable$Creator;
Landroid/graphics/GraphicBuffer;-><init>(IIIIJ)V Landroid/graphics/GraphicBuffer;-><init>(IIIIJ)V
Landroid/graphics/GraphicBuffer;->mNativeObject:J Landroid/graphics/GraphicBuffer;->mNativeObject:J
Landroid/graphics/ImageDecoder;-><init>(JIIZ)V
Landroid/graphics/ImageDecoder;->postProcessAndRelease(Landroid/graphics/Canvas;)I Landroid/graphics/ImageDecoder;->postProcessAndRelease(Landroid/graphics/Canvas;)I
Landroid/graphics/LinearGradient;->mColors:[I Landroid/graphics/LinearGradient;->mColors:[I
Landroid/graphics/Matrix;->native_instance:J Landroid/graphics/Matrix;->native_instance:J

View File

@@ -116,9 +116,10 @@ static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream, jobj
const auto& info = decoder->mCodec->getInfo(); const auto& info = decoder->mCodec->getInfo();
const int width = info.width(); const int width = info.width();
const int height = info.height(); const int height = info.height();
const bool isNinePatch = decoder->mPeeker->mPatch != nullptr;
return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID, return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID,
reinterpret_cast<jlong>(decoder.release()), width, height, reinterpret_cast<jlong>(decoder.release()), width, height,
animated); animated, isNinePatch);
} }
static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/, 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; jbyteArray ninePatchChunk = nullptr;
jobject ninePatchInsets = nullptr; jobject ninePatchInsets = nullptr;
@@ -346,9 +340,6 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong
if (!jpostProcess) { if (!jpostProcess) {
// FIXME: Share more code with BitmapFactory.cpp. // FIXME: Share more code with BitmapFactory.cpp.
if (decoder->mPeeker->mPatch != nullptr) { if (decoder->mPeeker->mPatch != nullptr) {
if (scale) {
decoder->mPeeker->scale(scaleX, scaleY, desiredWidth, desiredHeight);
}
size_t ninePatchArraySize = decoder->mPeeker->mPatch->serializedSize(); size_t ninePatchArraySize = decoder->mPeeker->mPatch->serializedSize();
ninePatchChunk = env->NewByteArray(ninePatchArraySize); ninePatchChunk = env->NewByteArray(ninePatchArraySize);
if (ninePatchChunk == nullptr) { if (ninePatchChunk == nullptr) {
@@ -408,7 +399,12 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong
SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy); SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy);
canvas.translate(translateX, translateY); canvas.translate(translateX, translateY);
canvas.scale(scaleX, scaleY); 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); canvas.drawBitmap(bm, 0.0f, 0.0f, &paint);
bm.swap(scaledBm); bm.swap(scaledBm);
@@ -532,7 +528,7 @@ static const JNINativeMethod gImageDecoderMethods[] = {
int register_android_graphics_ImageDecoder(JNIEnv* env) { int register_android_graphics_ImageDecoder(JNIEnv* env) {
gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder")); 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"); gImageDecoder_postProcessMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "postProcessAndRelease", "(Landroid/graphics/Canvas;)I");
gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size")); gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size"));

View File

@@ -748,6 +748,7 @@ public final class ImageDecoder implements AutoCloseable {
private final int mWidth; private final int mWidth;
private final int mHeight; private final int mHeight;
private final boolean mAnimated; private final boolean mAnimated;
private final boolean mIsNinePatch;
private int mDesiredWidth; private int mDesiredWidth;
private int mDesiredHeight; private int mDesiredHeight;
@@ -778,13 +779,14 @@ public final class ImageDecoder implements AutoCloseable {
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
private ImageDecoder(long nativePtr, int width, int height, private ImageDecoder(long nativePtr, int width, int height,
boolean animated) { boolean animated, boolean isNinePatch) {
mNativePtr = nativePtr; mNativePtr = nativePtr;
mWidth = width; mWidth = width;
mHeight = height; mHeight = height;
mDesiredWidth = width; mDesiredWidth = width;
mDesiredHeight = height; mDesiredHeight = height;
mAnimated = animated; mAnimated = animated;
mIsNinePatch = isNinePatch;
mCloseGuard.open("close"); 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 // 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 // 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) { if (decoder.mAnimated) {
// AnimatedImageDrawable calls postProcessAndRelease only if // AnimatedImageDrawable calls postProcessAndRelease only if
// mPostProcessor exists. // 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 // this call potentially manipulates the decoder so it must be performed prior to
// decoding the bitmap // decoding the bitmap
final int srcDensity = computeDensity(src, decoder); final int srcDensity = decoder.computeDensity(src);
Bitmap bm = decoder.decodeBitmapInternal(); Bitmap bm = decoder.decodeBitmapInternal();
bm.setDensity(srcDensity); 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 // 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 the caller changed the size then we treat the density as unknown
if (decoder.requestedResize()) { if (this.requestedResize()) {
return Bitmap.DENSITY_NONE; 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 // 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 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. // 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 // to the compatibility density only to have them scaled back up when
// drawn to the screen. // drawn to the screen.
Resources res = src.getResources(); Resources res = src.getResources();
final int srcDensity = src.getDensity();
if (res != null && res.getDisplayMetrics().noncompatDensityDpi == srcDensity) { if (res != null && res.getDisplayMetrics().noncompatDensityDpi == srcDensity) {
return 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 // 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. // to P in case the app relies on the Bitmap's size without considering density.
final int dstDensity = src.computeDstDensity(); if (srcDensity < dstDensity && sApiLevel >= Build.VERSION_CODES.P) {
if (srcDensity == Bitmap.DENSITY_NONE || srcDensity == dstDensity
|| (srcDensity < dstDensity && sApiLevel >= Build.VERSION_CODES.P)) {
return srcDensity; return srcDensity;
} }
float scale = (float) dstDensity / srcDensity; float scale = (float) dstDensity / srcDensity;
int scaledWidth = (int) (decoder.mWidth * scale + 0.5f); int scaledWidth = (int) (mWidth * scale + 0.5f);
int scaledHeight = (int) (decoder.mHeight * scale + 0.5f); int scaledHeight = (int) (mHeight * scale + 0.5f);
decoder.setTargetSize(scaledWidth, scaledHeight); this.setTargetSize(scaledWidth, scaledHeight);
return dstDensity; return dstDensity;
} }