Loading libs/hwui/hwui/ImageDecoder.cpp +36 −15 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChu , mOutColorType(mCodec->computeOutputColorType(kN32_SkColorType)) , mUnpremultipliedRequired(false) , mOutColorSpace(getDefaultColorSpace()) , mHandleRestorePrevious(true) { mTargetSize = swapWidthHeight() ? SkISize { mDecodeSize.height(), mDecodeSize.width() } : mDecodeSize; Loading Loading @@ -230,6 +231,13 @@ bool ImageDecoder::rewind() { return true; } void ImageDecoder::setHandleRestorePrevious(bool handle) { mHandleRestorePrevious = handle; if (!handle) { mRestoreFrame = nullptr; } } bool ImageDecoder::advanceFrame() { const int frameIndex = ++mOptions.fFrameIndex; const int frameCount = mCodec->codec()->getFrameCount(); Loading @@ -255,6 +263,7 @@ bool ImageDecoder::advanceFrame() { case RestoreState::kDoNothing: case RestoreState::kNeedsRestore: mRestoreState = RestoreState::kFirstRPFrame; mOptions.fPriorFrame = frameIndex - 1; break; case RestoreState::kFirstRPFrame: mRestoreState = RestoreState::kRPFrame; Loading Loading @@ -315,29 +324,19 @@ bool ImageDecoder::finished() const { return mOptions.fFrameIndex >= mCodec->codec()->getFrameCount(); } SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { // This was checked inside setTargetSize, but it's possible the first frame // was opaque, so that method succeeded, but after calling advanceFrame, the // current frame is not opaque. if (mUnpremultipliedRequired && !opaque()) { // Allow using a matrix to handle orientation, but not scaling. if (requires_matrix_scaling(swapWidthHeight(), mDecodeSize, mTargetSize)) { return SkCodec::kInvalidScale; } bool ImageDecoder::handleRestorePrevious(const SkImageInfo& outputInfo, void* pixels, size_t rowBytes) { if (!mHandleRestorePrevious) { return true; } void* decodePixels = pixels; size_t decodeRowBytes = rowBytes; const auto decodeInfo = SkImageInfo::Make(mDecodeSize, mOutColorType, getOutAlphaType(), getOutputColorSpace()); const auto outputInfo = getOutputInfo(); switch (mRestoreState) { case RestoreState::kFirstRPFrame:{ // This frame is marked kRestorePrevious. The prior frame should be in // |pixels|, and it is what we'll restore after each consecutive // kRestorePrevious frame. Cache it now. if (!(mRestoreFrame = Bitmap::allocateHeapBitmap(outputInfo))) { return SkCodec::kInternalError; return false; } const uint8_t* srcRow = static_cast<uint8_t*>(pixels); Loading Loading @@ -366,7 +365,29 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { case RestoreState::kDoNothing: break; } return true; } SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { // This was checked inside setTargetSize, but it's possible the first frame // was opaque, so that method succeeded, but after calling advanceFrame, the // current frame is not opaque. if (mUnpremultipliedRequired && !opaque()) { // Allow using a matrix to handle orientation, but not scaling. if (requires_matrix_scaling(swapWidthHeight(), mDecodeSize, mTargetSize)) { return SkCodec::kInvalidScale; } } const auto outputInfo = getOutputInfo(); if (!handleRestorePrevious(outputInfo, pixels, rowBytes)) { return SkCodec::kInternalError; } void* decodePixels = pixels; size_t decodeRowBytes = rowBytes; const auto decodeInfo = SkImageInfo::Make(mDecodeSize, mOutColorType, getOutAlphaType(), getOutputColorSpace()); // Used if we need a temporary before scaling or subsetting. // FIXME: Use scanline decoding on only a couple lines to save memory. b/70709380. SkBitmap tmp; Loading libs/hwui/hwui/ImageDecoder.h +6 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,9 @@ public: SkCodec::FrameInfo getCurrentFrameInfo(); // Set whether the ImageDecoder should handle RestorePrevious frames. void setHandleRestorePrevious(bool handle); private: // State machine for keeping track of how to handle RestorePrevious (RP) // frames in decode(). Loading Loading @@ -105,6 +108,7 @@ private: SkAndroidCodec::AndroidOptions mOptions; bool mCurrentFrameIsIndependent; bool mCurrentFrameIsOpaque; bool mHandleRestorePrevious; RestoreState mRestoreState; sk_sp<Bitmap> mRestoreFrame; std::optional<SkIRect> mCropRect; Loading @@ -115,6 +119,8 @@ private: SkAlphaType getOutAlphaType() const; sk_sp<SkColorSpace> getOutputColorSpace() const; bool swapWidthHeight() const; // Store/restore a frame if necessary. Returns false on error. bool handleRestorePrevious(const SkImageInfo&, void* pixels, size_t rowBytes); }; } // namespace android native/graphics/jni/imagedecoder.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -535,3 +535,9 @@ int32_t AImageDecoderFrameInfo_getBlendOp(const AImageDecoderFrameInfo* info) { return ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER; } } void AImageDecoder_setInternallyHandleDisposePrevious(AImageDecoder* decoder, bool handle) { if (decoder) { toDecoder(decoder)->setHandleRestorePrevious(handle); } } native/graphics/jni/libjnigraphics.map.txt +1 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ LIBJNIGRAPHICS { AImageDecoder_advanceFrame; # introduced=31 AImageDecoder_rewind; # introduced=31 AImageDecoder_getFrameInfo; # introduced = 31 AImageDecoder_setInternallyHandleDisposePrevious; # introduced = 31 AImageDecoderHeaderInfo_getWidth; # introduced=30 AImageDecoderHeaderInfo_getHeight; # introduced=30 AImageDecoderHeaderInfo_getMimeType; # introduced=30 Loading Loading
libs/hwui/hwui/ImageDecoder.cpp +36 −15 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChu , mOutColorType(mCodec->computeOutputColorType(kN32_SkColorType)) , mUnpremultipliedRequired(false) , mOutColorSpace(getDefaultColorSpace()) , mHandleRestorePrevious(true) { mTargetSize = swapWidthHeight() ? SkISize { mDecodeSize.height(), mDecodeSize.width() } : mDecodeSize; Loading Loading @@ -230,6 +231,13 @@ bool ImageDecoder::rewind() { return true; } void ImageDecoder::setHandleRestorePrevious(bool handle) { mHandleRestorePrevious = handle; if (!handle) { mRestoreFrame = nullptr; } } bool ImageDecoder::advanceFrame() { const int frameIndex = ++mOptions.fFrameIndex; const int frameCount = mCodec->codec()->getFrameCount(); Loading @@ -255,6 +263,7 @@ bool ImageDecoder::advanceFrame() { case RestoreState::kDoNothing: case RestoreState::kNeedsRestore: mRestoreState = RestoreState::kFirstRPFrame; mOptions.fPriorFrame = frameIndex - 1; break; case RestoreState::kFirstRPFrame: mRestoreState = RestoreState::kRPFrame; Loading Loading @@ -315,29 +324,19 @@ bool ImageDecoder::finished() const { return mOptions.fFrameIndex >= mCodec->codec()->getFrameCount(); } SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { // This was checked inside setTargetSize, but it's possible the first frame // was opaque, so that method succeeded, but after calling advanceFrame, the // current frame is not opaque. if (mUnpremultipliedRequired && !opaque()) { // Allow using a matrix to handle orientation, but not scaling. if (requires_matrix_scaling(swapWidthHeight(), mDecodeSize, mTargetSize)) { return SkCodec::kInvalidScale; } bool ImageDecoder::handleRestorePrevious(const SkImageInfo& outputInfo, void* pixels, size_t rowBytes) { if (!mHandleRestorePrevious) { return true; } void* decodePixels = pixels; size_t decodeRowBytes = rowBytes; const auto decodeInfo = SkImageInfo::Make(mDecodeSize, mOutColorType, getOutAlphaType(), getOutputColorSpace()); const auto outputInfo = getOutputInfo(); switch (mRestoreState) { case RestoreState::kFirstRPFrame:{ // This frame is marked kRestorePrevious. The prior frame should be in // |pixels|, and it is what we'll restore after each consecutive // kRestorePrevious frame. Cache it now. if (!(mRestoreFrame = Bitmap::allocateHeapBitmap(outputInfo))) { return SkCodec::kInternalError; return false; } const uint8_t* srcRow = static_cast<uint8_t*>(pixels); Loading Loading @@ -366,7 +365,29 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { case RestoreState::kDoNothing: break; } return true; } SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { // This was checked inside setTargetSize, but it's possible the first frame // was opaque, so that method succeeded, but after calling advanceFrame, the // current frame is not opaque. if (mUnpremultipliedRequired && !opaque()) { // Allow using a matrix to handle orientation, but not scaling. if (requires_matrix_scaling(swapWidthHeight(), mDecodeSize, mTargetSize)) { return SkCodec::kInvalidScale; } } const auto outputInfo = getOutputInfo(); if (!handleRestorePrevious(outputInfo, pixels, rowBytes)) { return SkCodec::kInternalError; } void* decodePixels = pixels; size_t decodeRowBytes = rowBytes; const auto decodeInfo = SkImageInfo::Make(mDecodeSize, mOutColorType, getOutAlphaType(), getOutputColorSpace()); // Used if we need a temporary before scaling or subsetting. // FIXME: Use scanline decoding on only a couple lines to save memory. b/70709380. SkBitmap tmp; Loading
libs/hwui/hwui/ImageDecoder.h +6 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,9 @@ public: SkCodec::FrameInfo getCurrentFrameInfo(); // Set whether the ImageDecoder should handle RestorePrevious frames. void setHandleRestorePrevious(bool handle); private: // State machine for keeping track of how to handle RestorePrevious (RP) // frames in decode(). Loading Loading @@ -105,6 +108,7 @@ private: SkAndroidCodec::AndroidOptions mOptions; bool mCurrentFrameIsIndependent; bool mCurrentFrameIsOpaque; bool mHandleRestorePrevious; RestoreState mRestoreState; sk_sp<Bitmap> mRestoreFrame; std::optional<SkIRect> mCropRect; Loading @@ -115,6 +119,8 @@ private: SkAlphaType getOutAlphaType() const; sk_sp<SkColorSpace> getOutputColorSpace() const; bool swapWidthHeight() const; // Store/restore a frame if necessary. Returns false on error. bool handleRestorePrevious(const SkImageInfo&, void* pixels, size_t rowBytes); }; } // namespace android
native/graphics/jni/imagedecoder.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -535,3 +535,9 @@ int32_t AImageDecoderFrameInfo_getBlendOp(const AImageDecoderFrameInfo* info) { return ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER; } } void AImageDecoder_setInternallyHandleDisposePrevious(AImageDecoder* decoder, bool handle) { if (decoder) { toDecoder(decoder)->setHandleRestorePrevious(handle); } }
native/graphics/jni/libjnigraphics.map.txt +1 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ LIBJNIGRAPHICS { AImageDecoder_advanceFrame; # introduced=31 AImageDecoder_rewind; # introduced=31 AImageDecoder_getFrameInfo; # introduced = 31 AImageDecoder_setInternallyHandleDisposePrevious; # introduced = 31 AImageDecoderHeaderInfo_getWidth; # introduced=30 AImageDecoderHeaderInfo_getHeight; # introduced=30 AImageDecoderHeaderInfo_getMimeType; # introduced=30 Loading