Merge "Revert "Use ImageDecoder for NinePatchDrawable and BitmapDrawable""

This commit is contained in:
TreeHugger Robot
2018-02-13 20:13:04 +00:00
committed by Android (Google) Code Review
5 changed files with 43 additions and 172 deletions

View File

@@ -23,10 +23,6 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -400,33 +396,6 @@ public final class PointerIcon implements Parcelable {
return true;
}
/**
* Get the Bitmap from the Drawable.
*
* If the Bitmap needed to be scaled up to account for density, BitmapDrawable
* handles this at draw time. But this class doesn't actually draw the Bitmap;
* it is just a holder for native code to access its SkBitmap. So this needs to
* get a version that is scaled to account for density.
*/
private Bitmap getBitmapFromDrawable(BitmapDrawable bitmapDrawable) {
Bitmap bitmap = bitmapDrawable.getBitmap();
final int scaledWidth = bitmapDrawable.getIntrinsicWidth();
final int scaledHeight = bitmapDrawable.getIntrinsicHeight();
if (scaledWidth == bitmap.getWidth() && scaledHeight == bitmap.getHeight()) {
return bitmap;
}
Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
RectF dst = new RectF(0, 0, scaledWidth, scaledHeight);
Bitmap scaled = Bitmap.createBitmap(scaledWidth, scaledHeight, bitmap.getConfig());
Canvas canvas = new Canvas(scaled);
Paint paint = new Paint();
paint.setFilterBitmap(true);
canvas.drawBitmap(bitmap, src, dst, paint);
return scaled;
}
private void loadResource(Context context, Resources resources, @XmlRes int resourceId) {
final XmlResourceParser parser = resources.getXml(resourceId);
final int bitmapRes;
@@ -483,8 +452,7 @@ public final class PointerIcon implements Parcelable {
+ "is different. All frames should have the exact same size and "
+ "share the same hotspot.");
}
BitmapDrawable bitmapDrawableFrame = (BitmapDrawable) drawableFrame;
mBitmapFrames[i - 1] = getBitmapFromDrawable(bitmapDrawableFrame);
mBitmapFrames[i - 1] = ((BitmapDrawable)drawableFrame).getBitmap();
}
}
}
@@ -493,8 +461,7 @@ public final class PointerIcon implements Parcelable {
+ "refer to a bitmap drawable.");
}
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
final Bitmap bitmap = getBitmapFromDrawable(bitmapDrawable);
final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
validateHotSpot(bitmap, hotSpotX, hotSpotY);
// Set the properties now that we have successfully loaded the icon.
mBitmap = bitmap;

View File

@@ -444,7 +444,6 @@ public final class ImageDecoder implements AutoCloseable {
private boolean mPreferRamOverQuality = false;
private boolean mAsAlphaMask = false;
private Rect mCropRect;
private Rect mOutPaddingRect;
private Source mSource;
private PostProcessor mPostProcessor;
@@ -782,18 +781,6 @@ public final class ImageDecoder implements AutoCloseable {
mCropRect = subset;
}
/**
* Set a Rect for retrieving nine patch padding.
*
* If the image is a nine patch, this Rect will be set to the padding
* rectangle during decode. Otherwise it will not be modified.
*
* @hide
*/
public void setOutPaddingRect(@NonNull Rect outPadding) {
mOutPaddingRect = outPadding;
}
/**
* Specify whether the {@link Bitmap} should be mutable.
*
@@ -905,6 +892,7 @@ public final class ImageDecoder implements AutoCloseable {
postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect,
mMutable, mAllocator, mRequireUnpremultiplied,
mPreferRamOverQuality, mAsAlphaMask);
}
private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -977,10 +965,7 @@ public final class ImageDecoder implements AutoCloseable {
if (np != null && NinePatch.isNinePatchChunk(np)) {
Rect opticalInsets = new Rect();
bm.getOpticalInsets(opticalInsets);
Rect padding = decoder.mOutPaddingRect;
if (padding == null) {
padding = new Rect();
}
Rect padding = new Rect();
nGetPadding(decoder.mNativePtr, padding);
return new NinePatchDrawable(res, bm, np, padding,
opticalInsets, null);
@@ -1023,15 +1008,6 @@ public final class ImageDecoder implements AutoCloseable {
final int srcDensity = computeDensity(src, decoder);
Bitmap bm = decoder.decodeBitmap();
bm.setDensity(srcDensity);
Rect padding = decoder.mOutPaddingRect;
if (padding != null) {
byte[] np = bm.getNinePatchChunk();
if (np != null && NinePatch.isNinePatchChunk(np)) {
nGetPadding(decoder.mNativePtr, padding);
}
}
return bm;
}
}

View File

@@ -27,7 +27,6 @@ import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.ImageDecoder;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Outline;
@@ -50,7 +49,6 @@ import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -113,7 +111,7 @@ public class BitmapDrawable extends Drawable {
*/
@Deprecated
public BitmapDrawable() {
init(new BitmapState((Bitmap) null), null);
mBitmapState = new BitmapState((Bitmap) null);
}
/**
@@ -126,7 +124,8 @@ public class BitmapDrawable extends Drawable {
@SuppressWarnings("unused")
@Deprecated
public BitmapDrawable(Resources res) {
init(new BitmapState((Bitmap) null), res);
mBitmapState = new BitmapState((Bitmap) null);
mBitmapState.mTargetDensity = mTargetDensity;
}
/**
@@ -136,7 +135,7 @@ public class BitmapDrawable extends Drawable {
*/
@Deprecated
public BitmapDrawable(Bitmap bitmap) {
init(new BitmapState(bitmap), null);
this(new BitmapState(bitmap), null);
}
/**
@@ -144,7 +143,8 @@ public class BitmapDrawable extends Drawable {
* the display metrics of the resources.
*/
public BitmapDrawable(Resources res, Bitmap bitmap) {
init(new BitmapState(bitmap), res);
this(new BitmapState(bitmap), res);
mBitmapState.mTargetDensity = mTargetDensity;
}
/**
@@ -154,7 +154,10 @@ public class BitmapDrawable extends Drawable {
*/
@Deprecated
public BitmapDrawable(String filepath) {
this(null, filepath);
this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
}
}
/**
@@ -162,21 +165,10 @@ public class BitmapDrawable extends Drawable {
*/
@SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" })
public BitmapDrawable(Resources res, String filepath) {
Bitmap bitmap = null;
try (FileInputStream stream = new FileInputStream(filepath)) {
bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, stream),
(decoder, info, src) -> {
decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
});
} catch (Exception e) {
/* do nothing. This matches the behavior of BitmapFactory.decodeFile()
If the exception happened on decode, mBitmapState.mBitmap will be null.
*/
} finally {
init(new BitmapState(bitmap), res);
if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
}
this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
mBitmapState.mTargetDensity = mTargetDensity;
if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
}
}
@@ -187,7 +179,10 @@ public class BitmapDrawable extends Drawable {
*/
@Deprecated
public BitmapDrawable(java.io.InputStream is) {
this(null, is);
this(new BitmapState(BitmapFactory.decodeStream(is)), null);
if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
}
}
/**
@@ -195,21 +190,10 @@ public class BitmapDrawable extends Drawable {
*/
@SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" })
public BitmapDrawable(Resources res, java.io.InputStream is) {
Bitmap bitmap = null;
try {
bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, is),
(decoder, info, src) -> {
decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
});
} catch (Exception e) {
/* do nothing. This matches the behavior of BitmapFactory.decodeStream()
If the exception happened on decode, mBitmapState.mBitmap will be null.
*/
} finally {
init(new BitmapState(bitmap), res);
if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
}
this(new BitmapState(BitmapFactory.decodeStream(is)), null);
mBitmapState.mTargetDensity = mTargetDensity;
if (mBitmapState.mBitmap == null) {
android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
}
}
@@ -828,19 +812,9 @@ public class BitmapDrawable extends Drawable {
}
}
int density = Bitmap.DENSITY_NONE;
if (value.density == TypedValue.DENSITY_DEFAULT) {
density = DisplayMetrics.DENSITY_DEFAULT;
} else if (value.density != TypedValue.DENSITY_NONE) {
density = value.density;
}
Bitmap bitmap = null;
try (InputStream is = r.openRawResource(srcResId, value)) {
ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> {
decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
});
bitmap = BitmapFactory.decodeResourceStream(r, value, is, null, null);
} catch (Exception e) {
// Do nothing and pick up the error below.
}
@@ -1039,21 +1013,14 @@ public class BitmapDrawable extends Drawable {
}
}
private BitmapDrawable(BitmapState state, Resources res) {
init(state, res);
}
/**
* The one helper to rule them all. This is called by all public & private
* The one constructor to rule them all. This is called by all public
* constructors to set the state and initialize local properties.
*/
private void init(BitmapState state, Resources res) {
private BitmapDrawable(BitmapState state, Resources res) {
mBitmapState = state;
updateLocalState(res);
if (mBitmapState != null && res != null) {
mBitmapState.mTargetDensity = mTargetDensity;
}
updateLocalState(res);
}
/**

View File

@@ -37,7 +37,6 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.ImageDecoder;
import android.graphics.Insets;
import android.graphics.NinePatch;
import android.graphics.Outline;
@@ -51,13 +50,11 @@ import android.graphics.Xfermode;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.StateSet;
import android.util.TypedValue;
import android.util.Xml;
import android.view.View;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
@@ -1182,10 +1179,6 @@ public abstract class Drawable {
return null;
}
if (opts == null) {
return getBitmapDrawable(res, value, is);
}
/* ugh. The decodeStream contract is that we have already allocated
the pad rect, but if the bitmap does not had a ninepatch chunk,
then the pad will be ignored. If we could change this to lazily
@@ -1201,6 +1194,7 @@ public abstract class Drawable {
// an application in compatibility mode, without scaling those down
// to the compatibility density only to have them scaled back up when
// drawn to the screen.
if (opts == null) opts = new BitmapFactory.Options();
opts.inScreenDensity = Drawable.resolveDensity(res, 0);
Bitmap bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
if (bm != null) {
@@ -1217,33 +1211,6 @@ public abstract class Drawable {
return null;
}
private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) {
try {
ImageDecoder.Source source = null;
if (value != null) {
int density = Bitmap.DENSITY_NONE;
if (value.density == TypedValue.DENSITY_DEFAULT) {
density = DisplayMetrics.DENSITY_DEFAULT;
} else if (value.density != TypedValue.DENSITY_NONE) {
density = value.density;
}
source = ImageDecoder.createSource(res, is, density);
} else {
source = ImageDecoder.createSource(res, is);
}
return ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
});
} catch (IOException e) {
/* do nothing.
If the exception happened on decode, the drawable will be null.
*/
Log.e("Drawable", "Unable to decode stream: " + e);
}
return null;
}
/**
* Create a drawable from an XML document. For more information on how to
* create resources in XML, see
@@ -1343,10 +1310,11 @@ public abstract class Drawable {
}
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
try (FileInputStream stream = new FileInputStream(pathName)) {
return getBitmapDrawable(null, null, stream);
} catch(IOException e) {
// Do nothing; we will just return null if the FileInputStream had an error
try {
Bitmap bm = BitmapFactory.decodeFile(pathName);
if (bm != null) {
return drawableFromBitmap(null, bm, null, null, null, pathName);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}

View File

@@ -24,9 +24,9 @@ import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.ImageDecoder;
import android.graphics.Insets;
import android.graphics.NinePatch;
import android.graphics.Outline;
@@ -211,8 +211,7 @@ public class NinePatchDrawable extends Drawable {
restoreAlpha = -1;
}
final boolean needsDensityScaling = canvas.getDensity() == 0
&& Bitmap.DENSITY_NONE != state.mNinePatch.getDensity();
final boolean needsDensityScaling = canvas.getDensity() == 0;
if (needsDensityScaling) {
restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
@@ -422,6 +421,10 @@ public class NinePatchDrawable extends Drawable {
final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
if (srcResId != 0) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = !state.mDither;
options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi;
final Rect padding = new Rect();
final Rect opticalInsets = new Rect();
Bitmap bitmap = null;
@@ -430,17 +433,7 @@ public class NinePatchDrawable extends Drawable {
final TypedValue value = new TypedValue();
final InputStream is = r.openRawResource(srcResId, value);
int density = Bitmap.DENSITY_NONE;
if (value.density == TypedValue.DENSITY_DEFAULT) {
density = DisplayMetrics.DENSITY_DEFAULT;
} else if (value.density != TypedValue.DENSITY_NONE) {
density = value.density;
}
ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> {
decoder.setOutPaddingRect(padding);
decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
});
bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options);
is.close();
} catch (IOException e) {