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

Commit ac347fb4 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Remove all hacks around ref counting in Bitmap Test: refactoring cl. bug:27762775"

parents 46ce8a96 c69853c8
Loading
Loading
Loading
Loading
+268 −228
Original line number Diff line number Diff line
@@ -31,34 +31,106 @@
#define DEBUG_PARCEL 0
#define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10))

static jclass   gBitmap_class;
static jfieldID gBitmap_nativePtr;
static jmethodID gBitmap_constructorMethodID;
static jmethodID gBitmap_reinitMethodID;
static jmethodID gBitmap_getAllocationByteCountMethodID;

namespace android {

class WrappedPixelRef : public SkPixelRef {
class Bitmap {
public:
    WrappedPixelRef(Bitmap* wrapper, void* storage,
            const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
            : SkPixelRef(info)
            , mBitmap(*wrapper)
            , mStorage(storage) {
        reconfigure(info, rowBytes, ctable);
    Bitmap(PixelRef* pixelRef)
        : mPixelRef(pixelRef) { }

    void freePixels() {
        mInfo = mPixelRef->info();
        mHasHardwareMipMap = mPixelRef->hasHardwareMipMap();
        mAllocationSize = mPixelRef->getAllocationByteCount();
        mRowBytes = mPixelRef->rowBytes();
        mGenerationId = mPixelRef->getGenerationID();
        mPixelRef.reset();
    }

    bool valid() {
        return !!mPixelRef;
    }

    PixelRef* pixelRef() { return mPixelRef.get(); }

    void assertValid() {
        LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
    }

    void getSkBitmap(SkBitmap* outBitmap) {
        assertValid();
        mPixelRef->getSkBitmap(outBitmap);
    }

    bool hasHardwareMipMap() {
        if (mPixelRef) {
            return mPixelRef->hasHardwareMipMap();
        }
        return mHasHardwareMipMap;
    }

    void setHasHardwareMipMap(bool hasMipMap) {
        assertValid();
        mPixelRef->setHasHardwareMipMap(hasMipMap);
    }

    void setAlphaType(SkAlphaType alphaType) {
        assertValid();
        mPixelRef->setAlphaType(alphaType);
    }

    ~WrappedPixelRef() {
        // Tell SkRefCnt that everything is as it expects by forcing
        // the refcnt to 1
        internal_dispose_restore_refcnt_to_1();
        SkSafeUnref(mColorTable);
    const SkImageInfo& info() {
        if (mPixelRef) {
            return mPixelRef->info();
        }
        return mInfo;
    }

    size_t getAllocationByteCount() const {
        if (mPixelRef) {
            return mPixelRef->getAllocationByteCount();
        }
        return mAllocationSize;
    }

    void reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
    size_t rowBytes() const {
        if (mPixelRef) {
            return mPixelRef->rowBytes();
        }
        return mRowBytes;
    }

    uint32_t getGenerationID() const {
        if (mPixelRef) {
            return mPixelRef->getGenerationID();
        }
        return mGenerationId;
    }

    ~Bitmap() { }

private:
    sk_sp<PixelRef> mPixelRef;
    SkImageInfo mInfo;
    bool mHasHardwareMipMap;
    size_t mAllocationSize;
    size_t mRowBytes;
    uint32_t mGenerationId;
};

void PixelRef::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
    if (kIndex_8_SkColorType != newInfo.colorType()) {
        ctable = nullptr;
    }
    mRowBytes = rowBytes;
        if (mColorTable != ctable) {
            SkSafeUnref(mColorTable);
            mColorTable = ctable;
            SkSafeRef(mColorTable);
    if (mColorTable.get() != ctable) {
        mColorTable.reset(ctable);
    }

    // Need to validate the alpha type to filter against the color type
@@ -80,103 +152,39 @@ public:
    // Docs say to only call this in the ctor, but we're going to call
    // it anyway even if this isn't always the ctor.
    // TODO: Fix this too as part of the above TODO
        setPreLocked(mStorage, mRowBytes, mColorTable);
    }

    // Can't mark as override since SkPixelRef::rowBytes isn't virtual
    // but that's OK since we just want BitmapWrapper to be able to rely
    // on calling rowBytes() on an unlocked pixelref, which it will be
    // doing on a WrappedPixelRef type, not a SkPixelRef, so static
    // dispatching will do what we want.
    size_t rowBytes() const { return mRowBytes; }
    SkColorTable* colorTable() const { return mColorTable; }

    bool hasHardwareMipMap() const {
        return mHasHardwareMipMap;
    setPreLocked(getStorage(), mRowBytes, mColorTable.get());
}

    void setHasHardwareMipMap(bool hasMipMap) {
        mHasHardwareMipMap = hasMipMap;
    }

protected:
    virtual bool onNewLockPixels(LockRec* rec) override {
        rec->fPixels = mStorage;
        rec->fRowBytes = mRowBytes;
        rec->fColorTable = mColorTable;
        return true;
    }

    virtual void onUnlockPixels() override {
        // nothing
    }

    virtual size_t getAllocatedSizeInBytes() const override {
        return info().getSafeSize(mRowBytes);
    }

private:
    Bitmap& mBitmap;
    void* mStorage;
    size_t mRowBytes = 0;
    SkColorTable* mColorTable = nullptr;
    bool mHasHardwareMipMap = false;

    virtual void internal_dispose() const override {
        mBitmap.onStrongRefDestroyed();
    }
};

Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
        : mPixelStorageType(PixelStorageType::Heap) {
PixelRef::PixelRef(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
            : SkPixelRef(info)
            , mPixelStorageType(PixelStorageType::Heap) {
    mPixelStorage.heap.address = address;
    mPixelStorage.heap.size = size;
    mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
    // Note: this will trigger a call to onStrongRefDestroyed(), but
    // we want the pixel ref to have a ref count of 0 at this point
    mPixelRef->unref();
    reconfigure(info, rowBytes, ctable);
}

Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc,
PixelRef::PixelRef(void* address, void* context, FreeFunc freeFunc,
                const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
        : mPixelStorageType(PixelStorageType::External) {
            : SkPixelRef(info)
            , mPixelStorageType(PixelStorageType::External) {
    mPixelStorage.external.address = address;
    mPixelStorage.external.context = context;
    mPixelStorage.external.freeFunc = freeFunc;
    mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
    // Note: this will trigger a call to onStrongRefDestroyed(), but
    // we want the pixel ref to have a ref count of 0 at this point
    mPixelRef->unref();
    reconfigure(info, rowBytes, ctable);
}

Bitmap::Bitmap(void* address, int fd, size_t mappedSize,
PixelRef::PixelRef(void* address, int fd, size_t mappedSize,
                const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
        : mPixelStorageType(PixelStorageType::Ashmem) {
            : SkPixelRef(info)
            , mPixelStorageType(PixelStorageType::Ashmem) {
    mPixelStorage.ashmem.address = address;
    mPixelStorage.ashmem.fd = fd;
    mPixelStorage.ashmem.size = mappedSize;
    mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
    // Note: this will trigger a call to onStrongRefDestroyed(), but
    // we want the pixel ref to have a ref count of 0 at this point
    mPixelRef->unref();
}
Bitmap::~Bitmap() {
    doFreePixels();
}

void Bitmap::freePixels() {
    AutoMutex _lock(mLock);
    if (mPinnedRefCount == 0) {
        doFreePixels();
        mPixelStorageType = PixelStorageType::Invalid;
    }
    reconfigure(info, rowBytes, ctable);
}

void Bitmap::doFreePixels() {
PixelRef::~PixelRef() {
    switch (mPixelStorageType) {
    case PixelStorageType::Invalid:
        // already free'd, nothing to do
        break;
    case PixelStorageType::External:
        mPixelStorage.external.freeFunc(mPixelStorage.external.address,
                mPixelStorage.external.context);
@@ -191,135 +199,76 @@ void Bitmap::doFreePixels() {
    }

    if (android::uirenderer::Caches::hasInstance()) {
        android::uirenderer::Caches::getInstance().textureCache.releaseTexture(
                mPixelRef->getStableID());
        android::uirenderer::Caches::getInstance().textureCache.releaseTexture(getStableID());
    }
}

bool Bitmap::hasHardwareMipMap() {
    return mPixelRef->hasHardwareMipMap();
bool PixelRef::hasHardwareMipMap() const {
    return mHasHardwareMipMap;
}

void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
    mPixelRef->setHasHardwareMipMap(hasMipMap);
void PixelRef::setHasHardwareMipMap(bool hasMipMap) {
    mHasHardwareMipMap = hasMipMap;
}

int Bitmap::getAshmemFd() const {
void* PixelRef::getStorage() const {
    switch (mPixelStorageType) {
    case PixelStorageType::External:
        return mPixelStorage.external.address;
    case PixelStorageType::Ashmem:
        return mPixelStorage.ashmem.fd;
    default:
        return -1;
    }
}

size_t Bitmap::getAllocationByteCount() const {
    switch (mPixelStorageType) {
        return mPixelStorage.ashmem.address;
    case PixelStorageType::Heap:
        return mPixelStorage.heap.size;
    default:
        return rowBytes() * height();
        return mPixelStorage.heap.address;
    }
}

const SkImageInfo& Bitmap::info() const {
    return mPixelRef->info();
bool PixelRef::onNewLockPixels(LockRec* rec) {
    rec->fPixels = getStorage();
    rec->fRowBytes = mRowBytes;
    rec->fColorTable = mColorTable.get();
    return true;
}

size_t Bitmap::rowBytes() const {
    return mPixelRef->rowBytes();
size_t PixelRef::getAllocatedSizeInBytes() const {
    return info().getSafeSize(mRowBytes);
}

SkPixelRef* Bitmap::peekAtPixelRef() const {
    assertValid();
    return mPixelRef.get();
int PixelRef::getAshmemFd() const {
    switch (mPixelStorageType) {
    case PixelStorageType::Ashmem:
        return mPixelStorage.ashmem.fd;
    default:
        return -1;
    }

SkPixelRef* Bitmap::refPixelRef() {
    assertValid();
    android::AutoMutex _lock(mLock);
    return refPixelRefLocked();
}

SkPixelRef* Bitmap::refPixelRefLocked() {
    mPixelRef->ref();
    if (mPixelRef->unique()) {
        // We just restored this from 0, pin the pixels and inc the strong count
        // Note that there *might be* an incoming onStrongRefDestroyed from whatever
        // last unref'd
        mPinnedRefCount++;
size_t PixelRef::getAllocationByteCount() const {
    switch (mPixelStorageType) {
    case PixelStorageType::Heap:
        return mPixelStorage.heap.size;
    default:
        return rowBytes() * height();
    }
    return mPixelRef.get();
}

void Bitmap::reconfigure(const SkImageInfo& info, size_t rowBytes,
        SkColorTable* ctable) {
    mPixelRef->reconfigure(info, rowBytes, ctable);
}

void Bitmap::reconfigure(const SkImageInfo& info) {
void PixelRef::reconfigure(const SkImageInfo& info) {
    reconfigure(info, info.minRowBytes(), nullptr);
}

void Bitmap::setAlphaType(SkAlphaType alphaType) {
void PixelRef::setAlphaType(SkAlphaType alphaType) {
    if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
        return;
    }

    mPixelRef->changeAlphaType(alphaType);
}

void Bitmap::detachFromJava() {
    bool disposeSelf;
    {
        android::AutoMutex _lock(mLock);
        mAttachedToJava = false;
        disposeSelf = shouldDisposeSelfLocked();
    }
    if (disposeSelf) {
        delete this;
    }
}

bool Bitmap::shouldDisposeSelfLocked() {
    return mPinnedRefCount == 0 && !mAttachedToJava;
}


void Bitmap::onStrongRefDestroyed() {
    bool disposeSelf = false;
    {
        android::AutoMutex _lock(mLock);
        if (mPinnedRefCount > 0) {
            mPinnedRefCount--;
            if (mPinnedRefCount == 0) {
                disposeSelf = shouldDisposeSelfLocked();
            }
        }
    }
    if (disposeSelf) {
        delete this;
    }
    changeAlphaType(alphaType);
}

void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
    assertValid();
    android::AutoMutex _lock(mLock);
    // Safe because mPixelRef is a WrappedPixelRef type, otherwise rowBytes()
    // would require locking the pixels first.
    outBitmap->setInfo(mPixelRef->info(), mPixelRef->rowBytes());
    outBitmap->setPixelRef(refPixelRefLocked())->unref();
    outBitmap->setHasHardwareMipMap(hasHardwareMipMap());
void PixelRef::getSkBitmap(SkBitmap* outBitmap) {
    outBitmap->setInfo(info(), rowBytes());
    outBitmap->setPixelRef(this);
    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
}

void Bitmap::assertValid() const {
    LOG_ALWAYS_FATAL_IF(mPixelStorageType == PixelStorageType::Invalid,
            "Error, cannot access an invalid/free'd bitmap here!");
}

} // namespace android

using namespace android;

// Convenience class that does not take a global ref on the pixels, relying
// on the caller already having a local JNI ref
@@ -333,7 +282,7 @@ public:
    }

    void* pixels() {
        return mBitmap->peekAtPixelRef()->pixels();
        return mBitmap->pixelRef()->pixels();
    }

    bool valid() {
@@ -344,6 +293,78 @@ private:
    Bitmap* mBitmap;
};

namespace bitmap {

// Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
    // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
    // irrelevant. This just tests to ensure that the SkAlphaType is not
    // opposite of isPremultiplied.
    if (isPremultiplied) {
        SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
    } else {
        SkASSERT(info.alphaType() != kPremul_SkAlphaType);
    }
}

void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
        bool isPremultiplied)
{
    // The caller needs to have already set the alpha type properly, so the
    // native SkBitmap stays in sync with the Java Bitmap.
    assert_premultiplied(info, isPremultiplied);

    env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
            info.width(), info.height(), isPremultiplied);
}

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

jobject createBitmap(JNIEnv* env, PixelRef* pixelRef,
        int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
        int density) {
    bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
    bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
    // The caller needs to have already set the alpha type properly, so the
    // native SkBitmap stays in sync with the Java Bitmap.
    assert_premultiplied(pixelRef->info(), isPremultiplied);
    Bitmap* bitmap = new Bitmap(pixelRef);
    jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
            reinterpret_cast<jlong>(bitmap), pixelRef->width(), pixelRef->height(), density, isMutable,
            isPremultiplied, ninePatchChunk, ninePatchInsets);

    if (env->ExceptionCheck() != 0) {
        ALOGE("*** Uncaught exception returned from Java call!\n");
        env->ExceptionDescribe();
    }
    return obj;
}

void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) {
    LocalScopedBitmap bitmap(bitmapHandle);
    bitmap->getSkBitmap(outBitmap);
}

PixelRef* toPixelRef(JNIEnv* env, jobject bitmap) {
    SkASSERT(env);
    SkASSERT(bitmap);
    SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
    jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
    LocalScopedBitmap localBitmap(bitmapHandle);
    localBitmap->assertValid();
    return localBitmap->pixelRef();
}

} // namespace bitmap

} // namespace android

using namespace android;
using namespace android::bitmap;

///////////////////////////////////////////////////////////////////////////////
// Conversions to/from SkColor, for get/setPixels, and the create method, which
// is basically like setPixels
@@ -649,8 +670,8 @@ static ToColorProc ChooseToColorProc(const SkBitmap& src) {
///////////////////////////////////////////////////////////////////////////////

static int getPremulBitmapCreateFlags(bool isMutable) {
    int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;
    if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
    int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
    if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
    return flags;
}

@@ -674,7 +695,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
    SkBitmap bitmap;
    bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType));

    Bitmap* nativeBitmap = GraphicsJNI::allocateHeapPixelRef(&bitmap, NULL);
    PixelRef* nativeBitmap = GraphicsJNI::allocateHeapPixelRef(&bitmap, NULL);
    if (!nativeBitmap) {
        return NULL;
    }
@@ -684,7 +705,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
                0, 0, width, height, bitmap);
    }

    return GraphicsJNI::createBitmap(env, nativeBitmap,
    return createBitmap(env, nativeBitmap,
            getPremulBitmapCreateFlags(isMutable));
}

@@ -699,29 +720,28 @@ static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
    if (!src.copyTo(&result, dstCT, &allocator)) {
        return NULL;
    }
    Bitmap* bitmap = allocator.getStorageObjAndReset();
    return GraphicsJNI::createBitmap(env, bitmap,
            getPremulBitmapCreateFlags(isMutable));
    auto pixelRef = allocator.getStorageObjAndReset();
    return createBitmap(env, pixelRef, getPremulBitmapCreateFlags(isMutable));
}

static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
static PixelRef* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
    SkBitmap result;

    AshmemPixelAllocator allocator(env);
    if (!src.copyTo(&result, dstCT, &allocator)) {
        return NULL;
    }
    Bitmap* bitmap = allocator.getStorageObjAndReset();
    bitmap->peekAtPixelRef()->setImmutable();
    return bitmap;
    auto pixelRef = allocator.getStorageObjAndReset();
    pixelRef->setImmutable();
    return pixelRef;
}

static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
    SkBitmap src;
    reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
    SkColorType dstCT = src.colorType();
    Bitmap* bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
    jobject ret = GraphicsJNI::createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
    auto pixelRef = Bitmap_copyAshmemImpl(env, src, dstCT);
    jobject ret = createBitmap(env, pixelRef, getPremulBitmapCreateFlags(false));
    return ret;
}

@@ -729,13 +749,13 @@ static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, ji
    SkBitmap src;
    reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
    SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
    Bitmap* bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
    jobject ret = GraphicsJNI::createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
    auto pixelRef = Bitmap_copyAshmemImpl(env, src, dstCT);
    jobject ret = createBitmap(env, pixelRef, getPremulBitmapCreateFlags(false));
    return ret;
}

static void Bitmap_destruct(Bitmap* bitmap) {
    bitmap->detachFromJava();
    delete bitmap;
}

static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
@@ -751,6 +771,7 @@ static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
        jint width, jint height, jint configHandle, jboolean requestPremul) {
    LocalScopedBitmap bitmap(bitmapHandle);
    bitmap->assertValid();
    SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);

    // ARGB_4444 is a deprecated format, convert automatically to 8888
@@ -773,7 +794,7 @@ static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
        // Otherwise respect the premultiplied request.
        alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
    }
    bitmap->reconfigure(SkImageInfo::Make(width, height, colorType, alphaType));
    bitmap->pixelRef()->reconfigure(SkImageInfo::Make(width, height, colorType, alphaType));
}

// These must match the int values in Bitmap.java
@@ -843,7 +864,7 @@ static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {

static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
    LocalScopedBitmap bitmap(bitmapHandle);
    return static_cast<jint>(bitmap->peekAtPixelRef()->getGenerationID());
    return static_cast<jint>(bitmap->getGenerationID());
}

static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
@@ -955,7 +976,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
    }

    // Map the bitmap in place from the ashmem region if possible otherwise copy.
    Bitmap* nativeBitmap;
    PixelRef* nativeBitmap;
    if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
#if DEBUG_PARCEL
        ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
@@ -1018,7 +1039,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
        blob.release();
    }

    return GraphicsJNI::createBitmap(env, nativeBitmap,
    return createBitmap(env, nativeBitmap,
            getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
}

@@ -1034,7 +1055,7 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
    android::Parcel* p = android::parcelForJavaObject(env, parcel);
    SkBitmap bitmap;

    android::Bitmap* androidBitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
    auto androidBitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
    androidBitmap->getSkBitmap(&bitmap);

    p->writeInt32(isMutable);
@@ -1061,7 +1082,7 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,

    // Transfer the underlying ashmem region if we have one and it's immutable.
    android::status_t status;
    int fd = androidBitmap->getAshmemFd();
    int fd = androidBitmap->pixelRef()->getAshmemFd();
    if (fd >= 0 && !isMutable && p->allowFds()) {
#if DEBUG_PARCEL
        ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
@@ -1131,7 +1152,7 @@ static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
        env->ReleaseIntArrayElements(offsetXY, array, 0);
    }

    return GraphicsJNI::createBitmap(env, allocator.getStorageObjAndReset(),
    return createBitmap(env, allocator.getStorageObjAndReset(),
            getPremulBitmapCreateFlags(true));
}

@@ -1307,7 +1328,7 @@ static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,

static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) {
    LocalScopedBitmap bitmap(bitmapHandle);
    SkPixelRef* pixelRef = bitmap.valid() ? bitmap->peekAtPixelRef() : nullptr;
    SkPixelRef* pixelRef = bitmap->pixelRef();
    SkSafeRef(pixelRef);
    return reinterpret_cast<jlong>(pixelRef);
}
@@ -1326,6 +1347,20 @@ static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr)
}

///////////////////////////////////////////////////////////////////////////////
static jclass make_globalref(JNIEnv* env, const char classname[])
{
    jclass c = env->FindClass(classname);
    SkASSERT(c);
    return (jclass) env->NewGlobalRef(c);
}

static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
                                const char fieldname[], const char type[])
{
    jfieldID id = env->GetFieldID(clazz, fieldname, type);
    SkASSERT(id);
    return id;
}

static const JNINativeMethod gBitmapMethods[] = {
    {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
@@ -1374,6 +1409,11 @@ static const JNINativeMethod gBitmapMethods[] = {

int register_android_graphics_Bitmap(JNIEnv* env)
{
    gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
    gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
    gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
    gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
    return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
                                         NELEM(gBitmapMethods));
}
 No newline at end of file
+53 −42

File changed.

Preview size limit exceeded, changes collapsed.

+12 −11

File changed.

Preview size limit exceeded, changes collapsed.

+6 −6
Original line number Diff line number Diff line
@@ -148,14 +148,14 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in
    }

    // Recycle a bitmap if possible.
    android::Bitmap* recycledBitmap = nullptr;
    android::PixelRef* recycledBitmap = nullptr;
    size_t recycledBytes = 0;
    if (javaBitmap) {
        recycledBitmap = GraphicsJNI::getBitmap(env, javaBitmap);
        if (recycledBitmap->peekAtPixelRef()->isImmutable()) {
        recycledBitmap = bitmap::toPixelRef(env, javaBitmap);
        if (recycledBitmap->isImmutable()) {
            ALOGW("Warning: Reusing an immutable bitmap as an image decoder target.");
        }
        recycledBytes = GraphicsJNI::getBitmapAllocationByteCount(env, javaBitmap);
        recycledBytes = bitmap::getBitmapAllocationByteCount(env, javaBitmap);
    }

    // Set up the pixel allocator
@@ -198,9 +198,9 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in

    int bitmapCreateFlags = 0;
    if (!requireUnpremul) {
        bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
        bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
    }
    return GraphicsJNI::createBitmap(env, heapAlloc.getStorageObjAndReset(), bitmapCreateFlags);
    return android::bitmap::createBitmap(env, heapAlloc.getStorageObjAndReset(), bitmapCreateFlags);
}

static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) {
+19 −96

File changed.

Preview size limit exceeded, changes collapsed.

Loading