Loading libs/hwui/hwui/ImageDecoder.cpp +41 −9 Original line number Diff line number Diff line Loading @@ -40,13 +40,14 @@ sk_sp<SkColorSpace> ImageDecoder::getDefaultColorSpace() const { ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker) : mCodec(std::move(codec)) , mPeeker(std::move(peeker)) , mTargetSize(mCodec->getInfo().dimensions()) , mDecodeSize(mTargetSize) , mDecodeSize(mCodec->codec()->dimensions()) , mOutColorType(mCodec->computeOutputColorType(kN32_SkColorType)) , mUnpremultipliedRequired(false) , mOutColorSpace(getDefaultColorSpace()) , mSampleSize(1) { mTargetSize = swapWidthHeight() ? SkISize { mDecodeSize.height(), mDecodeSize.width() } : mDecodeSize; } SkAlphaType ImageDecoder::getOutAlphaType() const { Loading Loading @@ -77,7 +78,8 @@ bool ImageDecoder::setTargetSize(int width, int height) { } } SkISize targetSize = { width, height }, decodeSize = targetSize; SkISize targetSize = { width, height }; SkISize decodeSize = swapWidthHeight() ? SkISize { height, width } : targetSize; int sampleSize = mCodec->computeSampleSize(&decodeSize); if (decodeSize != targetSize && mUnpremultipliedRequired && !opaque()) { Loading Loading @@ -157,6 +159,22 @@ SkImageInfo ImageDecoder::getOutputInfo() const { return SkImageInfo::Make(size, mOutColorType, getOutAlphaType(), getOutputColorSpace()); } bool ImageDecoder::swapWidthHeight() const { return SkEncodedOriginSwapsWidthHeight(mCodec->codec()->getOrigin()); } int ImageDecoder::width() const { return swapWidthHeight() ? mCodec->codec()->dimensions().height() : mCodec->codec()->dimensions().width(); } int ImageDecoder::height() const { return swapWidthHeight() ? mCodec->codec()->dimensions().width() : mCodec->codec()->dimensions().height(); } bool ImageDecoder::opaque() const { return mCodec->getInfo().alphaType() == kOpaque_SkAlphaType; } Loading @@ -174,7 +192,9 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { // FIXME: Use scanline decoding on only a couple lines to save memory. b/70709380. SkBitmap tmp; const bool scale = mDecodeSize != mTargetSize; if (scale || mCropRect) { const auto origin = mCodec->codec()->getOrigin(); const bool handleOrigin = origin != kDefault_SkEncodedOrigin; if (scale || handleOrigin || mCropRect) { if (!tmp.setInfo(decodeInfo)) { return SkCodec::kInternalError; } Loading @@ -189,7 +209,7 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { options.fSampleSize = mSampleSize; auto result = mCodec->getAndroidPixels(decodeInfo, decodePixels, decodeRowBytes, &options); if (scale || mCropRect) { if (scale || handleOrigin || mCropRect) { SkBitmap scaledBm; if (!scaledBm.installPixels(getOutputInfo(), pixels, rowBytes)) { return SkCodec::kInternalError; Loading @@ -200,15 +220,27 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { paint.setFilterQuality(kLow_SkFilterQuality); // bilinear filtering SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy); SkMatrix outputMatrix; if (mCropRect) { canvas.translate(-mCropRect->fLeft, -mCropRect->fTop); outputMatrix.setTranslate(-mCropRect->fLeft, -mCropRect->fTop); } int targetWidth = mTargetSize.width(); int targetHeight = mTargetSize.height(); if (handleOrigin) { outputMatrix.preConcat(SkEncodedOriginToMatrix(origin, targetWidth, targetHeight)); if (SkEncodedOriginSwapsWidthHeight(origin)) { std::swap(targetWidth, targetHeight); } } if (scale) { float scaleX = (float) mTargetSize.width() / mDecodeSize.width(); float scaleY = (float) mTargetSize.height() / mDecodeSize.height(); canvas.scale(scaleX, scaleY); float scaleX = (float) targetWidth / mDecodeSize.width(); float scaleY = (float) targetHeight / mDecodeSize.height(); outputMatrix.preScale(scaleX, scaleY); } canvas.setMatrix(outputMatrix); canvas.drawBitmap(tmp, 0.0f, 0.0f, &paint); } Loading libs/hwui/hwui/ImageDecoder.h +5 −0 Original line number Diff line number Diff line Loading @@ -49,7 +49,11 @@ public: // The size is the final size after scaling and cropping. SkImageInfo getOutputInfo() const; int width() const; int height() const; bool opaque() const; bool gray() const; SkCodec::Result decode(void* pixels, size_t rowBytes); Loading @@ -68,6 +72,7 @@ private: SkAlphaType getOutAlphaType() const; sk_sp<SkColorSpace> getOutputColorSpace() const; bool swapWidthHeight() const; }; } // namespace android libs/hwui/jni/ImageDecoder.cpp +2 −6 Original line number Diff line number Diff line Loading @@ -135,19 +135,15 @@ static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream, return throw_exception(env, kSourceException, "", jexception, source); } auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec), SkAndroidCodec::ExifOrientationBehavior::kRespect); auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec)); if (!androidCodec.get()) { return throw_exception(env, kSourceMalformedData, "", nullptr, source); } const auto& info = androidCodec->getInfo(); const int width = info.width(); const int height = info.height(); const bool isNinePatch = peeker->mPatch != nullptr; ImageDecoder* decoder = new ImageDecoder(std::move(androidCodec), std::move(peeker)); return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID, reinterpret_cast<jlong>(decoder), width, height, reinterpret_cast<jlong>(decoder), decoder->width(), decoder->height(), animated, isNinePatch); } Loading native/graphics/jni/imagedecoder.cpp +8 −7 Original line number Diff line number Diff line Loading @@ -65,17 +65,18 @@ static int createFromStream(std::unique_ptr<SkStreamRewindable> stream, AImageDe SkCodec::Result result; auto codec = SkCodec::MakeFromStream(std::move(stream), &result, nullptr, SkCodec::SelectionPolicy::kPreferAnimation); auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec), SkAndroidCodec::ExifOrientationBehavior::kRespect); // These may be swapped due to the SkEncodedOrigin, but we're just checking // them to make sure they fit in int32_t. auto dimensions = codec->dimensions(); auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec)); if (!androidCodec) { return ResultToErrorCode(result); } // AImageDecoderHeaderInfo_getWidth/Height return an int32_t. Ensure that // the conversion is safe. const auto& info = androidCodec->getInfo(); if (info.width() > std::numeric_limits<int32_t>::max() || info.height() > std::numeric_limits<int32_t>::max()) { if (dimensions.width() > std::numeric_limits<int32_t>::max() || dimensions.height() > std::numeric_limits<int32_t>::max()) { return ANDROID_IMAGE_DECODER_INVALID_INPUT; } Loading Loading @@ -200,14 +201,14 @@ int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo* info) { if (!info) { return 0; } return toDecoder(info)->mCodec->getInfo().width(); return toDecoder(info)->width(); } int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo* info) { if (!info) { return 0; } return toDecoder(info)->mCodec->getInfo().height(); return toDecoder(info)->height(); } const char* AImageDecoderHeaderInfo_getMimeType(const AImageDecoderHeaderInfo* info) { Loading Loading
libs/hwui/hwui/ImageDecoder.cpp +41 −9 Original line number Diff line number Diff line Loading @@ -40,13 +40,14 @@ sk_sp<SkColorSpace> ImageDecoder::getDefaultColorSpace() const { ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker) : mCodec(std::move(codec)) , mPeeker(std::move(peeker)) , mTargetSize(mCodec->getInfo().dimensions()) , mDecodeSize(mTargetSize) , mDecodeSize(mCodec->codec()->dimensions()) , mOutColorType(mCodec->computeOutputColorType(kN32_SkColorType)) , mUnpremultipliedRequired(false) , mOutColorSpace(getDefaultColorSpace()) , mSampleSize(1) { mTargetSize = swapWidthHeight() ? SkISize { mDecodeSize.height(), mDecodeSize.width() } : mDecodeSize; } SkAlphaType ImageDecoder::getOutAlphaType() const { Loading Loading @@ -77,7 +78,8 @@ bool ImageDecoder::setTargetSize(int width, int height) { } } SkISize targetSize = { width, height }, decodeSize = targetSize; SkISize targetSize = { width, height }; SkISize decodeSize = swapWidthHeight() ? SkISize { height, width } : targetSize; int sampleSize = mCodec->computeSampleSize(&decodeSize); if (decodeSize != targetSize && mUnpremultipliedRequired && !opaque()) { Loading Loading @@ -157,6 +159,22 @@ SkImageInfo ImageDecoder::getOutputInfo() const { return SkImageInfo::Make(size, mOutColorType, getOutAlphaType(), getOutputColorSpace()); } bool ImageDecoder::swapWidthHeight() const { return SkEncodedOriginSwapsWidthHeight(mCodec->codec()->getOrigin()); } int ImageDecoder::width() const { return swapWidthHeight() ? mCodec->codec()->dimensions().height() : mCodec->codec()->dimensions().width(); } int ImageDecoder::height() const { return swapWidthHeight() ? mCodec->codec()->dimensions().width() : mCodec->codec()->dimensions().height(); } bool ImageDecoder::opaque() const { return mCodec->getInfo().alphaType() == kOpaque_SkAlphaType; } Loading @@ -174,7 +192,9 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { // FIXME: Use scanline decoding on only a couple lines to save memory. b/70709380. SkBitmap tmp; const bool scale = mDecodeSize != mTargetSize; if (scale || mCropRect) { const auto origin = mCodec->codec()->getOrigin(); const bool handleOrigin = origin != kDefault_SkEncodedOrigin; if (scale || handleOrigin || mCropRect) { if (!tmp.setInfo(decodeInfo)) { return SkCodec::kInternalError; } Loading @@ -189,7 +209,7 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { options.fSampleSize = mSampleSize; auto result = mCodec->getAndroidPixels(decodeInfo, decodePixels, decodeRowBytes, &options); if (scale || mCropRect) { if (scale || handleOrigin || mCropRect) { SkBitmap scaledBm; if (!scaledBm.installPixels(getOutputInfo(), pixels, rowBytes)) { return SkCodec::kInternalError; Loading @@ -200,15 +220,27 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { paint.setFilterQuality(kLow_SkFilterQuality); // bilinear filtering SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy); SkMatrix outputMatrix; if (mCropRect) { canvas.translate(-mCropRect->fLeft, -mCropRect->fTop); outputMatrix.setTranslate(-mCropRect->fLeft, -mCropRect->fTop); } int targetWidth = mTargetSize.width(); int targetHeight = mTargetSize.height(); if (handleOrigin) { outputMatrix.preConcat(SkEncodedOriginToMatrix(origin, targetWidth, targetHeight)); if (SkEncodedOriginSwapsWidthHeight(origin)) { std::swap(targetWidth, targetHeight); } } if (scale) { float scaleX = (float) mTargetSize.width() / mDecodeSize.width(); float scaleY = (float) mTargetSize.height() / mDecodeSize.height(); canvas.scale(scaleX, scaleY); float scaleX = (float) targetWidth / mDecodeSize.width(); float scaleY = (float) targetHeight / mDecodeSize.height(); outputMatrix.preScale(scaleX, scaleY); } canvas.setMatrix(outputMatrix); canvas.drawBitmap(tmp, 0.0f, 0.0f, &paint); } Loading
libs/hwui/hwui/ImageDecoder.h +5 −0 Original line number Diff line number Diff line Loading @@ -49,7 +49,11 @@ public: // The size is the final size after scaling and cropping. SkImageInfo getOutputInfo() const; int width() const; int height() const; bool opaque() const; bool gray() const; SkCodec::Result decode(void* pixels, size_t rowBytes); Loading @@ -68,6 +72,7 @@ private: SkAlphaType getOutAlphaType() const; sk_sp<SkColorSpace> getOutputColorSpace() const; bool swapWidthHeight() const; }; } // namespace android
libs/hwui/jni/ImageDecoder.cpp +2 −6 Original line number Diff line number Diff line Loading @@ -135,19 +135,15 @@ static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream, return throw_exception(env, kSourceException, "", jexception, source); } auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec), SkAndroidCodec::ExifOrientationBehavior::kRespect); auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec)); if (!androidCodec.get()) { return throw_exception(env, kSourceMalformedData, "", nullptr, source); } const auto& info = androidCodec->getInfo(); const int width = info.width(); const int height = info.height(); const bool isNinePatch = peeker->mPatch != nullptr; ImageDecoder* decoder = new ImageDecoder(std::move(androidCodec), std::move(peeker)); return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID, reinterpret_cast<jlong>(decoder), width, height, reinterpret_cast<jlong>(decoder), decoder->width(), decoder->height(), animated, isNinePatch); } Loading
native/graphics/jni/imagedecoder.cpp +8 −7 Original line number Diff line number Diff line Loading @@ -65,17 +65,18 @@ static int createFromStream(std::unique_ptr<SkStreamRewindable> stream, AImageDe SkCodec::Result result; auto codec = SkCodec::MakeFromStream(std::move(stream), &result, nullptr, SkCodec::SelectionPolicy::kPreferAnimation); auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec), SkAndroidCodec::ExifOrientationBehavior::kRespect); // These may be swapped due to the SkEncodedOrigin, but we're just checking // them to make sure they fit in int32_t. auto dimensions = codec->dimensions(); auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec)); if (!androidCodec) { return ResultToErrorCode(result); } // AImageDecoderHeaderInfo_getWidth/Height return an int32_t. Ensure that // the conversion is safe. const auto& info = androidCodec->getInfo(); if (info.width() > std::numeric_limits<int32_t>::max() || info.height() > std::numeric_limits<int32_t>::max()) { if (dimensions.width() > std::numeric_limits<int32_t>::max() || dimensions.height() > std::numeric_limits<int32_t>::max()) { return ANDROID_IMAGE_DECODER_INVALID_INPUT; } Loading Loading @@ -200,14 +201,14 @@ int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo* info) { if (!info) { return 0; } return toDecoder(info)->mCodec->getInfo().width(); return toDecoder(info)->width(); } int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo* info) { if (!info) { return 0; } return toDecoder(info)->mCodec->getInfo().height(); return toDecoder(info)->height(); } const char* AImageDecoderHeaderInfo_getMimeType(const AImageDecoderHeaderInfo* info) { Loading