Loading libs/hwui/jni/BitmapRegionDecoder.cpp +145 −14 Original line number Diff line number Diff line Loading @@ -17,28 +17,139 @@ #undef LOG_TAG #define LOG_TAG "BitmapRegionDecoder" #include "BitmapRegionDecoder.h" #include <HardwareBitmapUploader.h> #include <androidfw/Asset.h> #include <sys/stat.h> #include <memory> #include "BitmapFactory.h" #include "CreateJavaOutputStreamAdaptor.h" #include "Gainmap.h" #include "GraphicsJNI.h" #include "Utils.h" #include "BitmapRegionDecoder.h" #include "SkBitmap.h" #include "SkCodec.h" #include "SkColorSpace.h" #include "SkData.h" #include "SkGainmapInfo.h" #include "SkStream.h" #include "SkStreamPriv.h" #include "Utils.h" #include <HardwareBitmapUploader.h> #include <androidfw/Asset.h> #include <sys/stat.h> using namespace android; #include <memory> namespace android { class BitmapRegionDecoderWrapper { public: static std::unique_ptr<BitmapRegionDecoderWrapper> Make(sk_sp<SkData> data) { std::unique_ptr<skia::BitmapRegionDecoder> mainImageBRD = skia::BitmapRegionDecoder::Make(std::move(data)); if (!mainImageBRD) { return nullptr; } using namespace android; SkGainmapInfo gainmapInfo; std::unique_ptr<SkStream> gainmapStream; std::unique_ptr<skia::BitmapRegionDecoder> gainmapBRD = nullptr; if (mainImageBRD->getAndroidGainmap(&gainmapInfo, &gainmapStream)) { sk_sp<SkData> data = nullptr; if (gainmapStream->getMemoryBase()) { // It is safe to make without copy because we'll hold onto the stream. data = SkData::MakeWithoutCopy(gainmapStream->getMemoryBase(), gainmapStream->getLength()); } else { data = SkCopyStreamToData(gainmapStream.get()); // We don't need to hold the stream anymore gainmapStream = nullptr; } gainmapBRD = skia::BitmapRegionDecoder::Make(std::move(data)); } return std::unique_ptr<BitmapRegionDecoderWrapper>( new BitmapRegionDecoderWrapper(std::move(mainImageBRD), std::move(gainmapBRD), gainmapInfo, std::move(gainmapStream))); } SkEncodedImageFormat getEncodedFormat() { return mMainImageBRD->getEncodedFormat(); } SkColorType computeOutputColorType(SkColorType requestedColorType) { return mMainImageBRD->computeOutputColorType(requestedColorType); } sk_sp<SkColorSpace> computeOutputColorSpace(SkColorType outputColorType, sk_sp<SkColorSpace> prefColorSpace = nullptr) { return mMainImageBRD->computeOutputColorSpace(outputColorType, prefColorSpace); } bool decodeRegion(SkBitmap* bitmap, skia::BRDAllocator* allocator, const SkIRect& desiredSubset, int sampleSize, SkColorType colorType, bool requireUnpremul, sk_sp<SkColorSpace> prefColorSpace) { return mMainImageBRD->decodeRegion(bitmap, allocator, desiredSubset, sampleSize, colorType, requireUnpremul, prefColorSpace); } bool decodeGainmapRegion(sp<uirenderer::Gainmap>* outGainmap, const SkIRect& desiredSubset, int sampleSize, bool requireUnpremul) { SkColorType decodeColorType = mGainmapBRD->computeOutputColorType(kN32_SkColorType); sk_sp<SkColorSpace> decodeColorSpace = mGainmapBRD->computeOutputColorSpace(decodeColorType, nullptr); SkBitmap bm; HeapAllocator heapAlloc; if (!mGainmapBRD->decodeRegion(&bm, &heapAlloc, desiredSubset, sampleSize, decodeColorType, requireUnpremul, decodeColorSpace)) { ALOGE("Error decoding Gainmap region"); return false; } sk_sp<Bitmap> nativeBitmap(heapAlloc.getStorageObjAndReset()); if (!nativeBitmap) { ALOGE("OOM allocating Bitmap for Gainmap"); return false; } auto gainmap = sp<uirenderer::Gainmap>::make(); if (!gainmap) { ALOGE("OOM allocating Gainmap"); return false; } gainmap->info = mGainmapInfo; gainmap->bitmap = std::move(nativeBitmap); *outGainmap = std::move(gainmap); return true; } SkIRect calculateGainmapRegion(const SkIRect& mainImageRegion) { const float scaleX = ((float)mGainmapBRD->width()) / mMainImageBRD->width(); const float scaleY = ((float)mGainmapBRD->height()) / mMainImageBRD->height(); // TODO: Account for rounding error? return SkIRect::MakeLTRB(mainImageRegion.left() * scaleX, mainImageRegion.top() * scaleY, mainImageRegion.right() * scaleX, mainImageRegion.bottom() * scaleY); } bool hasGainmap() { return mGainmapBRD != nullptr; } int width() const { return mMainImageBRD->width(); } int height() const { return mMainImageBRD->height(); } private: BitmapRegionDecoderWrapper(std::unique_ptr<skia::BitmapRegionDecoder> mainImageBRD, std::unique_ptr<skia::BitmapRegionDecoder> gainmapBRD, SkGainmapInfo info, std::unique_ptr<SkStream> stream) : mMainImageBRD(std::move(mainImageBRD)) , mGainmapBRD(std::move(gainmapBRD)) , mGainmapInfo(info) , mGainmapStream(std::move(stream)) {} std::unique_ptr<skia::BitmapRegionDecoder> mMainImageBRD; std::unique_ptr<skia::BitmapRegionDecoder> mGainmapBRD; SkGainmapInfo mGainmapInfo; std::unique_ptr<SkStream> mGainmapStream; }; } // namespace android static jobject createBitmapRegionDecoder(JNIEnv* env, sk_sp<SkData> data) { auto brd = skia::BitmapRegionDecoder::Make(std::move(data)); auto brd = android::BitmapRegionDecoderWrapper::Make(std::move(data)); if (!brd) { doThrowIOE(env, "Image format not supported"); return nullObjectReturn("CreateBitmapRegionDecoder returned null"); Loading Loading @@ -136,7 +247,7 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in recycledBytes = recycledBitmap->getAllocationByteCount(); } auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle); SkColorType decodeColorType = brd->computeOutputColorType(colorType); if (isHardware) { Loading Loading @@ -196,9 +307,22 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in GraphicsJNI::getColorSpace(env, decodeColorSpace.get(), decodeColorType)); } sp<uirenderer::Gainmap> gainmap; bool hasGainmap = brd->hasGainmap(); if (hasGainmap) { SkIRect gainmapSubset = brd->calculateGainmapRegion(subset); if (!brd->decodeGainmapRegion(&gainmap, gainmapSubset, sampleSize, requireUnpremul)) { // If there is an error decoding Gainmap - we don't fail. We just don't provide Gainmap hasGainmap = false; } } // If we may have reused a bitmap, we need to indicate that the pixels have changed. if (javaBitmap) { recycleAlloc.copyIfNecessary(); if (hasGainmap) { recycledBitmap->setGainmap(std::move(gainmap)); } bitmap::reinitBitmap(env, javaBitmap, recycledBitmap->info(), !requireUnpremul); return javaBitmap; } Loading @@ -209,23 +333,30 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in } if (isHardware) { sk_sp<Bitmap> hardwareBitmap = Bitmap::allocateHardwareBitmap(bitmap); if (hasGainmap) { hardwareBitmap->setGainmap(std::move(gainmap)); } return bitmap::createBitmap(env, hardwareBitmap.release(), bitmapCreateFlags); } return android::bitmap::createBitmap(env, heapAlloc.getStorageObjAndReset(), bitmapCreateFlags); Bitmap* heapBitmap = heapAlloc.getStorageObjAndReset(); if (hasGainmap && heapBitmap != nullptr) { heapBitmap->setGainmap(std::move(gainmap)); } return android::bitmap::createBitmap(env, heapBitmap, bitmapCreateFlags); } static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) { auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle); return static_cast<jint>(brd->height()); } static jint nativeGetWidth(JNIEnv* env, jobject, jlong brdHandle) { auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle); return static_cast<jint>(brd->width()); } static void nativeClean(JNIEnv* env, jobject, jlong brdHandle) { auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle); delete brd; } Loading libs/hwui/jni/Graphics.cpp +1 −2 Original line number Diff line number Diff line Loading @@ -516,8 +516,7 @@ int GraphicsJNI::set_metrics_int(JNIEnv* env, jobject metrics, const SkFontMetri /////////////////////////////////////////////////////////////////////////////////////////// jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, skia::BitmapRegionDecoder* bitmap) { jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, BitmapRegionDecoderWrapper* bitmap) { ALOG_ASSERT(bitmap != NULL); jobject obj = env->NewObject(gBitmapRegionDecoder_class, Loading libs/hwui/jni/GraphicsJNI.h +2 −4 Original line number Diff line number Diff line Loading @@ -20,9 +20,7 @@ class SkCanvas; struct SkFontMetrics; namespace android { namespace skia { class BitmapRegionDecoder; } class BitmapRegionDecoderWrapper; class Canvas; class Paint; struct Typeface; Loading Loading @@ -119,7 +117,7 @@ public: static jobject createRegion(JNIEnv* env, SkRegion* region); static jobject createBitmapRegionDecoder(JNIEnv* env, android::skia::BitmapRegionDecoder* bitmap); android::BitmapRegionDecoderWrapper* bitmap); /** * Given a bitmap we natively allocate a memory block to store the contents Loading Loading
libs/hwui/jni/BitmapRegionDecoder.cpp +145 −14 Original line number Diff line number Diff line Loading @@ -17,28 +17,139 @@ #undef LOG_TAG #define LOG_TAG "BitmapRegionDecoder" #include "BitmapRegionDecoder.h" #include <HardwareBitmapUploader.h> #include <androidfw/Asset.h> #include <sys/stat.h> #include <memory> #include "BitmapFactory.h" #include "CreateJavaOutputStreamAdaptor.h" #include "Gainmap.h" #include "GraphicsJNI.h" #include "Utils.h" #include "BitmapRegionDecoder.h" #include "SkBitmap.h" #include "SkCodec.h" #include "SkColorSpace.h" #include "SkData.h" #include "SkGainmapInfo.h" #include "SkStream.h" #include "SkStreamPriv.h" #include "Utils.h" #include <HardwareBitmapUploader.h> #include <androidfw/Asset.h> #include <sys/stat.h> using namespace android; #include <memory> namespace android { class BitmapRegionDecoderWrapper { public: static std::unique_ptr<BitmapRegionDecoderWrapper> Make(sk_sp<SkData> data) { std::unique_ptr<skia::BitmapRegionDecoder> mainImageBRD = skia::BitmapRegionDecoder::Make(std::move(data)); if (!mainImageBRD) { return nullptr; } using namespace android; SkGainmapInfo gainmapInfo; std::unique_ptr<SkStream> gainmapStream; std::unique_ptr<skia::BitmapRegionDecoder> gainmapBRD = nullptr; if (mainImageBRD->getAndroidGainmap(&gainmapInfo, &gainmapStream)) { sk_sp<SkData> data = nullptr; if (gainmapStream->getMemoryBase()) { // It is safe to make without copy because we'll hold onto the stream. data = SkData::MakeWithoutCopy(gainmapStream->getMemoryBase(), gainmapStream->getLength()); } else { data = SkCopyStreamToData(gainmapStream.get()); // We don't need to hold the stream anymore gainmapStream = nullptr; } gainmapBRD = skia::BitmapRegionDecoder::Make(std::move(data)); } return std::unique_ptr<BitmapRegionDecoderWrapper>( new BitmapRegionDecoderWrapper(std::move(mainImageBRD), std::move(gainmapBRD), gainmapInfo, std::move(gainmapStream))); } SkEncodedImageFormat getEncodedFormat() { return mMainImageBRD->getEncodedFormat(); } SkColorType computeOutputColorType(SkColorType requestedColorType) { return mMainImageBRD->computeOutputColorType(requestedColorType); } sk_sp<SkColorSpace> computeOutputColorSpace(SkColorType outputColorType, sk_sp<SkColorSpace> prefColorSpace = nullptr) { return mMainImageBRD->computeOutputColorSpace(outputColorType, prefColorSpace); } bool decodeRegion(SkBitmap* bitmap, skia::BRDAllocator* allocator, const SkIRect& desiredSubset, int sampleSize, SkColorType colorType, bool requireUnpremul, sk_sp<SkColorSpace> prefColorSpace) { return mMainImageBRD->decodeRegion(bitmap, allocator, desiredSubset, sampleSize, colorType, requireUnpremul, prefColorSpace); } bool decodeGainmapRegion(sp<uirenderer::Gainmap>* outGainmap, const SkIRect& desiredSubset, int sampleSize, bool requireUnpremul) { SkColorType decodeColorType = mGainmapBRD->computeOutputColorType(kN32_SkColorType); sk_sp<SkColorSpace> decodeColorSpace = mGainmapBRD->computeOutputColorSpace(decodeColorType, nullptr); SkBitmap bm; HeapAllocator heapAlloc; if (!mGainmapBRD->decodeRegion(&bm, &heapAlloc, desiredSubset, sampleSize, decodeColorType, requireUnpremul, decodeColorSpace)) { ALOGE("Error decoding Gainmap region"); return false; } sk_sp<Bitmap> nativeBitmap(heapAlloc.getStorageObjAndReset()); if (!nativeBitmap) { ALOGE("OOM allocating Bitmap for Gainmap"); return false; } auto gainmap = sp<uirenderer::Gainmap>::make(); if (!gainmap) { ALOGE("OOM allocating Gainmap"); return false; } gainmap->info = mGainmapInfo; gainmap->bitmap = std::move(nativeBitmap); *outGainmap = std::move(gainmap); return true; } SkIRect calculateGainmapRegion(const SkIRect& mainImageRegion) { const float scaleX = ((float)mGainmapBRD->width()) / mMainImageBRD->width(); const float scaleY = ((float)mGainmapBRD->height()) / mMainImageBRD->height(); // TODO: Account for rounding error? return SkIRect::MakeLTRB(mainImageRegion.left() * scaleX, mainImageRegion.top() * scaleY, mainImageRegion.right() * scaleX, mainImageRegion.bottom() * scaleY); } bool hasGainmap() { return mGainmapBRD != nullptr; } int width() const { return mMainImageBRD->width(); } int height() const { return mMainImageBRD->height(); } private: BitmapRegionDecoderWrapper(std::unique_ptr<skia::BitmapRegionDecoder> mainImageBRD, std::unique_ptr<skia::BitmapRegionDecoder> gainmapBRD, SkGainmapInfo info, std::unique_ptr<SkStream> stream) : mMainImageBRD(std::move(mainImageBRD)) , mGainmapBRD(std::move(gainmapBRD)) , mGainmapInfo(info) , mGainmapStream(std::move(stream)) {} std::unique_ptr<skia::BitmapRegionDecoder> mMainImageBRD; std::unique_ptr<skia::BitmapRegionDecoder> mGainmapBRD; SkGainmapInfo mGainmapInfo; std::unique_ptr<SkStream> mGainmapStream; }; } // namespace android static jobject createBitmapRegionDecoder(JNIEnv* env, sk_sp<SkData> data) { auto brd = skia::BitmapRegionDecoder::Make(std::move(data)); auto brd = android::BitmapRegionDecoderWrapper::Make(std::move(data)); if (!brd) { doThrowIOE(env, "Image format not supported"); return nullObjectReturn("CreateBitmapRegionDecoder returned null"); Loading Loading @@ -136,7 +247,7 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in recycledBytes = recycledBitmap->getAllocationByteCount(); } auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle); SkColorType decodeColorType = brd->computeOutputColorType(colorType); if (isHardware) { Loading Loading @@ -196,9 +307,22 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in GraphicsJNI::getColorSpace(env, decodeColorSpace.get(), decodeColorType)); } sp<uirenderer::Gainmap> gainmap; bool hasGainmap = brd->hasGainmap(); if (hasGainmap) { SkIRect gainmapSubset = brd->calculateGainmapRegion(subset); if (!brd->decodeGainmapRegion(&gainmap, gainmapSubset, sampleSize, requireUnpremul)) { // If there is an error decoding Gainmap - we don't fail. We just don't provide Gainmap hasGainmap = false; } } // If we may have reused a bitmap, we need to indicate that the pixels have changed. if (javaBitmap) { recycleAlloc.copyIfNecessary(); if (hasGainmap) { recycledBitmap->setGainmap(std::move(gainmap)); } bitmap::reinitBitmap(env, javaBitmap, recycledBitmap->info(), !requireUnpremul); return javaBitmap; } Loading @@ -209,23 +333,30 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in } if (isHardware) { sk_sp<Bitmap> hardwareBitmap = Bitmap::allocateHardwareBitmap(bitmap); if (hasGainmap) { hardwareBitmap->setGainmap(std::move(gainmap)); } return bitmap::createBitmap(env, hardwareBitmap.release(), bitmapCreateFlags); } return android::bitmap::createBitmap(env, heapAlloc.getStorageObjAndReset(), bitmapCreateFlags); Bitmap* heapBitmap = heapAlloc.getStorageObjAndReset(); if (hasGainmap && heapBitmap != nullptr) { heapBitmap->setGainmap(std::move(gainmap)); } return android::bitmap::createBitmap(env, heapBitmap, bitmapCreateFlags); } static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) { auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle); return static_cast<jint>(brd->height()); } static jint nativeGetWidth(JNIEnv* env, jobject, jlong brdHandle) { auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle); return static_cast<jint>(brd->width()); } static void nativeClean(JNIEnv* env, jobject, jlong brdHandle) { auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle); delete brd; } Loading
libs/hwui/jni/Graphics.cpp +1 −2 Original line number Diff line number Diff line Loading @@ -516,8 +516,7 @@ int GraphicsJNI::set_metrics_int(JNIEnv* env, jobject metrics, const SkFontMetri /////////////////////////////////////////////////////////////////////////////////////////// jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, skia::BitmapRegionDecoder* bitmap) { jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, BitmapRegionDecoderWrapper* bitmap) { ALOG_ASSERT(bitmap != NULL); jobject obj = env->NewObject(gBitmapRegionDecoder_class, Loading
libs/hwui/jni/GraphicsJNI.h +2 −4 Original line number Diff line number Diff line Loading @@ -20,9 +20,7 @@ class SkCanvas; struct SkFontMetrics; namespace android { namespace skia { class BitmapRegionDecoder; } class BitmapRegionDecoderWrapper; class Canvas; class Paint; struct Typeface; Loading Loading @@ -119,7 +117,7 @@ public: static jobject createRegion(JNIEnv* env, SkRegion* region); static jobject createBitmapRegionDecoder(JNIEnv* env, android::skia::BitmapRegionDecoder* bitmap); android::BitmapRegionDecoderWrapper* bitmap); /** * Given a bitmap we natively allocate a memory block to store the contents Loading