xref: /aosp_15_r20/frameworks/base/libs/hwui/hwui/ImageDecoder.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "ImageDecoder.h"
18 
19 #include <Gainmap.h>
20 #include <SkAlphaType.h>
21 #include <SkAndroidCodec.h>
22 #include <SkBitmap.h>
23 #include <SkBlendMode.h>
24 #include <SkCanvas.h>
25 #include <SkCodec.h>
26 #include <SkCodecAnimation.h>
27 #include <SkColorSpace.h>
28 #include <SkColorType.h>
29 #include <SkEncodedOrigin.h>
30 #include <SkGainmapInfo.h>
31 #include <SkImageInfo.h>
32 #include <SkMatrix.h>
33 #include <SkPaint.h>
34 #include <SkPngChunkReader.h>
35 #include <SkRect.h>
36 #include <SkRefCnt.h>
37 #include <SkSamplingOptions.h>
38 #include <SkSize.h>
39 #include <SkStream.h>
40 #include <hwui/Bitmap.h>
41 #include <log/log.h>
42 #include <utils/Trace.h>
43 
44 #include <memory>
45 
46 #include "modules/skcms/src/skcms_public.h"
47 
48 using namespace android;
49 
getDefaultColorSpace() const50 sk_sp<SkColorSpace> ImageDecoder::getDefaultColorSpace() const {
51     const skcms_ICCProfile* encodedProfile = mCodec->getICCProfile();
52     if (encodedProfile) {
53         if (encodedProfile->has_CICP) {
54             return mCodec->computeOutputColorSpace(kN32_SkColorType);
55         }
56         // If the profile maps directly to an SkColorSpace, that SkColorSpace
57         // will be returned. Otherwise, nullptr will be returned. In either
58         // case, using this SkColorSpace results in doing no color correction.
59         return SkColorSpace::Make(*encodedProfile);
60     }
61 
62     // The image has no embedded color profile, and should be treated as SRGB.
63     return SkColorSpace::MakeSRGB();
64 }
65 
ImageDecoder(std::unique_ptr<SkAndroidCodec> codec,sk_sp<SkPngChunkReader> peeker,SkCodec::ZeroInitialized zeroInit)66 ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker,
67                            SkCodec::ZeroInitialized zeroInit)
68     : mCodec(std::move(codec))
69     , mPeeker(std::move(peeker))
70     , mDecodeSize(mCodec->codec()->dimensions())
71     , mOutColorType(mCodec->computeOutputColorType(kN32_SkColorType))
72     , mUnpremultipliedRequired(false)
73     , mOutColorSpace(getDefaultColorSpace())
74     , mHandleRestorePrevious(true)
75 {
76     mTargetSize = swapWidthHeight() ? SkISize { mDecodeSize.height(), mDecodeSize.width() }
77                                     : mDecodeSize;
78     this->rewind();
79     mOptions.fZeroInitialized = zeroInit;
80 }
81 
82 ImageDecoder::~ImageDecoder() = default;
83 
getOutAlphaType() const84 SkAlphaType ImageDecoder::getOutAlphaType() const {
85     return opaque() ? kOpaque_SkAlphaType
86                     : mUnpremultipliedRequired ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
87 }
88 
swapped(const SkISize & size)89 static SkISize swapped(const SkISize& size) {
90     return SkISize { size.height(), size.width() };
91 }
92 
requires_matrix_scaling(bool swapWidthHeight,const SkISize & decodeSize,const SkISize & targetSize)93 static bool requires_matrix_scaling(bool swapWidthHeight, const SkISize& decodeSize,
94                                     const SkISize& targetSize) {
95     return (swapWidthHeight && decodeSize != swapped(targetSize))
96           || (!swapWidthHeight && decodeSize != targetSize);
97 }
98 
getSampledDimensions(int sampleSize) const99 SkISize ImageDecoder::getSampledDimensions(int sampleSize) const {
100     auto size = mCodec->getSampledDimensions(sampleSize);
101     return swapWidthHeight() ? swapped(size) : size;
102 }
103 
setTargetSize(int width,int height)104 bool ImageDecoder::setTargetSize(int width, int height) {
105     if (width <= 0 || height <= 0) {
106         return false;
107     }
108 
109     auto info = SkImageInfo::Make(width, height, mOutColorType, getOutAlphaType());
110     size_t rowBytes = info.minRowBytes();
111     if (rowBytes == 0) {
112         // This would have overflowed.
113         return false;
114     }
115 
116     size_t pixelMemorySize;
117     if (!Bitmap::computeAllocationSize(rowBytes, height, &pixelMemorySize)) {
118         return false;
119     }
120 
121     if (mCropRect) {
122         if (mCropRect->right() > width || mCropRect->bottom() > height) {
123             return false;
124         }
125     }
126 
127     const bool swap = swapWidthHeight();
128     const SkISize targetSize = { width, height };
129     SkISize decodeSize = swap ? SkISize { height, width } : targetSize;
130     int sampleSize = mCodec->computeSampleSize(&decodeSize);
131 
132     if (mUnpremultipliedRequired && !opaque()) {
133         // Allow using a matrix to handle orientation, but not scaling.
134         if (requires_matrix_scaling(swap, decodeSize, targetSize)) {
135             return false;
136         }
137     }
138 
139     mTargetSize = targetSize;
140     mDecodeSize = decodeSize;
141     mOptions.fSampleSize = sampleSize;
142     return true;
143 }
144 
setCropRect(const SkIRect * crop)145 bool ImageDecoder::setCropRect(const SkIRect* crop) {
146     if (!crop) {
147         mCropRect.reset();
148         return true;
149     }
150 
151     if (crop->left() >= crop->right() || crop->top() >= crop->bottom()) {
152         return false;
153     }
154 
155     const auto& size = mTargetSize;
156     if (crop->left() < 0 || crop->top() < 0
157             || crop->right() > size.width() || crop->bottom() > size.height()) {
158       return false;
159     }
160 
161     mCropRect.emplace(*crop);
162     return true;
163 }
164 
setOutColorType(SkColorType colorType)165 bool ImageDecoder::setOutColorType(SkColorType colorType) {
166     switch (colorType) {
167         case kRGB_565_SkColorType:
168             if (!opaque()) {
169                 return false;
170             }
171             break;
172         case kGray_8_SkColorType:
173             if (!gray()) {
174                 return false;
175             }
176             break;
177         case kN32_SkColorType:
178             break;
179         case kRGBA_F16_SkColorType:
180             break;
181         case kRGBA_1010102_SkColorType:
182             break;
183         default:
184             return false;
185     }
186 
187     mOutColorType = colorType;
188     return true;
189 }
190 
setUnpremultipliedRequired(bool required)191 bool ImageDecoder::setUnpremultipliedRequired(bool required) {
192     if (required && !opaque()) {
193         if (requires_matrix_scaling(swapWidthHeight(), mDecodeSize, mTargetSize)) {
194             return false;
195         }
196     }
197     mUnpremultipliedRequired = required;
198     return true;
199 }
200 
setOutColorSpace(sk_sp<SkColorSpace> colorSpace)201 void ImageDecoder::setOutColorSpace(sk_sp<SkColorSpace> colorSpace) {
202     mOutColorSpace = std::move(colorSpace);
203 }
204 
getOutputColorSpace() const205 sk_sp<SkColorSpace> ImageDecoder::getOutputColorSpace() const {
206     // kGray_8 is used for ALPHA_8, which ignores the color space.
207     return mOutColorType == kGray_8_SkColorType ? nullptr : mOutColorSpace;
208 }
209 
210 
getOutputInfo() const211 SkImageInfo ImageDecoder::getOutputInfo() const {
212     SkISize size = mCropRect ? mCropRect->size() : mTargetSize;
213     return SkImageInfo::Make(size, mOutColorType, getOutAlphaType(), getOutputColorSpace());
214 }
215 
swapWidthHeight() const216 bool ImageDecoder::swapWidthHeight() const {
217     return SkEncodedOriginSwapsWidthHeight(getOrigin());
218 }
219 
width() const220 int ImageDecoder::width() const {
221     return swapWidthHeight()
222             ? mCodec->codec()->dimensions().height()
223             : mCodec->codec()->dimensions().width();
224 }
225 
height() const226 int ImageDecoder::height() const {
227     return swapWidthHeight()
228             ? mCodec->codec()->dimensions().width()
229             : mCodec->codec()->dimensions().height();
230 }
231 
opaque() const232 bool ImageDecoder::opaque() const {
233     return mCurrentFrameIsOpaque;
234 }
235 
gray() const236 bool ImageDecoder::gray() const {
237     return mCodec->getInfo().colorType() == kGray_8_SkColorType;
238 }
239 
isAnimated()240 bool ImageDecoder::isAnimated() {
241     return mCodec->codec()->getFrameCount() > 1;
242 }
243 
currentFrame() const244 int ImageDecoder::currentFrame() const {
245     return mOptions.fFrameIndex;
246 }
247 
rewind()248 bool ImageDecoder::rewind() {
249     mOptions.fFrameIndex = 0;
250     mOptions.fPriorFrame = SkCodec::kNoFrame;
251     mCurrentFrameIsIndependent = true;
252     mCurrentFrameIsOpaque = mCodec->getInfo().isOpaque();
253     mRestoreState = RestoreState::kDoNothing;
254     mRestoreFrame = nullptr;
255 
256     // TODO: Rewind the input now instead of in the next call to decode, and
257     // plumb through whether rewind succeeded.
258     return true;
259 }
260 
setHandleRestorePrevious(bool handle)261 void ImageDecoder::setHandleRestorePrevious(bool handle) {
262     mHandleRestorePrevious = handle;
263     if (!handle) {
264         mRestoreFrame = nullptr;
265     }
266 }
267 
advanceFrame()268 bool ImageDecoder::advanceFrame() {
269     const int frameIndex = ++mOptions.fFrameIndex;
270     const int frameCount = mCodec->codec()->getFrameCount();
271     if (frameIndex >= frameCount) {
272         // Prevent overflow from repeated calls to advanceFrame.
273         mOptions.fFrameIndex = frameCount;
274         return false;
275     }
276 
277     SkCodec::FrameInfo frameInfo;
278     if (!mCodec->codec()->getFrameInfo(frameIndex, &frameInfo)
279             || !frameInfo.fFullyReceived) {
280         // Mark the decoder as finished, requiring a rewind.
281         mOptions.fFrameIndex = frameCount;
282         return false;
283     }
284 
285     mCurrentFrameIsIndependent = frameInfo.fRequiredFrame == SkCodec::kNoFrame;
286     mCurrentFrameIsOpaque = frameInfo.fAlphaType == kOpaque_SkAlphaType;
287 
288     if (frameInfo.fDisposalMethod == SkCodecAnimation::DisposalMethod::kRestorePrevious) {
289         switch (mRestoreState) {
290             case RestoreState::kDoNothing:
291             case RestoreState::kNeedsRestore:
292                 mRestoreState = RestoreState::kFirstRPFrame;
293                 mOptions.fPriorFrame = frameIndex - 1;
294                 break;
295             case RestoreState::kFirstRPFrame:
296                 mRestoreState = RestoreState::kRPFrame;
297                 break;
298             case RestoreState::kRPFrame:
299                 // Unchanged.
300                 break;
301         }
302     } else { // New frame is not restore previous
303         switch (mRestoreState) {
304             case RestoreState::kFirstRPFrame:
305             case RestoreState::kRPFrame:
306                 mRestoreState = RestoreState::kNeedsRestore;
307                 break;
308             case RestoreState::kNeedsRestore:
309                 mRestoreState = RestoreState::kDoNothing;
310                 mRestoreFrame = nullptr;
311                 [[fallthrough]];
312             case RestoreState::kDoNothing:
313                 mOptions.fPriorFrame = frameIndex - 1;
314                 break;
315         }
316     }
317 
318     return true;
319 }
320 
getCurrentFrameInfo()321 SkCodec::FrameInfo ImageDecoder::getCurrentFrameInfo() {
322     LOG_ALWAYS_FATAL_IF(finished());
323 
324     auto dims = mCodec->codec()->dimensions();
325     SkCodec::FrameInfo info;
326     if (!mCodec->codec()->getFrameInfo(mOptions.fFrameIndex, &info)) {
327         // SkCodec may return false for a non-animated image. Provide defaults.
328         info.fRequiredFrame = SkCodec::kNoFrame;
329         info.fDuration = 0;
330         info.fFullyReceived = true;
331         info.fAlphaType = mCodec->codec()->getInfo().alphaType();
332         info.fHasAlphaWithinBounds = info.fAlphaType != kOpaque_SkAlphaType;
333         info.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
334         info.fBlend = SkCodecAnimation::Blend::kSrc;
335         info.fFrameRect = SkIRect::MakeSize(dims);
336     }
337 
338     if (auto origin = getOrigin(); origin != kDefault_SkEncodedOrigin) {
339         if (SkEncodedOriginSwapsWidthHeight(origin)) {
340             dims = swapped(dims);
341         }
342         auto matrix = SkEncodedOriginToMatrix(origin, dims.width(), dims.height());
343         auto rect = SkRect::Make(info.fFrameRect);
344         LOG_ALWAYS_FATAL_IF(!matrix.mapRect(&rect));
345         rect.roundIn(&info.fFrameRect);
346     }
347     return info;
348 }
349 
finished() const350 bool ImageDecoder::finished() const {
351     return mOptions.fFrameIndex >= mCodec->codec()->getFrameCount();
352 }
353 
handleRestorePrevious(const SkImageInfo & outputInfo,void * pixels,size_t rowBytes)354 bool ImageDecoder::handleRestorePrevious(const SkImageInfo& outputInfo, void* pixels,
355                                          size_t rowBytes) {
356     if (!mHandleRestorePrevious) {
357         return true;
358     }
359 
360     switch (mRestoreState) {
361         case RestoreState::kFirstRPFrame:{
362             // This frame is marked kRestorePrevious. The prior frame should be in
363             // |pixels|, and it is what we'll restore after each consecutive
364             // kRestorePrevious frame. Cache it now.
365             if (!(mRestoreFrame = Bitmap::allocateHeapBitmap(outputInfo))) {
366                 return false;
367             }
368 
369             const uint8_t* srcRow = static_cast<uint8_t*>(pixels);
370                   uint8_t* dstRow = static_cast<uint8_t*>(mRestoreFrame->pixels());
371             for (int y = 0; y < outputInfo.height(); y++) {
372                 memcpy(dstRow, srcRow, outputInfo.minRowBytes());
373                 srcRow += rowBytes;
374                 dstRow += mRestoreFrame->rowBytes();
375             }
376             break;
377         }
378         case RestoreState::kRPFrame:
379         case RestoreState::kNeedsRestore:
380             // Restore the cached frame. It's possible that the client skipped decoding a frame, so
381             // we never cached it.
382             if (mRestoreFrame) {
383                 const uint8_t* srcRow = static_cast<uint8_t*>(mRestoreFrame->pixels());
384                       uint8_t* dstRow = static_cast<uint8_t*>(pixels);
385                 for (int y = 0; y < outputInfo.height(); y++) {
386                     memcpy(dstRow, srcRow, outputInfo.minRowBytes());
387                     srcRow += mRestoreFrame->rowBytes();
388                     dstRow += rowBytes;
389                 }
390             }
391             break;
392         case RestoreState::kDoNothing:
393             break;
394     }
395     return true;
396 }
397 
decode(void * pixels,size_t rowBytes)398 SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
399     // This was checked inside setTargetSize, but it's possible the first frame
400     // was opaque, so that method succeeded, but after calling advanceFrame, the
401     // current frame is not opaque.
402     if (mUnpremultipliedRequired && !opaque()) {
403         // Allow using a matrix to handle orientation, but not scaling.
404         if (requires_matrix_scaling(swapWidthHeight(), mDecodeSize, mTargetSize)) {
405             return SkCodec::kInvalidScale;
406         }
407     }
408 
409     const auto outputInfo = getOutputInfo();
410     if (!handleRestorePrevious(outputInfo, pixels, rowBytes)) {
411         return SkCodec::kInternalError;
412     }
413 
414     void* decodePixels = pixels;
415     size_t decodeRowBytes = rowBytes;
416     const auto decodeInfo = SkImageInfo::Make(mDecodeSize, mOutColorType, getOutAlphaType(),
417                                               getOutputColorSpace());
418     // Used if we need a temporary before scaling or subsetting.
419     // FIXME: Use scanline decoding on only a couple lines to save memory. b/70709380.
420     SkBitmap tmp;
421     const bool scale = mDecodeSize != mTargetSize;
422     const auto origin = getOrigin();
423     const bool handleOrigin = origin != kDefault_SkEncodedOrigin;
424     SkMatrix outputMatrix;
425     if (scale || handleOrigin || mCropRect) {
426         if (mCropRect) {
427             outputMatrix.setTranslate(-mCropRect->fLeft, -mCropRect->fTop);
428         }
429 
430         int targetWidth  = mTargetSize.width();
431         int targetHeight = mTargetSize.height();
432         if (handleOrigin) {
433             outputMatrix.preConcat(SkEncodedOriginToMatrix(origin, targetWidth, targetHeight));
434             if (SkEncodedOriginSwapsWidthHeight(origin)) {
435                 std::swap(targetWidth, targetHeight);
436             }
437         }
438         if (scale) {
439             float scaleX = (float) targetWidth  / mDecodeSize.width();
440             float scaleY = (float) targetHeight / mDecodeSize.height();
441             outputMatrix.preScale(scaleX, scaleY);
442         }
443         // It's possible that this portion *does* have alpha, even if the
444         // composed frame does not. In that case, the SkBitmap needs to have
445         // alpha so it blends properly.
446         if (!tmp.setInfo(decodeInfo.makeAlphaType(mUnpremultipliedRequired ? kUnpremul_SkAlphaType
447                                                                            : kPremul_SkAlphaType)))
448         {
449             return SkCodec::kInternalError;
450         }
451         if (!Bitmap::allocateHeapBitmap(&tmp)) {
452             return SkCodec::kInternalError;
453         }
454         decodePixels = tmp.getPixels();
455         decodeRowBytes = tmp.rowBytes();
456 
457         if (!mCurrentFrameIsIndependent) {
458             SkMatrix inverse;
459             if (outputMatrix.invert(&inverse)) {
460                 SkCanvas canvas(tmp, SkCanvas::ColorBehavior::kLegacy);
461                 canvas.setMatrix(inverse);
462                 SkBitmap priorFrame;
463                 priorFrame.installPixels(outputInfo, pixels, rowBytes);
464                 priorFrame.setImmutable(); // Don't want asImage() to force a copy
465                 canvas.drawImage(priorFrame.asImage(), 0, 0,
466                                  SkSamplingOptions(SkFilterMode::kLinear));
467             } else {
468                 ALOGE("Failed to invert matrix!");
469             }
470         }
471 
472         // Even if the client did not provide zero initialized memory, the
473         // memory we decode into is.
474         mOptions.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
475     }
476 
477     ATRACE_BEGIN("getAndroidPixels");
478     auto result = mCodec->getAndroidPixels(decodeInfo, decodePixels, decodeRowBytes, &mOptions);
479     ATRACE_END();
480 
481     // The next call to decode() may not provide zero initialized memory.
482     mOptions.fZeroInitialized = SkCodec::kNo_ZeroInitialized;
483 
484     if (scale || handleOrigin || mCropRect) {
485         ATRACE_NAME("Handling scale/origin/crop");
486         SkBitmap scaledBm;
487         if (!scaledBm.installPixels(outputInfo, pixels, rowBytes)) {
488             return SkCodec::kInternalError;
489         }
490 
491         SkPaint paint;
492         paint.setBlendMode(SkBlendMode::kSrc);
493 
494         SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy);
495         canvas.setMatrix(outputMatrix);
496         tmp.setImmutable(); // Don't want asImage() to force copy
497         canvas.drawImage(tmp.asImage(), 0, 0, SkSamplingOptions(SkFilterMode::kLinear), &paint);
498     }
499 
500     return result;
501 }
502 
extractGainmap(Bitmap * destination,bool isShared)503 SkCodec::Result ImageDecoder::extractGainmap(Bitmap* destination, bool isShared) {
504     ATRACE_CALL();
505     SkGainmapInfo gainmapInfo;
506     std::unique_ptr<SkAndroidCodec> gainmapCodec;
507     {
508         ATRACE_NAME("getGainmapAndroidCodec");
509         if (!mCodec->getGainmapAndroidCodec(&gainmapInfo, &gainmapCodec)) {
510             return SkCodec::kSuccess;
511         }
512     }
513     ImageDecoder decoder{std::move(gainmapCodec)};
514     // Gainmap inherits the origin of the containing image
515     decoder.mOverrideOrigin.emplace(getOrigin());
516     // Update mDecodeSize / mTargetSize for the overridden origin
517     decoder.setTargetSize(decoder.width(), decoder.height());
518     if (decoder.gray()) {
519         decoder.setOutColorType(kGray_8_SkColorType);
520     }
521 
522     const bool isScaled = width() != mTargetSize.width() || height() != mTargetSize.height();
523 
524     if (isScaled) {
525         float scaleX = (float)mTargetSize.width() / width();
526         float scaleY = (float)mTargetSize.height() / height();
527         decoder.setTargetSize(decoder.width() * scaleX, decoder.height() * scaleY);
528     }
529 
530     if (mCropRect) {
531         float sX = decoder.mTargetSize.width() / (float)mTargetSize.width();
532         float sY = decoder.mTargetSize.height() / (float)mTargetSize.height();
533         SkIRect crop = *mCropRect;
534         // TODO: Tweak rounding?
535         crop.fLeft *= sX;
536         crop.fRight *= sX;
537         crop.fTop *= sY;
538         crop.fBottom *= sY;
539         decoder.setCropRect(&crop);
540     }
541 
542     SkImageInfo bitmapInfo = decoder.getOutputInfo();
543     if (bitmapInfo.colorType() == kGray_8_SkColorType) {
544         bitmapInfo = bitmapInfo.makeColorType(kAlpha_8_SkColorType);
545     }
546 
547     SkBitmap bm;
548     if (!bm.setInfo(bitmapInfo)) {
549         ALOGE("Failed to setInfo properly");
550         return SkCodec::kInternalError;
551     }
552 
553     sk_sp<Bitmap> nativeBitmap;
554     if (isShared) {
555         nativeBitmap = Bitmap::allocateAshmemBitmap(&bm);
556     } else {
557         nativeBitmap = Bitmap::allocateHeapBitmap(&bm);
558     }
559     if (!nativeBitmap) {
560         ALOGE("OOM allocating Bitmap with dimensions %i x %i", bitmapInfo.width(),
561               bitmapInfo.height());
562         return SkCodec::kInternalError;
563     }
564 
565     SkCodec::Result result = decoder.decode(bm.getPixels(), bm.rowBytes());
566     bm.setImmutable();
567 
568     if (result == SkCodec::kSuccess) {
569         auto gainmap = sp<uirenderer::Gainmap>::make();
570         gainmap->info = gainmapInfo;
571         gainmap->bitmap = std::move(nativeBitmap);
572         destination->setGainmap(std::move(gainmap));
573     }
574 
575     return result;
576 }
577