diff options
-rw-r--r-- | libs/hwui/hwui/ImageDecoder.cpp | 50 | ||||
-rw-r--r-- | libs/hwui/hwui/ImageDecoder.h | 5 | ||||
-rw-r--r-- | libs/hwui/jni/ImageDecoder.cpp | 8 | ||||
-rw-r--r-- | native/graphics/jni/imagedecoder.cpp | 15 |
4 files changed, 56 insertions, 22 deletions
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp index 43cc4f244f71..688913471913 100644 --- a/libs/hwui/hwui/ImageDecoder.cpp +++ b/libs/hwui/hwui/ImageDecoder.cpp @@ -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 { @@ -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()) { @@ -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; } @@ -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; } @@ -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; @@ -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); } diff --git a/libs/hwui/hwui/ImageDecoder.h b/libs/hwui/hwui/ImageDecoder.h index a1b51573db3f..a08e92478fb0 100644 --- a/libs/hwui/hwui/ImageDecoder.h +++ b/libs/hwui/hwui/ImageDecoder.h @@ -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); @@ -68,6 +72,7 @@ private: SkAlphaType getOutAlphaType() const; sk_sp<SkColorSpace> getOutputColorSpace() const; + bool swapWidthHeight() const; }; } // namespace android diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp index da91d46b0738..96e912fd9f26 100644 --- a/libs/hwui/jni/ImageDecoder.cpp +++ b/libs/hwui/jni/ImageDecoder.cpp @@ -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); } diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp index ac4c16a4199b..4aeebe47f1ae 100644 --- a/native/graphics/jni/imagedecoder.cpp +++ b/native/graphics/jni/imagedecoder.cpp @@ -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; } @@ -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) { |