diff options
-rw-r--r-- | api/current.txt | 4 | ||||
-rw-r--r-- | core/jni/android/graphics/Bitmap.cpp | 21 | ||||
-rw-r--r-- | graphics/java/android/graphics/Bitmap.java | 111 | ||||
-rw-r--r-- | graphics/java/android/graphics/BitmapFactory.java | 46 |
4 files changed, 155 insertions, 27 deletions
diff --git a/api/current.txt b/api/current.txt index 201dc58a8fa3..8d03c37a3a42 100644 --- a/api/current.txt +++ b/api/current.txt @@ -8742,13 +8742,17 @@ package android.graphics { method public final boolean isPremultiplied(); method public final boolean isRecycled(); method public void prepareToDraw(); + method public void reconfigure(int, int, android.graphics.Bitmap.Config); method public void recycle(); method public boolean sameAs(android.graphics.Bitmap); + method public void setConfig(android.graphics.Bitmap.Config); method public void setDensity(int); method public void setHasAlpha(boolean); method public final void setHasMipMap(boolean); + method public void setHeight(int); method public void setPixel(int, int, int); method public void setPixels(int[], int, int, int, int, int, int); + method public void setWidth(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public static final int DENSITY_NONE = 0; // 0x0 diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 63683b4f4954..b03d12aa2057 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -271,6 +271,26 @@ static jboolean Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) { return true;
}
+static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jint bitmapInt,
+ int width, int height, SkBitmap::Config config, int allocSize) {
+ if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {
+ // done in native as there's no way to get BytesPerPixel in Java
+ doThrowIAE(env, "Bitmap not large enough to support new configuration");
+ return;
+ }
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapInt);
+ SkPixelRef* ref = bitmap->pixelRef();
+ SkSafeRef(ref);
+ bitmap->setConfig(config, width, height);
+ bitmap->setPixelRef(ref);
+
+ // notifyPixelsChanged will increment the generation ID even though the actual pixel data
+ // hasn't been touched. This signals the renderer that the bitmap (including width, height,
+ // and config) has changed.
+ ref->notifyPixelsChanged();
+ SkSafeUnref(ref);
+}
+
// These must match the int values in Bitmap.java
enum JavaEncodeFormat {
kJPEG_JavaEncodeFormat = 0,
@@ -666,6 +686,7 @@ static JNINativeMethod gBitmapMethods[] = { (void*)Bitmap_copy },
{ "nativeDestructor", "(I)V", (void*)Bitmap_destructor },
{ "nativeRecycle", "(I)Z", (void*)Bitmap_recycle },
+ { "nativeReconfigure", "(IIIII)V", (void*)Bitmap_reconfigure },
{ "nativeCompress", "(IIILjava/io/OutputStream;[B)Z",
(void*)Bitmap_compress },
{ "nativeErase", "(II)V", (void*)Bitmap_erase },
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 50231da8f17c..ad5bfc8007fb 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -170,7 +170,98 @@ public final class Bitmap implements Parcelable { public void setDensity(int density) { mDensity = density; } - + + /** + * <p>Modifies the bitmap to have a specified width, height, and {@link + * Config}, without affecting the underlying allocation backing the bitmap. + * Bitmap pixel data is not re-initialized for the new configuration.</p> + * + * <p>This method can be used to avoid allocating a new bitmap, instead + * reusing an existing bitmap's allocation for a new configuration of equal + * or lesser size. If the Bitmap's allocation isn't large enough to support + * the new configuration, an IllegalArgumentException will be thrown and the + * bitmap will not be modified.</p> + * + * <p>The result of {@link #getByteCount()} will reflect the new configuration, + * while {@link #getAllocationByteCount()} will reflect that of the initial + * configuration.</p> + * + * <p>WARNING: This method should NOT be called on a bitmap currently used + * by the view system. It does not make guarantees about how the underlying + * pixel buffer is remapped to the new config, just that the allocation is + * reused. Additionally, the view system does not account for bitmap + * properties being modifying during use, e.g. while attached to + * drawables.</p> + * + * @see #setWidth(int) + * @see #setHeight(int) + * @see #setConfig(Config) + */ + public void reconfigure(int width, int height, Config config) { + checkRecycled("Can't call reconfigure() on a recycled bitmap"); + if (width <= 0 || height <= 0) { + throw new IllegalArgumentException("width and height must be > 0"); + } + if (!isMutable()) { + throw new IllegalArgumentException("only mutable bitmaps may be reconfigured"); + } + if (mBuffer == null) { + throw new IllegalArgumentException("only non-inPurgeable bitmaps may be reconfigured"); + } + + nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length); + mWidth = width; + mHeight = height; + } + + /** + * <p>Convenience method for calling {@link #reconfigure(int, int, Config)} + * with the current height and config.</p> + * + * <p>WARNING: this method should not be used on bitmaps currently used by + * the view system, see {@link #reconfigure(int, int, Config)} for more + * details.</p> + * + * @see #reconfigure(int, int, Config) + * @see #setHeight(int) + * @see #setConfig(Config) + */ + public void setWidth(int width) { + reconfigure(width, getHeight(), getConfig()); + } + + /** + * <p>Convenience method for calling {@link #reconfigure(int, int, Config)} + * with the current width and config.</p> + * + * <p>WARNING: this method should not be used on bitmaps currently used by + * the view system, see {@link #reconfigure(int, int, Config)} for more + * details.</p> + * + * @see #reconfigure(int, int, Config) + * @see #setWidth(int) + * @see #setConfig(Config) + */ + public void setHeight(int height) { + reconfigure(getWidth(), height, getConfig()); + } + + /** + * <p>Convenience method for calling {@link #reconfigure(int, int, Config)} + * with the current height and width.</p> + * + * <p>WARNING: this method should not be used on bitmaps currently used by + * the view system, see {@link #reconfigure(int, int, Config)} for more + * details.</p> + * + * @see #reconfigure(int, int, Config) + * @see #setWidth(int) + * @see #setHeight(int) + */ + public void setConfig(Config config) { + reconfigure(getWidth(), getHeight(), config); + } + /** * Sets the nine patch chunk. * @@ -1010,7 +1101,7 @@ public final class Bitmap implements Parcelable { * * <p>As of {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, the result of this method can * no longer be used to determine memory usage of a bitmap. See {@link - * #getAllocationByteCount()}. + * #getAllocationByteCount()}.</p> */ public final int getByteCount() { // int result permits bitmaps up to 46,340 x 46,340 @@ -1021,11 +1112,15 @@ public final class Bitmap implements Parcelable { * Returns the size of the allocated memory used to store this bitmap's pixels. * * <p>This can be larger than the result of {@link #getByteCount()} if a bitmap is reused to - * decode other bitmaps of smaller size. See {@link BitmapFactory.Options#inBitmap inBitmap in - * BitmapFactory.Options}. If a bitmap is not reused in this way, this value will be the same as - * that returned by {@link #getByteCount()}. + * decode other bitmaps of smaller size, or by manual reconfiguration. See {@link + * #reconfigure(int, int, Config)}, {@link #setWidth(int)}, {@link #setHeight(int)}, {@link + * #setConfig(Bitmap.Config)}, and {@link BitmapFactory.Options#inBitmap + * BitmapFactory.Options.inBitmap}. If a bitmap is not modified in this way, this value will be + * the same as that returned by {@link #getByteCount()}.</p> + * + * <p>This value will not change over the lifetime of a Bitmap.</p> * - * <p>This value will not change over the lifetime of a Bitmap. + * @see #reconfigure(int, int, Config) */ public final int getAllocationByteCount() { return mBuffer.length; @@ -1423,11 +1518,13 @@ public final class Bitmap implements Parcelable { private static native Bitmap nativeCreate(int[] colors, int offset, int stride, int width, int height, - int nativeConfig, boolean mutable); + int nativeConfig, boolean mutable); private static native Bitmap nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable); private static native void nativeDestructor(int nativeBitmap); private static native boolean nativeRecycle(int nativeBitmap); + private static native void nativeReconfigure(int nativeBitmap, int width, int height, + int config, int allocSize); private static native boolean nativeCompress(int nativeBitmap, int format, int quality, OutputStream stream, diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index aff4cd8b9c6a..a4124bfc8481 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -48,34 +48,40 @@ public class BitmapFactory { /** * If set, decode methods that take the Options object will attempt to - * reuse this bitmap when loading content. If the decode operation cannot - * use this bitmap, the decode method will return <code>null</code> and - * will throw an IllegalArgumentException. The current implementation - * necessitates that the reused bitmap be mutable, and the resulting - * reused bitmap will continue to remain mutable even when decoding a - * resource which would normally result in an immutable bitmap. + * reuse this bitmap when loading content. If the decode operation + * cannot use this bitmap, the decode method will return + * <code>null</code> and will throw an IllegalArgumentException. The + * current implementation necessitates that the reused bitmap be + * mutable, and the resulting reused bitmap will continue to remain + * mutable even when decoding a resource which would normally result in + * an immutable bitmap.</p> * - * <p>As of {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, any mutable - * bitmap can be reused to decode any other bitmaps as long as the resulting - * {@link Bitmap#getByteCount() byte count} of the decoded bitmap is less - * than or equal to the {@link Bitmap#getAllocationByteCount() allocated byte count} - * of the reused bitmap. This can be because the intrinsic size is smaller, - * or the size after density / sampled size scaling is smaller. + * <p>As of {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, any + * mutable bitmap can be reused to decode any other bitmaps as long as + * the resulting {@link Bitmap#getByteCount() byte count} of the decoded + * bitmap is less than or equal to the {@link + * Bitmap#getAllocationByteCount() allocated byte count} of the reused + * bitmap. This can be because the intrinsic size is smaller, or its + * size post scaling (for density / sample size) is smaller.</p> * - * <p>Prior to {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE} additional - * constraints apply: The image being decoded (whether as a resource or - * as a stream) must be in jpeg or png format. Only equal sized bitmaps - * are supported, with {@link #inSampleSize} set to 1. Additionally, the - * {@link android.graphics.Bitmap.Config configuration} of the reused - * bitmap will override the setting of {@link #inPreferredConfig}, if set. + * <p>Prior to {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE} + * additional constraints apply: The image being decoded (whether as a + * resource or as a stream) must be in jpeg or png format. Only equal + * sized bitmaps are supported, with {@link #inSampleSize} set to 1. + * Additionally, the {@link android.graphics.Bitmap.Config + * configuration} of the reused bitmap will override the setting of + * {@link #inPreferredConfig}, if set.</p> * * <p>You should still always use the returned Bitmap of the decode * method and not assume that reusing the bitmap worked, due to the * constraints outlined above and failure situations that can occur. * Checking whether the return value matches the value of the inBitmap * set in the Options structure will indicate if the bitmap was reused, - * but in all cases you should use the Bitmap returned by the decoding function to ensure - * that you are using the bitmap that was used as the decode destination.</p> + * but in all cases you should use the Bitmap returned by the decoding + * function to ensure that you are using the bitmap that was used as the + * decode destination.</p> + * + * @see Bitmap#reconfigure(int,int,Config) */ public Bitmap inBitmap; |