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

Commit c84d203d authored by Chris Craik's avatar Chris Craik
Browse files

Add reconfigure method to Bitmap

bug:9797004

Grants a means to reuse a bitmap's allocation for different
width/height/Config without going through
BitmapFactoryOptions.inBitmap

Change-Id: Ib62319f3bd96c451fc1636288adf06a8275b4e3d
parent e77d6dd9
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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
+21 −0
Original line number Diff line number Diff line
@@ -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 },
+104 −7
Original line number Diff line number Diff line
@@ -171,6 +171,97 @@ public final class Bitmap implements Parcelable {
        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;
@@ -1428,6 +1523,8 @@ public final class Bitmap implements Parcelable {
                                            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,
+26 −20
Original line number Diff line number Diff line
@@ -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;