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