diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 0487e139d264e..2dec4b399e576 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -223,97 +223,11 @@ void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) { bitmap->getSkBitmap(outBitmap); } -Bitmap& toBitmap(JNIEnv* env, jobject bitmap) { - SkASSERT(env); - SkASSERT(bitmap); - SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); - jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); - LocalScopedBitmap localBitmap(bitmapHandle); - return localBitmap->bitmap(); -} - Bitmap& toBitmap(jlong bitmapHandle) { LocalScopedBitmap localBitmap(bitmapHandle); return localBitmap->bitmap(); } -void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info) { - jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); - LocalScopedBitmap localBitmap(bitmapHandle); - - const SkImageInfo& imageInfo = localBitmap->info(); - info->width = imageInfo.width(); - info->height = imageInfo.height(); - info->stride = localBitmap->rowBytes(); - info->flags = 0; - switch (imageInfo.colorType()) { - case kN32_SkColorType: - info->format = ANDROID_BITMAP_FORMAT_RGBA_8888; - break; - case kRGB_565_SkColorType: - info->format = ANDROID_BITMAP_FORMAT_RGB_565; - break; - case kARGB_4444_SkColorType: - info->format = ANDROID_BITMAP_FORMAT_RGBA_4444; - break; - case kAlpha_8_SkColorType: - info->format = ANDROID_BITMAP_FORMAT_A_8; - break; - case kRGBA_F16_SkColorType: - info->format = ANDROID_BITMAP_FORMAT_RGBA_F16; - break; - default: - info->format = ANDROID_BITMAP_FORMAT_NONE; - break; - } - switch (imageInfo.alphaType()) { - case kUnknown_SkAlphaType: - LOG_ALWAYS_FATAL("Bitmap has no alpha type"); - break; - case kOpaque_SkAlphaType: - info->flags |= ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE; - break; - case kPremul_SkAlphaType: - info->flags |= ANDROID_BITMAP_FLAGS_ALPHA_PREMUL; - break; - case kUnpremul_SkAlphaType: - info->flags |= ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL; - break; - } -} - -void* lockPixels(JNIEnv* env, jobject bitmap) { - SkASSERT(env); - SkASSERT(bitmap); - SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); - jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); - - LocalScopedBitmap localBitmap(bitmapHandle); - if (!localBitmap->valid()) return nullptr; - - SkPixelRef& pixelRef = localBitmap->bitmap(); - if (!pixelRef.pixels()) { - return nullptr; - } - pixelRef.ref(); - return pixelRef.pixels(); -} - -bool unlockPixels(JNIEnv* env, jobject bitmap) { - SkASSERT(env); - SkASSERT(bitmap); - SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); - jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); - - LocalScopedBitmap localBitmap(bitmapHandle); - if (!localBitmap->valid()) return false; - - SkPixelRef& pixelRef = localBitmap->bitmap(); - pixelRef.notifyPixelsChanged(); - pixelRef.unref(); - return true; -} - } // namespace bitmap } // namespace android @@ -321,6 +235,27 @@ bool unlockPixels(JNIEnv* env, jobject bitmap) { using namespace android; using namespace android::bitmap; +Bitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) { + SkASSERT(env); + SkASSERT(bitmap); + SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); + jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); + LocalScopedBitmap localBitmap(bitmapHandle); + return localBitmap.valid() ? &localBitmap->bitmap() : nullptr; +} + +SkImageInfo GraphicsJNI::getBitmapInfo(JNIEnv* env, jobject bitmap, uint32_t* outRowBytes) { + SkASSERT(env); + SkASSERT(bitmap); + SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); + jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); + LocalScopedBitmap localBitmap(bitmapHandle); + if (outRowBytes) { + *outRowBytes = localBitmap->rowBytes(); + } + return localBitmap->info(); +} + bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride, int x, int y, int width, int height, SkBitmap* dstBitmap) { const jint* array = env->GetIntArrayElements(srcColors, NULL); diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h index 59adbb207a0c6..73eca3aa8ef86 100644 --- a/core/jni/android/graphics/Bitmap.h +++ b/core/jni/android/graphics/Bitmap.h @@ -38,17 +38,8 @@ jobject createBitmap(JNIEnv* env, Bitmap* bitmap, int bitmapCreateFlags, jbyteArray ninePatchChunk = nullptr, jobject ninePatchInsets = nullptr, int density = -1); - -Bitmap& toBitmap(JNIEnv* env, jobject bitmap); Bitmap& toBitmap(jlong bitmapHandle); -// NDK access -void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info); -// Returns a pointer to the pixels or nullptr if the bitmap is not valid -void* lockPixels(JNIEnv* env, jobject bitmap); -// Returns true if unlocked, false if the bitmap is no longer valid (destroyed) -bool unlockPixels(JNIEnv* env, jobject bitmap); - /** Reinitialize a bitmap. bitmap must already have its SkAlphaType set in sync with isPremultiplied */ diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index bc1cc09506adf..aa209cb3899e4 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -342,10 +342,6 @@ SkColorType GraphicsJNI::legacyBitmapConfigToColorType(jint legacyConfig) { return static_cast(gConfig2ColorType[legacyConfig]); } -void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap) { - bitmap::toBitmap(env, bitmap).getSkBitmap(outBitmap); -} - AndroidBitmapFormat GraphicsJNI::getFormatFromConfig(JNIEnv* env, jobject jconfig) { ALOG_ASSERT(env); if (NULL == jconfig) { diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 6e7d9e736c0a8..99034edaadf7f 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -61,7 +61,8 @@ public: static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf); static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas); - static void getSkBitmap(JNIEnv*, jobject bitmap, SkBitmap* outBitmap); + static android::Bitmap* getNativeBitmap(JNIEnv*, jobject bitmap); + static SkImageInfo getBitmapInfo(JNIEnv*, jobject bitmap, uint32_t* outRowBytes); static SkRegion* getNativeRegion(JNIEnv*, jobject region); /* diff --git a/core/jni/android/graphics/apex/android_bitmap.cpp b/core/jni/android/graphics/apex/android_bitmap.cpp index a328def879080..90cc986998274 100644 --- a/core/jni/android/graphics/apex/android_bitmap.cpp +++ b/core/jni/android/graphics/apex/android_bitmap.cpp @@ -14,19 +14,25 @@ * limitations under the License. */ +#define LOG_TAG "Bitmap" +#include + #include "android/graphics/bitmap.h" -#include "Bitmap.h" #include "TypeCast.h" #include "GraphicsJNI.h" +#include #include using namespace android; ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj) { - Bitmap& bitmap = android::bitmap::toBitmap(env, bitmapObj); - bitmap.ref(); - return TypeCast::toABitmap(&bitmap); + Bitmap* bitmap = GraphicsJNI::getNativeBitmap(env, bitmapObj); + if (bitmap) { + bitmap->ref(); + return TypeCast::toABitmap(bitmap); + } + return nullptr; } void ABitmap_acquireRef(ABitmap* bitmap) { @@ -37,8 +43,8 @@ void ABitmap_releaseRef(ABitmap* bitmap) { SkSafeUnref(TypeCast::toBitmap(bitmap)); } -static AndroidBitmapFormat getFormat(Bitmap* bitmap) { - switch (bitmap->colorType()) { +static AndroidBitmapFormat getFormat(const SkImageInfo& info) { + switch (info.colorType()) { case kN32_SkColorType: return ANDROID_BITMAP_FORMAT_RGBA_8888; case kRGB_565_SkColorType: @@ -71,6 +77,20 @@ static SkColorType getColorType(AndroidBitmapFormat format) { } } +static uint32_t getInfoFlags(const SkImageInfo& info) { + switch (info.alphaType()) { + case kUnknown_SkAlphaType: + LOG_ALWAYS_FATAL("Bitmap has no alpha type"); + break; + case kOpaque_SkAlphaType: + return ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE; + case kPremul_SkAlphaType: + return ANDROID_BITMAP_FLAGS_ALPHA_PREMUL; + case kUnpremul_SkAlphaType: + return ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL; + } +} + ABitmap* ABitmap_copy(ABitmap* srcBitmapHandle, AndroidBitmapFormat dstFormat) { SkColorType dstColorType = getColorType(dstFormat); if (srcBitmapHandle && dstColorType != kUnknown_SkColorType) { @@ -87,15 +107,25 @@ ABitmap* ABitmap_copy(ABitmap* srcBitmapHandle, AndroidBitmapFormat dstFormat) { return nullptr; } +static AndroidBitmapInfo getInfo(const SkImageInfo& imageInfo, uint32_t rowBytes) { + AndroidBitmapInfo info; + info.width = imageInfo.width(); + info.height = imageInfo.height(); + info.stride = rowBytes; + info.format = getFormat(imageInfo); + info.flags = getInfoFlags(imageInfo); + return info; +} + AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmapHandle) { Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle); + return getInfo(bitmap->info(), bitmap->rowBytes()); +} - AndroidBitmapInfo info; - info.width = bitmap->width(); - info.height = bitmap->height(); - info.stride = bitmap->rowBytes(); - info.format = getFormat(bitmap); - return info; +AndroidBitmapInfo ABitmap_getInfoFromJava(JNIEnv* env, jobject bitmapObj) { + uint32_t rowBytes = 0; + SkImageInfo imageInfo = GraphicsJNI::getBitmapInfo(env, bitmapObj, &rowBytes); + return getInfo(imageInfo, rowBytes); } void* ABitmap_getPixels(ABitmap* bitmapHandle) { @@ -107,9 +137,17 @@ void* ABitmap_getPixels(ABitmap* bitmapHandle) { } AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj) { - return GraphicsJNI::getFormatFromConfig(env, bitmapConfigObj); + return GraphicsJNI::getFormatFromConfig(env, bitmapConfigObj); } jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format) { - return GraphicsJNI::getConfigFromFormat(env, format); + return GraphicsJNI::getConfigFromFormat(env, format); +} + +void ABitmap_notifyPixelsChanged(ABitmap* bitmapHandle) { + Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle); + if (bitmap->isImmutable()) { + ALOGE("Attempting to modify an immutable Bitmap!"); + } + return bitmap->notifyPixelsChanged(); } diff --git a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h index dea55172b3bb2..f231eeddb7e23 100644 --- a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h +++ b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h @@ -27,6 +27,20 @@ __BEGIN_DECLS */ typedef struct ABitmap ABitmap; +/** + * Retrieve bitmapInfo for the provided java bitmap even if it has been recycled. In the case of a + * recycled bitmap the values contained in the bitmap before it was recycled are returned. + * + * NOTE: This API does not need to remain as an APEX API if/when we pull libjnigraphics into the + * UI module. + */ +AndroidBitmapInfo ABitmap_getInfoFromJava(JNIEnv* env, jobject bitmapObj); + +/** + * + * @return ptr to an opaque handle to the native bitmap or null if the java bitmap has been recycled + * or does not exist. + */ ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj); ABitmap* ABitmap_copy(ABitmap* srcBitmap, AndroidBitmapFormat dstFormat); @@ -37,6 +51,7 @@ void ABitmap_releaseRef(ABitmap* bitmap); AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmap); void* ABitmap_getPixels(ABitmap* bitmap); +void ABitmap_notifyPixelsChanged(ABitmap* bitmap); AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj); jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format); @@ -88,10 +103,12 @@ namespace graphics { mBitmap = nullptr; } - const ABitmap* get() const { return mBitmap; } + ABitmap* get() const { return mBitmap; } AndroidBitmapInfo getInfo() const { return ABitmap_getInfo(mBitmap); } void* getPixels() const { return ABitmap_getPixels(mBitmap); } + void notifyPixelsChanged() const { ABitmap_notifyPixelsChanged(mBitmap); } + private: // takes ownership of the provided ABitmap Bitmap(ABitmap* bitmap) : mBitmap(bitmap) {} diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp index ff14832a2f0f0..1aebeaf1e7e83 100644 --- a/native/graphics/jni/bitmap.cpp +++ b/native/graphics/jni/bitmap.cpp @@ -15,7 +15,7 @@ */ #include -#include +#include int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, AndroidBitmapInfo* info) { @@ -24,7 +24,7 @@ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, } if (info) { - android::bitmap::imageInfo(env, jbitmap, info); + *info = ABitmap_getInfoFromJava(env, jbitmap); } return ANDROID_BITMAP_RESULT_SUCCESS; } @@ -34,11 +34,15 @@ int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } - void* addr = android::bitmap::lockPixels(env, jbitmap); + android::graphics::Bitmap bitmap(env, jbitmap); + void* addr = bitmap.isValid() ? bitmap.getPixels() : nullptr; + if (!addr) { return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; } + ABitmap_acquireRef(bitmap.get()); + if (addrPtr) { *addrPtr = addr; } @@ -50,9 +54,13 @@ int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } - bool unlocked = android::bitmap::unlockPixels(env, jbitmap); - if (!unlocked) { + android::graphics::Bitmap bitmap(env, jbitmap); + + if (!bitmap.isValid()) { return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; } + + bitmap.notifyPixelsChanged(); + ABitmap_releaseRef(bitmap.get()); return ANDROID_BITMAP_RESULT_SUCCESS; }