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

Commit e7b5129c authored by Nader Jawad's avatar Nader Jawad
Browse files

Updated Bitmap mutablity documentation and removed Bitmap#mIsMutable

flag

Updated Bitmap java and native implementation to redirect queries of
mutability to the native implementation provided by Skia. Updated
documentation of Bitmap.createBitmap method to accurately describe
mutability of the Bitmap result based on various inputs.
Removed flag from Bitmap class in favor of querying jni API directly.
Updated Bitmap constructor to no longer utilize mutable parameter
provided by jni call. Created hidden setImmutable method that invokes
corresponding native method to flip the Bitmap's mutability flag.

Fixes: 65560449
Test: Re-ran CTS tests and updated Bitmap tests to verify mutability of
all creation methods

Change-Id: I1b0b9de2fc15369b4e3f83512b866915387ac926
parent d75cf83a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -791,7 +791,7 @@ Landroid/graphics/BitmapFactory;->nativeDecodeByteArray([BIILandroid/graphics/Bi
Landroid/graphics/BitmapFactory;->nativeDecodeFileDescriptor(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;
Landroid/graphics/BitmapFactory;->nativeDecodeStream(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;
Landroid/graphics/Bitmap;->getDefaultDensity()I
Landroid/graphics/Bitmap;-><init>(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V
Landroid/graphics/Bitmap;-><init>(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;)V
Landroid/graphics/Bitmap;->mNativePtr:J
Landroid/graphics/Bitmap;->mNinePatchChunk:[B
Landroid/graphics/Bitmap;->mNinePatchInsets:Landroid/graphics/NinePatch$InsetStruct;
+24 −2
Original line number Diff line number Diff line
@@ -205,9 +205,12 @@ jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
    // native SkBitmap stays in sync with the Java Bitmap.
    assert_premultiplied(bitmap->info(), isPremultiplied);
    BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap);
    if (!isMutable) {
        bitmapWrapper->bitmap().setImmutable();
    }
    jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
            reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density,
            isMutable, isPremultiplied, ninePatchChunk, ninePatchInsets);
            isPremultiplied, ninePatchChunk, ninePatchInsets);

    if (env->ExceptionCheck() != 0) {
        ALOGE("*** Uncaught exception returned from Java call!\n");
@@ -1571,6 +1574,20 @@ static void Bitmap_copyColorSpace(JNIEnv* env, jobject, jlong srcBitmapPtr, jlon
    dstBitmapHandle->bitmap().setColorSpace(srcBitmapHandle->bitmap().info().refColorSpace());
}

static jboolean Bitmap_isImmutable(jlong bitmapHandle) {
    LocalScopedBitmap bitmapHolder(bitmapHandle);
    if (!bitmapHolder.valid()) return JNI_FALSE;

    return bitmapHolder->bitmap().isImmutable() ? JNI_TRUE : JNI_FALSE;
}

static void Bitmap_setImmutable(JNIEnv* env, jobject, jlong bitmapHandle) {
    LocalScopedBitmap bitmapHolder(bitmapHandle);
    if (!bitmapHolder.valid()) return;

    return bitmapHolder->bitmap().setImmutable();
}

///////////////////////////////////////////////////////////////////////////////

static const JNINativeMethod gBitmapMethods[] = {
@@ -1626,13 +1643,18 @@ static const JNINativeMethod gBitmapMethods[] = {
    {   "nativeIsSRGBLinear",       "(J)Z", (void*)Bitmap_isSRGBLinear},
    {   "nativeCopyColorSpace",     "(JJ)V",
        (void*)Bitmap_copyColorSpace },
    {   "nativeSetImmutable",       "(J)V", (void*)Bitmap_setImmutable},

    // ------------ @CriticalNative ----------------
    {   "nativeIsImmutable",        "(J)Z", (void*)Bitmap_isImmutable}

};

int register_android_graphics_Bitmap(JNIEnv* env)
{
    gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
    gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
    gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
    gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
    gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
    gBitmap_getAllocationByteCountMethodID = GetMethodIDOrDie(env, gBitmap_class, "getAllocationByteCount", "()I");
    return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
+37 −19
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ import android.view.DisplayListCanvas;
import android.view.RenderNode;
import android.view.ThreadedRenderer;

import dalvik.annotation.optimization.CriticalNative;

import libcore.util.NativeAllocationRegistry;

import java.io.OutputStream;
@@ -59,8 +61,6 @@ public final class Bitmap implements Parcelable {
    // Convenience for JNI access
    private final long mNativePtr;

    private final boolean mIsMutable;

    /**
     * Represents whether the Bitmap's content is requested to be pre-multiplied.
     * Note that isPremultiplied() does not directly return this value, because
@@ -117,8 +117,7 @@ public final class Bitmap implements Parcelable {
     * int (pointer).
     */
    // called from JNI
    Bitmap(long nativeBitmap, int width, int height, int density,
            boolean isMutable, boolean requestPremultiplied,
    Bitmap(long nativeBitmap, int width, int height, int density, boolean requestPremultiplied,
            byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) {
        if (nativeBitmap == 0) {
            throw new RuntimeException("internal error: native bitmap is 0");
@@ -126,7 +125,6 @@ public final class Bitmap implements Parcelable {

        mWidth = width;
        mHeight = height;
        mIsMutable = isMutable;
        mRequestPremultiplied = requestPremultiplied;

        mNinePatchChunk = ninePatchChunk;
@@ -742,7 +740,7 @@ public final class Bitmap implements Parcelable {
    }

    /**
     * Returns an immutable bitmap from the source bitmap. The new bitmap may
     * Returns a bitmap from the source bitmap. The new bitmap may
     * be the same object as source, or a copy may have been made.  It is
     * initialized with the same density and color space as the original bitmap.
     */
@@ -751,7 +749,7 @@ public final class Bitmap implements Parcelable {
    }

    /**
     * Returns an immutable bitmap from the specified subset of the source
     * Returns a bitmap from the specified subset of the source
     * bitmap. The new bitmap may be the same object as source, or a copy may
     * have been made. It is initialized with the same density and color space
     * as the original bitmap.
@@ -771,7 +769,7 @@ public final class Bitmap implements Parcelable {
    }

    /**
     * Returns an immutable bitmap from subset of the source bitmap,
     * Returns a bitmap from subset of the source bitmap,
     * transformed by the optional matrix. The new bitmap may be the
     * same object as source, or a copy may have been made. It is
     * initialized with the same density and color space as the original
@@ -781,6 +779,12 @@ public final class Bitmap implements Parcelable {
     * same as the source bitmap itself, then the source bitmap is
     * returned and no new bitmap is created.
     *
     * The returned bitmap will always be mutable except in the following scenarios:
     * (1) In situations where the source bitmap is returned and the source bitmap is immutable
     *
     * (2) The source bitmap is a hardware bitmap. That is {@link #getConfig()} is equivalent to
     * {@link Config#HARDWARE}
     *
     * @param source   The bitmap we are subsetting
     * @param x        The x coordinate of the first pixel in source
     * @param y        The y coordinate of the first pixel in source
@@ -1218,11 +1222,9 @@ public final class Bitmap implements Parcelable {
     *              scaled to match if necessary.
     * @param height The height of the bitmap to create. The picture's height will be
     *              scaled to match if necessary.
     * @param config The {@link Config} of the created bitmap. If this is null then
     *               the bitmap will be {@link Config#HARDWARE}.
     * @param config The {@link Config} of the created bitmap.
     *
     * @return An immutable bitmap with a HARDWARE config whose contents are created
     * from the recorded drawing commands in the Picture source.
     * @return An immutable bitmap with a configuration specified by the config parameter
     */
    public static @NonNull Bitmap createBitmap(@NonNull Picture source, int width, int height,
            @NonNull Config config) {
@@ -1260,7 +1262,7 @@ public final class Bitmap implements Parcelable {
            }
            canvas.drawPicture(source);
            canvas.setBitmap(null);
            bitmap.makeImmutable();
            bitmap.setImmutable();
            return bitmap;
        }
    }
@@ -1351,13 +1353,22 @@ public final class Bitmap implements Parcelable {
     * Returns true if the bitmap is marked as mutable (i.e.&nbsp;can be drawn into)
     */
    public final boolean isMutable() {
        return mIsMutable;
        return !nativeIsImmutable(mNativePtr);
    }

    /** @hide */
    public final void makeImmutable() {
        // todo mIsMutable = false;
        // todo nMakeImmutable();
    /**
     * Marks the Bitmap as immutable. Further modifications to this Bitmap are disallowed.
     * After this method is called, this Bitmap cannot be made mutable again and subsequent calls
     * to {@link #reconfigure(int, int, Config)}, {@link #setPixel(int, int, int)},
     * {@link #setPixels(int[], int, int, int, int, int, int)} and {@link #eraseColor(int)} will
     * fail and throw an IllegalStateException.
     *
     * @hide
     */
    public void setImmutable() {
        if (isMutable()) {
            nativeSetImmutable(mNativePtr);
        }
    }

    /**
@@ -1923,7 +1934,7 @@ public final class Bitmap implements Parcelable {
    public void writeToParcel(Parcel p, int flags) {
        checkRecycled("Can't parcel a recycled bitmap");
        noteHardwareBitmapSlowCall();
        if (!nativeWriteToParcel(mNativePtr, mIsMutable, mDensity, p)) {
        if (!nativeWriteToParcel(mNativePtr, isMutable(), mDensity, p)) {
            throw new RuntimeException("native writeToParcel failed");
        }
    }
@@ -2096,4 +2107,11 @@ public final class Bitmap implements Parcelable {
    private static native boolean nativeIsSRGB(long nativePtr);
    private static native boolean nativeIsSRGBLinear(long nativePtr);
    private static native void nativeCopyColorSpace(long srcBitmap, long dstBitmap);

    private static native void nativeSetImmutable(long nativePtr);

    // ---------------- @CriticalNative -------------------

    @CriticalNative
    private static native boolean nativeIsImmutable(long nativePtr);
}