Merge "Never scale nine-patches in ImageDecoder" into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9cb6759072
@@ -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
|
||||||
|
|||||||
@@ -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"));
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user