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

Commit 1728bebe authored by Chris Craik's avatar Chris Craik Committed by Android (Google) Code Review
Browse files

Merge "Support larger bitmaps in BitmapFactory.Options.inBitmap"

parents be165675 9f58361e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -8633,6 +8633,7 @@ package android.graphics {
    method public void eraseColor(int);
    method public android.graphics.Bitmap extractAlpha();
    method public android.graphics.Bitmap extractAlpha(android.graphics.Paint, int[]);
    method public final int getAllocationByteCount();
    method public final int getByteCount();
    method public final android.graphics.Bitmap.Config getConfig();
    method public int getDensity();
+23 −5
Original line number Diff line number Diff line
@@ -211,19 +211,17 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,

    SkBitmap* bitmap;
    bool useExistingBitmap = false;
    unsigned int existingBufferSize = 0;
    if (javaBitmap == NULL) {
        bitmap = new SkBitmap;
    } else {
        if (sampleSize != 1) {
            return nullObjectReturn("SkImageDecoder: Cannot reuse bitmap with sampleSize != 1");
        }

        bitmap = (SkBitmap*) env->GetIntField(javaBitmap, gBitmap_nativeBitmapFieldID);
        // only reuse the provided bitmap if it is immutable
        // only reuse the provided bitmap if it is mutable
        if (!bitmap->isImmutable()) {
            useExistingBitmap = true;
            // config of supplied bitmap overrules config set in options
            prefConfig = bitmap->getConfig();
            existingBufferSize = GraphicsJNI::getBitmapAllocationByteCount(env, javaBitmap);
        } else {
            ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
            bitmap = new SkBitmap;
@@ -252,6 +250,26 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
        decodeMode = SkImageDecoder::kDecodeBounds_Mode;
    }

    if (javaBitmap != NULL) {
        // If we're reusing the pixelref from an existing bitmap, decode the bounds and
        // reinitialize the native object for the new content, keeping the pixelRef
        SkPixelRef* pixelRef = bitmap->pixelRef();
        SkSafeRef(pixelRef);

        SkBitmap boundsBitmap;
        decoder->decode(stream, &boundsBitmap, prefConfig, SkImageDecoder::kDecodeBounds_Mode);
        stream->rewind();

        if (boundsBitmap.getSize() > existingBufferSize) {
            return nullObjectReturn("bitmap marked for reuse too small to contain decoded data");
        }

        bitmap->setConfig(boundsBitmap.config(), boundsBitmap.width(), boundsBitmap.height(), 0);
        bitmap->setPixelRef(pixelRef);
        SkSafeUnref(pixelRef);
        GraphicsJNI::reinitBitmap(env, javaBitmap);
    }

    SkBitmap* decoded;
    if (willScale) {
        decoded = new SkBitmap;
+13 −0
Original line number Diff line number Diff line
@@ -152,6 +152,8 @@ static jfieldID gPointF_yFieldID;
static jclass   gBitmap_class;
static jfieldID gBitmap_nativeInstanceID;
static jmethodID gBitmap_constructorMethodID;
static jmethodID gBitmap_reinitMethodID;
static jmethodID gBitmap_getAllocationByteCountMethodID;

static jclass   gBitmapConfig_class;
static jfieldID gBitmapConfig_nativeInstanceID;
@@ -363,6 +365,15 @@ jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
    return createBitmap(env, bitmap, NULL, isMutable, ninepatch, NULL, density);
}

void GraphicsJNI::reinitBitmap(JNIEnv* env, jobject javaBitmap)
{
    env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID);
}

int GraphicsJNI::getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
{
    return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
}

jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
{
@@ -584,6 +595,8 @@ int register_android_graphics_Graphics(JNIEnv* env)
    gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I");
    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
                                            "(I[BZ[B[II)V");
    gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "()V");
    gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
    gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
    gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(I)V");

+4 −0
Original line number Diff line number Diff line
@@ -59,6 +59,10 @@ public:
    static jobject createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
                                jbyteArray ninepatch, int density = -1);

    static void reinitBitmap(JNIEnv* env, jobject javaBitmap);

    static int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap);

    static jobject createRegion(JNIEnv* env, SkRegion* region);

    static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap);
+38 −14
Original line number Diff line number Diff line
@@ -85,26 +85,20 @@ public final class Bitmap implements Parcelable {
    }

    /**
     * @noinspection UnusedDeclaration
     */
    /*  Private constructor that must received an already allocated native
        bitmap int (pointer).

        This can be called from JNI code.
     * Private constructor that must received an already allocated native
     * bitmap int (pointer).
     */
    @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
    Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk,
            int density) {
        this(nativeBitmap, buffer, isMutable, ninePatchChunk, null, density);
    }

    /**
     * @noinspection UnusedDeclaration
     */
    /*  Private constructor that must received an already allocated native
        bitmap int (pointer).

        This can be called from JNI code.
     * Private constructor that must received an already allocated native bitmap
     * int (pointer).
     */
    @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
    Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk,
            int[] layoutBounds, int density) {
        if (nativeBitmap == 0) {
@@ -124,6 +118,14 @@ public final class Bitmap implements Parcelable {
        }
    }

    /**
     * Native bitmap has been reconfigured, so discard cached width/height
     */
    @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
    void reinit() {
        mWidth = mHeight = -1;
    }

    /**
     * <p>Returns the density for this bitmap.</p>
     *
@@ -454,7 +456,7 @@ public final class Bitmap implements Parcelable {
    /**
     * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
     * specified width and height are the same as the current width and height of 
     * the source btimap, the source bitmap is returned and now new bitmap is
     * the source bitmap, the source bitmap is returned and no new bitmap is
     * created.
     *
     * @param src       The source bitmap.
@@ -989,6 +991,10 @@ public final class Bitmap implements Parcelable {
     * getPixels() or setPixels(), then the pixels are uniformly treated as
     * 32bit values, packed according to the Color class.
     *
     * <p>As of {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, this method
     * should not be used to calculate the memory usage of the bitmap. Instead,
     * see {@link #getAllocationByteCount()}.
     *
     * @return number of bytes between rows of the native bitmap pixels.
     */
    public final int getRowBytes() {
@@ -996,13 +1002,31 @@ public final class Bitmap implements Parcelable {
    }

    /**
     * Returns the number of bytes used to store this bitmap's pixels.
     * Returns the minimum number of bytes that can be used to store this bitmap's pixels.
     *
     * <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()}.
     */
    public final int getByteCount() {
        // int result permits bitmaps up to 46,340 x 46,340
        return getRowBytes() * getHeight();
    }

    /**
     * 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()}.
     *
     * <p>This value will not change over the lifetime of a Bitmap.
     */
    public final int getAllocationByteCount() {
        return mBuffer.length;
    }

    /**
     * If the bitmap's internal config is in one of the public formats, return
     * that config, otherwise return null.
Loading