diff options
| -rwxr-xr-x | core/jni/android/graphics/Bitmap.cpp | 496 | ||||
| -rw-r--r-- | core/jni/android/graphics/Bitmap.h | 95 | ||||
| -rw-r--r-- | core/jni/android/graphics/BitmapFactory.cpp | 23 | ||||
| -rw-r--r-- | core/jni/android/graphics/BitmapRegionDecoder.cpp | 12 | ||||
| -rw-r--r-- | core/jni/android/graphics/Graphics.cpp | 115 | ||||
| -rw-r--r-- | core/jni/android/graphics/GraphicsJNI.h | 55 | ||||
| -rw-r--r-- | core/jni/android_graphics_Canvas.cpp | 3 | ||||
| -rw-r--r-- | core/jni/android_view_SurfaceControl.cpp | 8 |
8 files changed, 377 insertions, 430 deletions
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 6acb76d365b5..e79732100e53 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -31,152 +31,160 @@ #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(); } - ~WrappedPixelRef() { - // Tell SkRefCnt that everything is as it expects by forcing - // the refcnt to 1 - internal_dispose_restore_refcnt_to_1(); - SkSafeUnref(mColorTable); + bool valid() { + return !!mPixelRef; } - void 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); - } + 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); + } - // Need to validate the alpha type to filter against the color type - // to prevent things like a non-opaque RGB565 bitmap - SkAlphaType alphaType; - LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType( - newInfo.colorType(), newInfo.alphaType(), &alphaType), - "Failed to validate alpha type!"); - - // Dirty hack is dirty - // TODO: Figure something out here, Skia's current design makes this - // really hard to work with. Skia really, really wants immutable objects, - // but with the nested-ref-count hackery going on that's just not - // feasible without going insane trying to figure it out - SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info()); - *myInfo = newInfo; - changeAlphaType(alphaType); - - // 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 { + bool hasHardwareMipMap() { + if (mPixelRef) { + return mPixelRef->hasHardwareMipMap(); + } return mHasHardwareMipMap; } void setHasHardwareMipMap(bool hasMipMap) { - mHasHardwareMipMap = hasMipMap; + assertValid(); + mPixelRef->setHasHardwareMipMap(hasMipMap); } -protected: - virtual bool onNewLockPixels(LockRec* rec) override { - rec->fPixels = mStorage; - rec->fRowBytes = mRowBytes; - rec->fColorTable = mColorTable; - return true; + void setAlphaType(SkAlphaType alphaType) { + assertValid(); + mPixelRef->setAlphaType(alphaType); } - virtual void onUnlockPixels() override { - // nothing + const SkImageInfo& info() { + if (mPixelRef) { + return mPixelRef->info(); + } + return mInfo; } - virtual size_t getAllocatedSizeInBytes() const override { - return info().getSafeSize(mRowBytes); + size_t getAllocationByteCount() const { + if (mPixelRef) { + return mPixelRef->getAllocationByteCount(); + } + return mAllocationSize; } -private: - Bitmap& mBitmap; - void* mStorage; - size_t mRowBytes = 0; - SkColorTable* mColorTable = nullptr; - bool mHasHardwareMipMap = false; + size_t rowBytes() const { + if (mPixelRef) { + return mPixelRef->rowBytes(); + } + return mRowBytes; + } - virtual void internal_dispose() const override { - mBitmap.onStrongRefDestroyed(); + 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; }; -Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable) - : mPixelStorageType(PixelStorageType::Heap) { +void PixelRef::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) { + if (kIndex_8_SkColorType != newInfo.colorType()) { + ctable = nullptr; + } + mRowBytes = rowBytes; + if (mColorTable.get() != ctable) { + mColorTable.reset(ctable); + } + + // Need to validate the alpha type to filter against the color type + // to prevent things like a non-opaque RGB565 bitmap + SkAlphaType alphaType; + LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType( + newInfo.colorType(), newInfo.alphaType(), &alphaType), + "Failed to validate alpha type!"); + + // Dirty hack is dirty + // TODO: Figure something out here, Skia's current design makes this + // really hard to work with. Skia really, really wants immutable objects, + // but with the nested-ref-count hackery going on that's just not + // feasible without going insane trying to figure it out + SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info()); + *myInfo = newInfo; + changeAlphaType(alphaType); + + // 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(getStorage(), mRowBytes, mColorTable.get()); +} + +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, - const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable) - : mPixelStorageType(PixelStorageType::External) { +PixelRef::PixelRef(void* address, void* context, FreeFunc freeFunc, + const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable) + : 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, - const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable) - : mPixelStorageType(PixelStorageType::Ashmem) { +PixelRef::PixelRef(void* address, int fd, size_t mappedSize, + const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable) + : 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,20 +199,41 @@ 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.address; + case PixelStorageType::Heap: + return mPixelStorage.heap.address; + } +} + +bool PixelRef::onNewLockPixels(LockRec* rec) { + rec->fPixels = getStorage(); + rec->fRowBytes = mRowBytes; + rec->fColorTable = mColorTable.get(); + return true; +} + +size_t PixelRef::getAllocatedSizeInBytes() const { + return info().getSafeSize(mRowBytes); +} + +int PixelRef::getAshmemFd() const { switch (mPixelStorageType) { case PixelStorageType::Ashmem: return mPixelStorage.ashmem.fd; @@ -213,7 +242,7 @@ int Bitmap::getAshmemFd() const { } } -size_t Bitmap::getAllocationByteCount() const { +size_t PixelRef::getAllocationByteCount() const { switch (mPixelStorageType) { case PixelStorageType::Heap: return mPixelStorage.heap.size; @@ -222,105 +251,25 @@ size_t Bitmap::getAllocationByteCount() const { } } -const SkImageInfo& Bitmap::info() const { - return mPixelRef->info(); -} - -size_t Bitmap::rowBytes() const { - return mPixelRef->rowBytes(); -} - -SkPixelRef* Bitmap::peekAtPixelRef() const { - assertValid(); - return mPixelRef.get(); -} - -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++; - } - 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; - } + changeAlphaType(alphaType); } -bool Bitmap::shouldDisposeSelfLocked() { - return mPinnedRefCount == 0 && !mAttachedToJava; +void PixelRef::getSkBitmap(SkBitmap* outBitmap) { + outBitmap->setInfo(info(), rowBytes()); + outBitmap->setPixelRef(this); + outBitmap->setHasHardwareMipMap(mHasHardwareMipMap); } -void Bitmap::onStrongRefDestroyed() { - bool disposeSelf = false; - { - android::AutoMutex _lock(mLock); - if (mPinnedRefCount > 0) { - mPinnedRefCount--; - if (mPinnedRefCount == 0) { - disposeSelf = shouldDisposeSelfLocked(); - } - } - } - if (disposeSelf) { - delete this; - } -} - -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 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 class LocalScopedBitmap { @@ -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 diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h index 9ae1f3f3d07b..8e631eed040f 100644 --- a/core/jni/android/graphics/Bitmap.h +++ b/core/jni/android/graphics/Bitmap.h @@ -20,80 +20,91 @@ #include <SkBitmap.h> #include <SkColorTable.h> #include <SkImageInfo.h> -#include <utils/Mutex.h> -#include <memory> +#include <SkPixelRef.h> namespace android { enum class PixelStorageType { - Invalid, External, Heap, Ashmem, }; -class WrappedPixelRef; - typedef void (*FreeFunc)(void* addr, void* context); -/** - * Glue-thingy that deals with managing the interaction between the Java - * Bitmap object & SkBitmap along with trying to map a notion of strong/weak - * lifecycles onto SkPixelRef which only has strong counts to avoid requiring - * two GC passes to free the byte[] that backs a Bitmap. - * - * Since not all Bitmaps are byte[]-backed it also supports external allocations, - * which currently is used by screenshots to wrap a gralloc buffer. - */ -class Bitmap { +class PixelRef; + +namespace bitmap { + +enum BitmapCreateFlags { + kBitmapCreateFlag_None = 0x0, + kBitmapCreateFlag_Mutable = 0x1, + kBitmapCreateFlag_Premultiplied = 0x2, +}; + +jobject createBitmap(JNIEnv* env, PixelRef* bitmap, + int bitmapCreateFlags, jbyteArray ninePatchChunk = NULL, + jobject ninePatchInsets = NULL, int density = -1); + + +void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap); + +PixelRef* toPixelRef(JNIEnv* env, jobject bitmap); + +/** Reinitialize a bitmap. bitmap must already have its SkAlphaType set in + sync with isPremultiplied +*/ +void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info, + bool isPremultiplied); + +int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap); + +} // namespace bitmap + +class PixelRef : public SkPixelRef { public: - Bitmap(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes, + PixelRef(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable); - Bitmap(void* address, void* context, FreeFunc freeFunc, + PixelRef(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable); - Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, + PixelRef(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable); - const SkImageInfo& info() const; - int width() const { return info().width(); } int height() const { return info().height(); } - size_t rowBytes() const; - SkPixelRef* peekAtPixelRef() const; - SkPixelRef* refPixelRef(); - bool valid() const { return mPixelStorageType != PixelStorageType::Invalid; } + // Can't mark as override since SkPixelRef::rowBytes isn't virtual + // but that's OK since we just want Bitmap to be able to rely + // on calling rowBytes() on an unlocked pixelref, which it will be + // doing on a PixelRef type, not a SkPixelRef, so static + // dispatching will do what we want. + size_t rowBytes() const { return mRowBytes; } void reconfigure(const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable); void reconfigure(const SkImageInfo& info); void setAlphaType(SkAlphaType alphaType); void getSkBitmap(SkBitmap* outBitmap); - void detachFromJava(); - - void freePixels(); - bool hasHardwareMipMap(); - void setHasHardwareMipMap(bool hasMipMap); int getAshmemFd() const; size_t getAllocationByteCount() const; +protected: + virtual bool onNewLockPixels(LockRec* rec) override; + virtual void onUnlockPixels() override { }; + virtual size_t getAllocatedSizeInBytes() const override; private: - friend class WrappedPixelRef; - - ~Bitmap(); + friend class Bitmap; + virtual ~PixelRef(); void doFreePixels(); - void onStrongRefDestroyed(); - - void pinPixelsLocked(); - bool shouldDisposeSelfLocked(); - void assertValid() const; - SkPixelRef* refPixelRefLocked(); + void* getStorage() const; + void setHasHardwareMipMap(bool hasMipMap); + bool hasHardwareMipMap() const; - android::Mutex mLock; - int mPinnedRefCount = 0; - std::unique_ptr<WrappedPixelRef> mPixelRef; PixelStorageType mPixelStorageType; - bool mAttachedToJava = true; + + size_t mRowBytes = 0; + sk_sp<SkColorTable> mColorTable; + bool mHasHardwareMipMap = false; union { struct { diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 5a540ce10662..5bb02746bf3a 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -162,7 +162,7 @@ private: class RecyclingPixelAllocator : public SkBitmap::Allocator { public: - RecyclingPixelAllocator(android::Bitmap* bitmap, unsigned int size) + RecyclingPixelAllocator(android::PixelRef* bitmap, unsigned int size) : mBitmap(bitmap), mSize(size) { } @@ -190,7 +190,8 @@ public: } mBitmap->reconfigure(info, bitmap->rowBytes(), ctable); - bitmap->setPixelRef(mBitmap->refPixelRef())->unref(); + mBitmap->ref(); + bitmap->setPixelRef(mBitmap)->unref(); // since we're already allocated, we lockPixels right away // HeapAllocator behaves this way too @@ -199,7 +200,7 @@ public: } private: - android::Bitmap* const mBitmap; + android::PixelRef* const mBitmap; const unsigned int mSize; }; @@ -326,16 +327,16 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding scaledHeight = static_cast<int>(scaledHeight * scale + 0.5f); } - android::Bitmap* reuseBitmap = nullptr; + android::PixelRef* reuseBitmap = nullptr; unsigned int existingBufferSize = 0; if (javaBitmap != NULL) { - reuseBitmap = GraphicsJNI::getBitmap(env, javaBitmap); - if (reuseBitmap->peekAtPixelRef()->isImmutable()) { + reuseBitmap = bitmap::toPixelRef(env, javaBitmap); + if (reuseBitmap->isImmutable()) { ALOGW("Unable to reuse an immutable bitmap as an image decoder target."); javaBitmap = NULL; reuseBitmap = nullptr; } else { - existingBufferSize = GraphicsJNI::getBitmapAllocationByteCount(env, javaBitmap); + existingBufferSize = bitmap::getBitmapAllocationByteCount(env, javaBitmap); } } @@ -529,18 +530,18 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding bool isPremultiplied = !requireUnpremultiplied; if (javaBitmap != nullptr) { - GraphicsJNI::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied); + bitmap::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied); outputBitmap.notifyPixelsChanged(); // If a java bitmap was passed in for reuse, pass it back return javaBitmap; } int bitmapCreateFlags = 0x0; - if (isMutable) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Mutable; - if (isPremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied; + if (isMutable) bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Mutable; + if (isPremultiplied) bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Premultiplied; // now create the java bitmap - return GraphicsJNI::createBitmap(env, defaultAllocator.getStorageObjAndReset(), + return bitmap::createBitmap(env, defaultAllocator.getStorageObjAndReset(), bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1); } diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index 21850bde83d2..7d0915ba1bc2 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -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) { diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 8cee814fa162..8a55052376f7 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -157,12 +157,6 @@ static jclass gPointF_class; static jfieldID gPointF_xFieldID; static jfieldID gPointF_yFieldID; -static jclass gBitmap_class; -static jfieldID gBitmap_nativePtr; -static jmethodID gBitmap_constructorMethodID; -static jmethodID gBitmap_reinitMethodID; -static jmethodID gBitmap_getAllocationByteCountMethodID; - static jclass gBitmapConfig_class; static jfieldID gBitmapConfig_nativeInstanceID; @@ -342,24 +336,15 @@ SkColorType GraphicsJNI::legacyBitmapConfigToColorType(jint legacyConfig) { return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]); } -android::Bitmap* GraphicsJNI::getBitmap(JNIEnv* env, jobject bitmap) { - SkASSERT(env); - SkASSERT(bitmap); - SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); - jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); - android::Bitmap* b = reinterpret_cast<android::Bitmap*>(bitmapHandle); - SkASSERT(b); - return b; -} - void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap) { - getBitmap(env, bitmap)->getSkBitmap(outBitmap); + android::bitmap::toPixelRef(env, bitmap)->getSkBitmap(outBitmap); } SkPixelRef* GraphicsJNI::refSkPixelRef(JNIEnv* env, jobject bitmap) { - return getBitmap(env, bitmap)->refPixelRef(); + SkPixelRef* pixelRef = android::bitmap::toPixelRef(env, bitmap); + pixelRef->ref(); + return pixelRef; } - SkColorType GraphicsJNI::getNativeBitmapColorType(JNIEnv* env, jobject jconfig) { SkASSERT(env); if (NULL == jconfig) { @@ -394,50 +379,6 @@ SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region) /////////////////////////////////////////////////////////////////////////////////////////// -// 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); - } -} - -jobject GraphicsJNI::createBitmap(JNIEnv* env, android::Bitmap* bitmap, - 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(bitmap->info(), isPremultiplied); - - jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID, - reinterpret_cast<jlong>(bitmap), bitmap->width(), bitmap->height(), density, isMutable, - isPremultiplied, ninePatchChunk, ninePatchInsets); - hasException(env); // For the side effect of logging. - return obj; -} - -void GraphicsJNI::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 GraphicsJNI::getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap) -{ - return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID); -} - jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap) { SkASSERT(bitmap != NULL); @@ -482,7 +423,7 @@ static bool computeAllocationSize(const SkBitmap& bitmap, size_t* size) { return true; } -android::Bitmap* GraphicsJNI::allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { +android::PixelRef* GraphicsJNI::allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { const SkImageInfo& info = bitmap->info(); if (info.colorType() == kUnknown_SkColorType) { LOG_ALWAYS_FATAL("unknown bitmap configuration"); @@ -503,7 +444,7 @@ android::Bitmap* GraphicsJNI::allocateHeapPixelRef(SkBitmap* bitmap, SkColorTabl return nullptr; } - android::Bitmap* wrapper = new android::Bitmap(addr, size, info, rowBytes, ctable); + auto wrapper = new android::PixelRef(addr, size, info, rowBytes, ctable); wrapper->getSkBitmap(bitmap); // since we're already allocated, we lockPixels right away // HeapAllocator behaves this way too @@ -566,7 +507,7 @@ bool GraphicsJNI::allocatePixels(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ct return true; } -android::Bitmap* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, +android::PixelRef* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable) { int fd; @@ -603,7 +544,7 @@ android::Bitmap* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitm return nullptr; } - android::Bitmap* wrapper = new android::Bitmap(addr, fd, size, info, rowBytes, ctable); + auto wrapper = new android::PixelRef(addr, fd, size, info, rowBytes, ctable); wrapper->getSkBitmap(bitmap); // since we're already allocated, we lockPixels right away // HeapAllocator behaves this way too @@ -612,7 +553,7 @@ android::Bitmap* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitm return wrapper; } -android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, +android::PixelRef* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable, int fd, void* addr, size_t size, bool readOnly) { const SkImageInfo& info = bitmap->info(); if (info.colorType() == kUnknown_SkColorType) { @@ -634,7 +575,7 @@ android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, // attempting to compute our own. const size_t rowBytes = bitmap->rowBytes(); - android::Bitmap* wrapper = new android::Bitmap(addr, fd, size, info, rowBytes, ctable); + auto wrapper = new android::PixelRef(addr, fd, size, info, rowBytes, ctable); wrapper->getSkBitmap(bitmap); if (readOnly) { bitmap->pixelRef()->setImmutable(); @@ -647,24 +588,15 @@ android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, } /////////////////////////////////////////////////////////////////////////////// - -HeapAllocator::HeapAllocator() {} - -HeapAllocator::~HeapAllocator() { - if (mStorage) { - mStorage->detachFromJava(); - } -} - bool HeapAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { - mStorage = GraphicsJNI::allocateHeapPixelRef(bitmap, ctable); - return mStorage != nullptr; + mStorage.reset(GraphicsJNI::allocateHeapPixelRef(bitmap, ctable)); + return !!mStorage; } //////////////////////////////////////////////////////////////////////////////// RecyclingClippingPixelAllocator::RecyclingClippingPixelAllocator( - android::Bitmap* recycledBitmap, size_t recycledBytes) + android::PixelRef* recycledBitmap, size_t recycledBytes) : mRecycledBitmap(recycledBitmap) , mRecycledBytes(recycledBytes) , mSkiaBitmap(nullptr) @@ -707,7 +639,8 @@ bool RecyclingClippingPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTab // skbug.com/4538: We also need to make sure that the rowBytes on the pixel ref // match the rowBytes on the bitmap. bitmap->setInfo(bitmap->info(), rowBytes); - bitmap->setPixelRef(mRecycledBitmap->refPixelRef())->unref(); + mRecycledBitmap->ref(); + bitmap->setPixelRef(mRecycledBitmap)->unref(); // Make sure that the recycled bitmap has the correct alpha type. mRecycledBitmap->setAlphaType(bitmap->alphaType()); @@ -734,7 +667,8 @@ bool RecyclingClippingPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTab void RecyclingClippingPixelAllocator::copyIfNecessary() { if (mNeedsCopy) { - SkPixelRef* recycledPixels = mRecycledBitmap->refPixelRef(); + mRecycledBitmap->ref(); + SkPixelRef* recycledPixels = mRecycledBitmap; void* dst = recycledPixels->pixels(); const size_t dstRowBytes = mRecycledBitmap->rowBytes(); const size_t bytesToCopy = std::min(mRecycledBitmap->info().minRowBytes(), @@ -759,16 +693,10 @@ AshmemPixelAllocator::AshmemPixelAllocator(JNIEnv *env) { "env->GetJavaVM failed"); } -AshmemPixelAllocator::~AshmemPixelAllocator() { - if (mStorage) { - mStorage->detachFromJava(); - } -} - bool AshmemPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { JNIEnv* env = vm2env(mJavaVM); - mStorage = GraphicsJNI::allocateAshmemPixelRef(env, bitmap, ctable); - return mStorage != nullptr; + mStorage.reset(GraphicsJNI::allocateAshmemPixelRef(env, bitmap, ctable)); + return !!mStorage; } //////////////////////////////////////////////////////////////////////////////// @@ -813,11 +741,6 @@ int register_android_graphics_Graphics(JNIEnv* env) gPointF_xFieldID = getFieldIDCheck(env, gPointF_class, "x", "F"); gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F"); - 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"); gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder"); gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(J)V"); diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 738ad54b715d..ceda3cd28ad4 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -23,12 +23,6 @@ struct Typeface; class GraphicsJNI { public: - enum BitmapCreateFlags { - kBitmapCreateFlag_None = 0x0, - kBitmapCreateFlag_Mutable = 0x1, - kBitmapCreateFlag_Premultiplied = 0x2, - }; - // returns true if an exception is set (and dumps it out to the Log) static bool hasException(JNIEnv*); @@ -51,7 +45,6 @@ public: static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf); static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas); - static android::Bitmap* getBitmap(JNIEnv*, jobject bitmap); static void getSkBitmap(JNIEnv*, jobject bitmap, SkBitmap* outBitmap); static SkPixelRef* refSkPixelRef(JNIEnv*, jobject bitmap); static SkRegion* getNativeRegion(JNIEnv*, jobject region); @@ -73,32 +66,16 @@ public: */ static SkColorType getNativeBitmapColorType(JNIEnv*, jobject jconfig); - /* - * Create a java Bitmap object given the native bitmap - * bitmap's SkAlphaType must already be in sync with bitmapCreateFlags. - */ - static jobject createBitmap(JNIEnv* env, android::Bitmap* bitmap, - int bitmapCreateFlags, jbyteArray ninePatchChunk = NULL, - jobject ninePatchInsets = NULL, int density = -1); - - /** Reinitialize a bitmap. bitmap must already have its SkAlphaType set in - sync with isPremultiplied - */ - static void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info, - bool isPremultiplied); - - static int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap); - static jobject createRegion(JNIEnv* env, SkRegion* region); static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap); - static android::Bitmap* allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable); + static android::PixelRef* allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable); - static android::Bitmap* allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, + static android::PixelRef* allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable); - static android::Bitmap* mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, + static android::PixelRef* mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable, int fd, void* addr, size_t size, bool readOnly); /** @@ -120,23 +97,21 @@ public: class HeapAllocator : public SkBRDAllocator { public: - HeapAllocator(); - ~HeapAllocator(); + HeapAllocator() { }; + ~HeapAllocator() { }; virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) override; /** * Fetches the backing allocation object. Must be called! */ - android::Bitmap* getStorageObjAndReset() { - android::Bitmap* result = mStorage; - mStorage = NULL; - return result; + android::PixelRef* getStorageObjAndReset() { + return mStorage.release(); }; SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kYes_ZeroInitialized; } private: - android::Bitmap* mStorage = nullptr; + sk_sp<android::PixelRef> mStorage; }; /** @@ -169,7 +144,7 @@ private: class RecyclingClippingPixelAllocator : public SkBRDAllocator { public: - RecyclingClippingPixelAllocator(android::Bitmap* recycledBitmap, + RecyclingClippingPixelAllocator(android::PixelRef* recycledBitmap, size_t recycledBytes); ~RecyclingClippingPixelAllocator(); @@ -194,7 +169,7 @@ public: SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kNo_ZeroInitialized; } private: - android::Bitmap* mRecycledBitmap; + android::PixelRef* mRecycledBitmap; const size_t mRecycledBytes; SkBitmap* mSkiaBitmap; bool mNeedsCopy; @@ -203,17 +178,15 @@ private: class AshmemPixelAllocator : public SkBitmap::Allocator { public: explicit AshmemPixelAllocator(JNIEnv* env); - ~AshmemPixelAllocator(); + ~AshmemPixelAllocator() { }; virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable); - android::Bitmap* getStorageObjAndReset() { - android::Bitmap* result = mStorage; - mStorage = NULL; - return result; + android::PixelRef* getStorageObjAndReset() { + return mStorage.release(); }; private: JavaVM* mJavaVM; - android::Bitmap* mStorage = nullptr; + sk_sp<android::PixelRef> mStorage; }; diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index d5a7a9025269..d4121ade5445 100644 --- a/core/jni/android_graphics_Canvas.cpp +++ b/core/jni/android_graphics_Canvas.cpp @@ -341,9 +341,8 @@ static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmap jlong paintHandle, jint dstDensity, jint srcDensity) { Canvas* canvas = get_canvas(canvasHandle); - Bitmap* bitmap = reinterpret_cast<Bitmap*>(bitmapHandle); SkBitmap skiaBitmap; - bitmap->getSkBitmap(&skiaBitmap); + bitmap::toSkBitmap(bitmapHandle, &skiaBitmap); const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle); const Paint* paint = reinterpret_cast<Paint*>(paintHandle); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 73b3f52f078b..5d53b3f8bdce 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -184,14 +184,14 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, return NULL; } - Bitmap* bitmap = new Bitmap( + auto pixelRef = new PixelRef( (void*) screenshot->getPixels(), (void*) screenshot.get(), DeleteScreenshot, screenshotInfo, rowBytes, nullptr); screenshot.release(); - bitmap->peekAtPixelRef()->setImmutable(); + pixelRef->setImmutable(); - return GraphicsJNI::createBitmap(env, bitmap, - GraphicsJNI::kBitmapCreateFlag_Premultiplied, NULL); + return bitmap::createBitmap(env, pixelRef, + bitmap::kBitmapCreateFlag_Premultiplied, NULL); } static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj, |