Remove all hacks around ref counting in Bitmap
Test: refactoring cl.
bug:27762775
Change-Id: If7ebb8d5ee3a3085c1ef9ffc277cf6feaeab89e1
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 6acb76d..e797321 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;
+ 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();
}
- mRowBytes = rowBytes;
- if (mColorTable != ctable) {
- SkSafeUnref(mColorTable);
- mColorTable = ctable;
- SkSafeRef(mColorTable);
- }
-
- // 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 {
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;
}
+ size_t rowBytes() const {
+ if (mPixelRef) {
+ return mPixelRef->rowBytes();
+ }
+ return mRowBytes;
+ }
+
+ uint32_t getGenerationID() const {
+ if (mPixelRef) {
+ return mPixelRef->getGenerationID();
+ }
+ return mGenerationId;
+ }
+
+ ~Bitmap() { }
+
private:
- Bitmap& mBitmap;
- void* mStorage;
- size_t mRowBytes = 0;
- SkColorTable* mColorTable = nullptr;
- bool mHasHardwareMipMap = false;
-
- virtual void internal_dispose() const override {
- mBitmap.onStrongRefDestroyed();
- }
+ 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) {
- 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();
+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());
}
-Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc,
- const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
- : mPixelStorageType(PixelStorageType::External) {
+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;
+ reconfigure(info, rowBytes, ctable);
+}
+
+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();
+ reconfigure(info, rowBytes, ctable);
}
-void Bitmap::freePixels() {
- AutoMutex _lock(mLock);
- if (mPinnedRefCount == 0) {
- doFreePixels();
- mPixelStorageType = PixelStorageType::Invalid;
- }
-}
-
-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 @@
}
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 @@
}
}
-size_t Bitmap::getAllocationByteCount() const {
+size_t PixelRef::getAllocationByteCount() const {
switch (mPixelStorageType) {
case PixelStorageType::Heap:
return mPixelStorage.heap.size;
@@ -222,104 +251,24 @@
}
}
-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);
+ changeAlphaType(alphaType);
}
-void Bitmap::detachFromJava() {
- bool disposeSelf;
- {
- android::AutoMutex _lock(mLock);
- mAttachedToJava = false;
- disposeSelf = shouldDisposeSelfLocked();
- }
- if (disposeSelf) {
- delete this;
- }
+void PixelRef::getSkBitmap(SkBitmap* outBitmap) {
+ outBitmap->setInfo(info(), rowBytes());
+ outBitmap->setPixelRef(this);
+ outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
}
-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;
- }
-}
-
-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
@@ -333,7 +282,7 @@
}
void* pixels() {
- return mBitmap->peekAtPixelRef()->pixels();
+ return mBitmap->pixelRef()->pixels();
}
bool valid() {
@@ -344,6 +293,78 @@
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 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 @@
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 @@
0, 0, width, height, bitmap);
}
- return GraphicsJNI::createBitmap(env, nativeBitmap,
+ return createBitmap(env, nativeBitmap,
getPremulBitmapCreateFlags(isMutable));
}
@@ -699,29 +720,28 @@
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 @@
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 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 @@
// 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_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 @@
}
// 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 @@
blob.release();
}
- return GraphicsJNI::createBitmap(env, nativeBitmap,
+ return createBitmap(env, nativeBitmap,
getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
}
@@ -1034,7 +1055,7 @@
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 @@
// 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 @@
env->ReleaseIntArrayElements(offsetXY, array, 0);
}
- return GraphicsJNI::createBitmap(env, allocator.getStorageObjAndReset(),
+ return createBitmap(env, allocator.getStorageObjAndReset(),
getPremulBitmapCreateFlags(true));
}
@@ -1307,7 +1328,7 @@
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 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 @@
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 9ae1f3f..8e631ee 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 {
-public:
- Bitmap(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes,
- SkColorTable* ctable);
- Bitmap(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,
- size_t rowBytes, SkColorTable* ctable);
+class PixelRef;
- const SkImageInfo& info() const;
+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:
+ PixelRef(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes,
+ SkColorTable* ctable);
+ PixelRef(void* address, void* context, FreeFunc freeFunc,
+ const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
+ PixelRef(void* address, int fd, size_t mappedSize, const SkImageInfo& info,
+ size_t rowBytes, SkColorTable* ctable);
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* getStorage() const;
+ void setHasHardwareMipMap(bool hasMipMap);
+ bool hasHardwareMipMap() const;
- void pinPixelsLocked();
- bool shouldDisposeSelfLocked();
- void assertValid() const;
- SkPixelRef* refPixelRefLocked();
-
- 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 5a540ce..5bb0274 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -162,7 +162,7 @@
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 @@
}
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 @@
}
private:
- android::Bitmap* const mBitmap;
+ android::PixelRef* const mBitmap;
const unsigned int mSize;
};
@@ -326,16 +327,16 @@
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 @@
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 21850bd..7d0915b 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -148,14 +148,14 @@
}
// 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 @@
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 8cee814..8a55052 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -157,12 +157,6 @@
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 @@
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 @@
///////////////////////////////////////////////////////////////////////////////////////////
-// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
}
///////////////////////////////////////////////////////////////////////////////
-
-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 @@
// 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 @@
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 @@
"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 @@
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 738ad54..ceda3cd 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -23,12 +23,6 @@
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 @@
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 @@
*/
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 @@
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 @@
class RecyclingClippingPixelAllocator : public SkBRDAllocator {
public:
- RecyclingClippingPixelAllocator(android::Bitmap* recycledBitmap,
+ RecyclingClippingPixelAllocator(android::PixelRef* recycledBitmap,
size_t recycledBytes);
~RecyclingClippingPixelAllocator();
@@ -194,7 +169,7 @@
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 @@
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 d5a7a90..d4121ad 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -341,9 +341,8 @@
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 73b3f52..5d53b3f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -184,14 +184,14 @@
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,