xref: /aosp_15_r20/external/skia/src/codec/SkCodec.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/codec/SkCodec.h"
9 
10 #include "include/codec/SkCodecAnimation.h"
11 #include "include/codec/SkPixmapUtils.h"
12 #include "include/core/SkAlphaType.h"
13 #include "include/core/SkBitmap.h"
14 #include "include/core/SkColorPriv.h"
15 #include "include/core/SkColorSpace.h"
16 #include "include/core/SkColorType.h"
17 #include "include/core/SkData.h"
18 #include "include/core/SkImage.h" // IWYU pragma: keep
19 #include "include/core/SkImageInfo.h"
20 #include "include/core/SkMatrix.h"
21 #include "include/core/SkStream.h"
22 #include "include/private/base/SkTemplates.h"
23 #include "modules/skcms/skcms.h"
24 #include "src/base/SkNoDestructor.h"
25 #include "src/codec/SkCodecPriv.h"
26 #include "src/codec/SkFrameHolder.h"
27 #include "src/codec/SkPixmapUtilsPriv.h"
28 #include "src/codec/SkSampler.h"
29 
30 #include <string>
31 #include <string_view>
32 #include <utility>
33 
34 #if !defined(SK_DISABLE_LEGACY_INIT_DECODERS)
35 #include "include/private/base/SkOnce.h"
36 
37 #if defined(SK_CODEC_DECODES_AVIF)
38 #include "include/codec/SkAvifDecoder.h"
39 #endif
40 
41 #if defined(SK_CODEC_DECODES_BMP)
42 #include "include/codec/SkBmpDecoder.h"
43 #endif
44 
45 #if defined(SK_CODEC_DECODES_GIF) || defined(SK_HAS_WUFFS_LIBRARY)
46 #include "include/codec/SkGifDecoder.h"
47 #endif
48 
49 #if defined(SK_HAS_HEIF_LIBRARY)
50 #include "include/android/SkHeifDecoder.h"
51 #endif
52 
53 #if defined(SK_CODEC_DECODES_ICO)
54 #include "include/codec/SkIcoDecoder.h"
55 #endif
56 
57 #if defined(SK_CODEC_DECODES_JPEG)
58 #include "include/codec/SkJpegDecoder.h"
59 #endif
60 
61 #if defined(SK_CODEC_DECODES_JPEGXL)
62 #include "include/codec/SkJpegxlDecoder.h"
63 #endif
64 
65 #if defined(SK_CODEC_DECODES_PNG)
66 #include "include/codec/SkPngDecoder.h"
67 #endif
68 
69 #if defined(SK_CODEC_DECODES_RAW)
70 #include "include/codec/SkRawDecoder.h"
71 #endif
72 
73 #if defined(SK_CODEC_DECODES_WBMP)
74 #include "include/codec/SkWbmpDecoder.h"
75 #endif
76 
77 #if defined(SK_CODEC_DECODES_WEBP)
78 #include "include/codec/SkWebpDecoder.h"
79 #endif
80 #endif // !defined(SK_DISABLE_LEGACY_INIT_DECODERS)
81 
82 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
83 #include "cutils/properties.h"
84 #endif // defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
85 
86 namespace SkCodecs {
87 // A static variable inside a function avoids a static initializer.
88 // https://chromium.googlesource.com/chromium/src/+/HEAD/docs/static_initializers.md#removing-static-initializers
get_decoders_for_editing()89 static std::vector<Decoder>* get_decoders_for_editing() {
90     static SkNoDestructor<std::vector<Decoder>> decoders;
91 #if !defined(SK_DISABLE_LEGACY_INIT_DECODERS)
92     static SkOnce once;
93     once([] {
94         if (decoders->empty()) {
95 #if defined(SK_CODEC_DECODES_PNG)
96             decoders->push_back(SkPngDecoder::Decoder());
97 #endif
98 #if defined(SK_CODEC_DECODES_JPEG)
99             decoders->push_back(SkJpegDecoder::Decoder());
100 #endif
101 #if defined(SK_CODEC_DECODES_WEBP)
102             decoders->push_back(SkWebpDecoder::Decoder());
103 #endif
104 #if defined(SK_CODEC_DECODES_GIF) || defined(SK_HAS_WUFFS_LIBRARY)
105             decoders->push_back(SkGifDecoder::Decoder());
106 #endif
107 #if defined(SK_CODEC_DECODES_ICO)
108             decoders->push_back(SkIcoDecoder::Decoder());
109 #endif
110 #if defined(SK_CODEC_DECODES_BMP)
111             decoders->push_back(SkBmpDecoder::Decoder());
112 #endif
113 #if defined(SK_CODEC_DECODES_WBMP)
114             decoders->push_back(SkWbmpDecoder::Decoder());
115 #endif
116 #if defined(SK_CODEC_DECODES_AVIF)
117 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
118             // Register CrabbyAvif based SkAvifDecoder on the Android framework
119             // if it is allowed. Otherwise Android framework will use
120             // SkHeifDecoder for decoding AVIF.
121             // TODO: Codec registration for the Android framework has to be
122             // moved outside of skia and this logic has to be moved there.
123             if (property_get_int32("media.avif.crabbyavif", 0) != 0) {
124                 decoders->push_back(SkAvifDecoder::CrabbyAvif::Decoder());
125             }
126 #else
127             decoders->push_back(SkAvifDecoder::LibAvif::Decoder());
128 #endif
129 #endif
130 #if defined(SK_CODEC_DECODES_JPEGXL)
131             decoders->push_back(SkJpegxlDecoder::Decoder());
132 #endif
133 #if defined(SK_HAS_HEIF_LIBRARY)
134             decoders->push_back(SkHeifDecoder::Decoder());
135 #endif
136 #if defined(SK_CODEC_DECODES_RAW)
137             decoders->push_back(SkRawDecoder::Decoder());
138 #endif
139         }
140     });
141 #endif // !defined(SK_DISABLE_LEGACY_INIT_DECODERS)
142     return decoders.get();
143 }
144 
get_decoders()145 const std::vector<Decoder>& get_decoders() {
146     auto decoders = get_decoders_for_editing();
147     return *decoders;
148 }
149 
Register(Decoder d)150 void Register(Decoder d) {
151     auto decoders = get_decoders_for_editing();
152     for (size_t i = 0; i < decoders->size(); i++) {
153         if ((*decoders)[i].id == d.id) {
154             (*decoders)[i] = d;
155             return;
156         }
157     }
158     decoders->push_back(d);
159 }
160 
HasDecoder(std::string_view id)161 bool HasDecoder(std::string_view id) {
162     for (const SkCodecs::Decoder& decoder : get_decoders()) {
163         if (decoder.id == id) {
164             return true;
165         }
166     }
167     return false;
168 }
169 
170 }  // namespace SkCodecs
171 
MakeFromStream(std::unique_ptr<SkStream> stream,Result * outResult,SkPngChunkReader * chunkReader,SelectionPolicy selectionPolicy)172 std::unique_ptr<SkCodec> SkCodec::MakeFromStream(
173         std::unique_ptr<SkStream> stream, Result* outResult,
174         SkPngChunkReader* chunkReader, SelectionPolicy selectionPolicy) {
175     return MakeFromStream(std::move(stream), SkCodecs::get_decoders(), outResult,
176                           chunkReader, selectionPolicy);
177 }
MakeFromStream(std::unique_ptr<SkStream> stream,SkSpan<const SkCodecs::Decoder> decoders,Result * outResult,SkPngChunkReader * chunkReader,SelectionPolicy selectionPolicy)178 std::unique_ptr<SkCodec> SkCodec::MakeFromStream(
179         std::unique_ptr<SkStream> stream, SkSpan<const SkCodecs::Decoder> decoders,
180         Result* outResult, SkPngChunkReader* chunkReader, SelectionPolicy selectionPolicy) {
181     Result resultStorage;
182     if (!outResult) {
183         outResult = &resultStorage;
184     }
185 
186     if (!stream) {
187         *outResult = kInvalidInput;
188         return nullptr;
189     }
190 
191     if (selectionPolicy != SelectionPolicy::kPreferStillImage
192             && selectionPolicy != SelectionPolicy::kPreferAnimation) {
193         *outResult = kInvalidParameters;
194         return nullptr;
195     }
196 
197     constexpr size_t bytesToRead = MinBufferedBytesNeeded();
198 
199     char buffer[bytesToRead];
200     size_t bytesRead = stream->peek(buffer, bytesToRead);
201 
202     // It is also possible to have a complete image less than bytesToRead bytes
203     // (e.g. a 1 x 1 wbmp), meaning peek() would return less than bytesToRead.
204     // Assume that if bytesRead < bytesToRead, but > 0, the stream is shorter
205     // than bytesToRead, so pass that directly to the decoder.
206     // It also is possible the stream uses too small a buffer for peeking, but
207     // we trust the caller to use a large enough buffer.
208 
209     if (0 == bytesRead) {
210         // TODO: After implementing peek in CreateJavaOutputStreamAdaptor.cpp, this
211         // printf could be useful to notice failures.
212         // SkCodecPrintf("Encoded image data failed to peek!\n");
213 
214         // It is possible the stream does not support peeking, but does support
215         // rewinding.
216         // Attempt to read() and pass the actual amount read to the decoder.
217         bytesRead = stream->read(buffer, bytesToRead);
218         if (!stream->rewind()) {
219             SkCodecPrintf("Encoded image data could not peek or rewind to determine format!\n");
220             *outResult = kCouldNotRewind;
221             return nullptr;
222         }
223     }
224 
225     SkCodecs::MakeFromStreamCallback rawFallback = nullptr;
226     for (const SkCodecs::Decoder& proc : decoders) {
227         if (proc.isFormat(buffer, bytesRead)) {
228             // Some formats are special, since we want to be able to provide an extra parameter.
229             if (proc.id == "png") {
230                 return proc.makeFromStream(std::move(stream), outResult, chunkReader);
231             } else if (proc.id == "heif" || proc.id == "gif") {
232                 return proc.makeFromStream(std::move(stream), outResult, &selectionPolicy);
233             } else if (proc.id == "raw") {
234                 rawFallback = proc.makeFromStream;
235                 continue;
236             }
237             return proc.makeFromStream(std::move(stream), outResult, nullptr);
238         }
239     }
240     if (rawFallback != nullptr) {
241         // Fallback to raw.
242         return rawFallback(std::move(stream), outResult, nullptr);
243     }
244 
245     if (bytesRead < bytesToRead) {
246         *outResult = kIncompleteInput;
247     } else {
248         *outResult = kUnimplemented;
249     }
250     return nullptr;
251 }
252 
MakeFromData(sk_sp<SkData> data,SkPngChunkReader * reader)253 std::unique_ptr<SkCodec> SkCodec::MakeFromData(sk_sp<SkData> data, SkPngChunkReader* reader) {
254     return MakeFromData(std::move(data), SkCodecs::get_decoders(), reader);
255 }
MakeFromData(sk_sp<SkData> data,SkSpan<const SkCodecs::Decoder> decoders,SkPngChunkReader * reader)256 std::unique_ptr<SkCodec> SkCodec::MakeFromData(sk_sp<SkData> data,
257                                                SkSpan<const SkCodecs::Decoder> decoders,
258                                                SkPngChunkReader* reader) {
259     if (!data) {
260         return nullptr;
261     }
262     return MakeFromStream(SkMemoryStream::Make(std::move(data)), decoders, nullptr, reader);
263 }
264 
SkCodec(SkEncodedInfo && info,XformFormat srcFormat,std::unique_ptr<SkStream> stream,SkEncodedOrigin origin)265 SkCodec::SkCodec(SkEncodedInfo&& info,
266                  XformFormat srcFormat,
267                  std::unique_ptr<SkStream> stream,
268                  SkEncodedOrigin origin)
269         : fEncodedInfo(std::move(info))
270         , fSrcXformFormat(srcFormat)
271         , fStream(std::move(stream))
272         , fOrigin(origin)
273         , fDstInfo()
274         , fOptions() {}
275 
~SkCodec()276 SkCodec::~SkCodec() {}
277 
setSrcXformFormat(XformFormat pixelFormat)278 void SkCodec::setSrcXformFormat(XformFormat pixelFormat) {
279     fSrcXformFormat = pixelFormat;
280 }
281 
queryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes & supportedDataTypes,SkYUVAPixmapInfo * yuvaPixmapInfo) const282 bool SkCodec::queryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes,
283                             SkYUVAPixmapInfo* yuvaPixmapInfo) const {
284     if (!yuvaPixmapInfo) {
285         return false;
286     }
287     return this->onQueryYUVAInfo(supportedDataTypes, yuvaPixmapInfo) &&
288            yuvaPixmapInfo->isSupported(supportedDataTypes);
289 }
290 
getYUVAPlanes(const SkYUVAPixmaps & yuvaPixmaps)291 SkCodec::Result SkCodec::getYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) {
292     if (!yuvaPixmaps.isValid()) {
293         return kInvalidInput;
294     }
295     if (!this->rewindIfNeeded()) {
296         return kCouldNotRewind;
297     }
298     return this->onGetYUVAPlanes(yuvaPixmaps);
299 }
300 
conversionSupported(const SkImageInfo & dst,bool srcIsOpaque,bool needsColorXform)301 bool SkCodec::conversionSupported(const SkImageInfo& dst, bool srcIsOpaque, bool needsColorXform) {
302     if (!valid_alpha(dst.alphaType(), srcIsOpaque)) {
303         return false;
304     }
305 
306     switch (dst.colorType()) {
307         case kRGBA_8888_SkColorType:
308         case kBGRA_8888_SkColorType:
309         case kRGBA_F16_SkColorType:
310         case kBGRA_10101010_XR_SkColorType:
311             return true;
312         case kBGR_101010x_XR_SkColorType:
313         case kRGB_565_SkColorType:
314             return srcIsOpaque;
315         case kGray_8_SkColorType:
316             return SkEncodedInfo::kGray_Color == fEncodedInfo.color() && srcIsOpaque;
317         case kAlpha_8_SkColorType:
318             // conceptually we can convert anything into alpha_8, but we haven't actually coded
319             // all of those other conversions yet.
320             return SkEncodedInfo::kXAlpha_Color == fEncodedInfo.color();
321         default:
322             return false;
323     }
324 }
325 
rewindIfNeeded()326 bool SkCodec::rewindIfNeeded() {
327     // Store the value of fNeedsRewind so we can update it. Next read will
328     // require a rewind.
329     const bool needsRewind = fNeedsRewind;
330     fNeedsRewind = true;
331     if (!needsRewind) {
332         return true;
333     }
334 
335     // startScanlineDecode will need to be called before decoding scanlines.
336     fCurrScanline = -1;
337     // startIncrementalDecode will need to be called before incrementalDecode.
338     fStartedIncrementalDecode = false;
339 
340     // Some codecs do not have a stream.  They may hold onto their own data or another codec.
341     // They must handle rewinding themselves.
342     if (fStream && !fStream->rewind()) {
343         return false;
344     }
345 
346     return this->onRewind();
347 }
348 
frame_rect_on_screen(SkIRect frameRect,const SkIRect & screenRect)349 static SkIRect frame_rect_on_screen(SkIRect frameRect,
350                                     const SkIRect& screenRect) {
351     if (!frameRect.intersect(screenRect)) {
352         return SkIRect::MakeEmpty();
353     }
354 
355     return frameRect;
356 }
357 
zero_rect(const SkImageInfo & dstInfo,void * pixels,size_t rowBytes,SkISize srcDimensions,SkIRect prevRect)358 bool zero_rect(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes,
359                SkISize srcDimensions, SkIRect prevRect) {
360     const auto dimensions = dstInfo.dimensions();
361     if (dimensions != srcDimensions) {
362         SkRect src = SkRect::Make(srcDimensions);
363         SkRect dst = SkRect::Make(dimensions);
364         SkMatrix map = SkMatrix::RectToRect(src, dst);
365         SkRect asRect = SkRect::Make(prevRect);
366         if (!map.mapRect(&asRect)) {
367             return false;
368         }
369         asRect.roundOut(&prevRect);
370     }
371 
372     if (!prevRect.intersect(SkIRect::MakeSize(dimensions))) {
373         // Nothing to zero, due to scaling or bad frame rect.
374         return true;
375     }
376 
377     const SkImageInfo info = dstInfo.makeDimensions(prevRect.size());
378     const size_t bpp = dstInfo.bytesPerPixel();
379     const size_t offset = prevRect.x() * bpp + prevRect.y() * rowBytes;
380     void* eraseDst = SkTAddOffset<void>(pixels, offset);
381     SkSampler::Fill(info, eraseDst, rowBytes, SkCodec::kNo_ZeroInitialized);
382     return true;
383 }
384 
handleFrameIndex(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options & options,GetPixelsCallback getPixelsFn)385 SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels, size_t rowBytes,
386                                           const Options& options, GetPixelsCallback getPixelsFn) {
387     if (getPixelsFn) {
388         // If a callback is used, it handles the frame index, so calls from this SkCodec
389         // should always short-circuit in the else case below.
390         fUsingCallbackForHandleFrameIndex = true;
391     } else if (fUsingCallbackForHandleFrameIndex) {
392         return kSuccess;
393     }
394 
395     if (!this->rewindIfNeeded()) {
396         return kCouldNotRewind;
397     }
398 
399     const int index = options.fFrameIndex;
400     if (0 == index) {
401         return this->initializeColorXform(info, fEncodedInfo.alpha(), fEncodedInfo.opaque())
402             ? kSuccess : kInvalidConversion;
403     }
404 
405     if (index < 0) {
406         return kInvalidParameters;
407     }
408 
409     if (options.fSubset) {
410         // If we add support for this, we need to update the code that zeroes
411         // a kRestoreBGColor frame.
412         return kInvalidParameters;
413     }
414 
415     if (index >= this->onGetFrameCount()) {
416         return kIncompleteInput;
417     }
418 
419     const auto* frameHolder = this->getFrameHolder();
420     SkASSERT(frameHolder);
421 
422     const auto* frame = frameHolder->getFrame(index);
423     SkASSERT(frame);
424 
425     const int requiredFrame = frame->getRequiredFrame();
426     if (requiredFrame != kNoFrame) {
427         // Decode earlier frame if necessary
428         const SkFrame* preppedFrame = nullptr;
429         if (options.fPriorFrame == kNoFrame) {
430             Result result = kInternalError;
431             // getPixelsFn will be set when things like SkAndroidCodec are calling this function.
432             // Thus, we call the provided function when recursively decoding previous frames,
433             // but only when necessary (i.e. there is a required frame).
434             if (getPixelsFn) {
435                 result = getPixelsFn(info, pixels, rowBytes, options, requiredFrame);
436             } else {
437                 Options prevFrameOptions(options);
438                 prevFrameOptions.fFrameIndex = requiredFrame;
439                 result = this->getPixels(info, pixels, rowBytes, &prevFrameOptions);
440             }
441             if (result != kSuccess) {
442                 return result;
443             }
444             preppedFrame = frameHolder->getFrame(requiredFrame);
445         } else {
446             // Check for a valid frame as a starting point. Alternatively, we could
447             // treat an invalid frame as not providing one, but rejecting it will
448             // make it easier to catch the mistake.
449             if (options.fPriorFrame < requiredFrame || options.fPriorFrame >= index) {
450                 return kInvalidParameters;
451             }
452             preppedFrame = frameHolder->getFrame(options.fPriorFrame);
453         }
454 
455         SkASSERT(preppedFrame);
456         switch (preppedFrame->getDisposalMethod()) {
457             case SkCodecAnimation::DisposalMethod::kRestorePrevious:
458                 SkASSERT(options.fPriorFrame != kNoFrame);
459                 return kInvalidParameters;
460             case SkCodecAnimation::DisposalMethod::kRestoreBGColor:
461                 // If a frame after the required frame is provided, there is no
462                 // need to clear, since it must be covered by the desired frame.
463                 // FIXME: If the required frame is kRestoreBGColor, we don't actually need to decode
464                 // it, since we'll just clear it to transparent. Instead, we could decode *its*
465                 // required frame and then clear.
466                 if (preppedFrame->frameId() == requiredFrame) {
467                     SkIRect preppedRect = preppedFrame->frameRect();
468                     if (!zero_rect(info, pixels, rowBytes, this->dimensions(), preppedRect)) {
469                         return kInternalError;
470                     }
471                 }
472                 break;
473             default:
474                 break;
475         }
476     }
477 
478     return this->initializeColorXform(info, frame->reportedAlpha(), !frame->hasAlpha())
479         ? kSuccess : kInvalidConversion;
480 }
481 
getPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options * options)482 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
483                                    const Options* options) {
484     if (kUnknown_SkColorType == info.colorType()) {
485         return kInvalidConversion;
486     }
487     if (nullptr == pixels) {
488         return kInvalidParameters;
489     }
490     if (rowBytes < info.minRowBytes()) {
491         return kInvalidParameters;
492     }
493 
494     // Default options.
495     Options optsStorage;
496     if (nullptr == options) {
497         options = &optsStorage;
498     } else {
499         if (options->fSubset) {
500             SkIRect subset(*options->fSubset);
501             if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) {
502                 // FIXME: How to differentiate between not supporting subset at all
503                 // and not supporting this particular subset?
504                 return kUnimplemented;
505             }
506         }
507     }
508 
509     const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes,
510                                                            *options);
511     if (frameIndexResult != kSuccess) {
512         return frameIndexResult;
513     }
514 
515     // FIXME: Support subsets somehow? Note that this works for SkWebpCodec
516     // because it supports arbitrary scaling/subset combinations.
517     if (!this->dimensionsSupported(info.dimensions())) {
518         return kInvalidScale;
519     }
520 
521     fDstInfo = info;
522     fOptions = *options;
523 
524     // On an incomplete decode, the subclass will specify the number of scanlines that it decoded
525     // successfully.
526     int rowsDecoded = 0;
527     const Result result = this->onGetPixels(info, pixels, rowBytes, *options, &rowsDecoded);
528 
529     // A return value of kIncompleteInput indicates a truncated image stream.
530     // In this case, we will fill any uninitialized memory with a default value.
531     // Some subclasses will take care of filling any uninitialized memory on
532     // their own.  They indicate that all of the memory has been filled by
533     // setting rowsDecoded equal to the height.
534     if ((kIncompleteInput == result || kErrorInInput == result) && rowsDecoded != info.height()) {
535         // FIXME: (skbug.com/5772) fillIncompleteImage will fill using the swizzler's width, unless
536         // there is a subset. In that case, it will use the width of the subset. From here, the
537         // subset will only be non-null in the case of SkWebpCodec, but it treats the subset
538         // differenty from the other codecs, and it needs to use the width specified by the info.
539         // Set the subset to null so SkWebpCodec uses the correct width.
540         fOptions.fSubset = nullptr;
541         this->fillIncompleteImage(info, pixels, rowBytes, options->fZeroInitialized, info.height(),
542                 rowsDecoded);
543     }
544 
545     return result;
546 }
547 
getImage(const SkImageInfo & info,const Options * options)548 std::tuple<sk_sp<SkImage>, SkCodec::Result> SkCodec::getImage(const SkImageInfo& info,
549                                                               const Options* options) {
550     SkBitmap bm;
551     if (!bm.tryAllocPixels(info)) {
552         return {nullptr, kInternalError};
553     }
554 
555     Result result;
556     auto decode = [this, options, &result](const SkPixmap& pm) {
557         result = this->getPixels(pm, options);
558         switch (result) {
559             case SkCodec::kSuccess:
560             case SkCodec::kIncompleteInput:
561             case SkCodec::kErrorInInput:
562                 return true;
563             default:
564                 return false;
565         }
566     };
567 
568     // If the codec reports this image is rotated, we will decode it into
569     // a temporary buffer, then copy it (rotated) into the pixmap belonging
570     // to bm that we allocated above. If the image is not rotated, we will
571     // decode straight into that allocated pixmap.
572     if (!SkPixmapUtils::Orient(bm.pixmap(), this->getOrigin(), decode)) {
573         return {nullptr, result};
574     }
575     // Setting the bitmap to be immutable saves us from having to copy it.
576     bm.setImmutable();
577     return {SkImages::RasterFromBitmap(bm), kSuccess};
578 }
579 
getImage()580 std::tuple<sk_sp<SkImage>, SkCodec::Result> SkCodec::getImage() {
581     // If the codec reports that it is rotated, we need to rotate the image info
582     // it says it is, so the output is what the user wants.
583     SkImageInfo info = this->getInfo();
584     if (SkEncodedOriginSwapsWidthHeight(this->getOrigin())) {
585         info = SkPixmapUtils::SwapWidthHeight(info);
586     }
587     return this->getImage(info, nullptr);
588 }
589 
startIncrementalDecode(const SkImageInfo & info,void * pixels,size_t rowBytes,const SkCodec::Options * options)590 SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* pixels,
591         size_t rowBytes, const SkCodec::Options* options) {
592     fStartedIncrementalDecode = false;
593 
594     if (kUnknown_SkColorType == info.colorType()) {
595         return kInvalidConversion;
596     }
597     if (nullptr == pixels) {
598         return kInvalidParameters;
599     }
600 
601     // Set options.
602     Options optsStorage;
603     if (nullptr == options) {
604         options = &optsStorage;
605     } else {
606         if (options->fSubset) {
607             SkIRect size = SkIRect::MakeSize(info.dimensions());
608             if (!size.contains(*options->fSubset)) {
609                 return kInvalidParameters;
610             }
611 
612             const int top = options->fSubset->top();
613             const int bottom = options->fSubset->bottom();
614             if (top < 0 || top >= info.height() || top >= bottom || bottom > info.height()) {
615                 return kInvalidParameters;
616             }
617         }
618     }
619 
620     const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes,
621                                                            *options);
622     if (frameIndexResult != kSuccess) {
623         return frameIndexResult;
624     }
625 
626     if (!this->dimensionsSupported(info.dimensions())) {
627         return kInvalidScale;
628     }
629 
630     fDstInfo = info;
631     fOptions = *options;
632 
633     const Result result = this->onStartIncrementalDecode(info, pixels, rowBytes, fOptions);
634     if (kSuccess == result) {
635         fStartedIncrementalDecode = true;
636     } else if (kUnimplemented == result) {
637         // FIXME: This is temporarily necessary, until we transition SkCodec
638         // implementations from scanline decoding to incremental decoding.
639         // SkAndroidCodec will first attempt to use incremental decoding, but
640         // will fall back to scanline decoding if incremental returns
641         // kUnimplemented. rewindIfNeeded(), above, set fNeedsRewind to true
642         // (after potentially rewinding), but we do not want the next call to
643         // startScanlineDecode() to do a rewind.
644         fNeedsRewind = false;
645     }
646     return result;
647 }
648 
649 
startScanlineDecode(const SkImageInfo & info,const SkCodec::Options * options)650 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info,
651         const SkCodec::Options* options) {
652     // Reset fCurrScanline in case of failure.
653     fCurrScanline = -1;
654 
655     // Set options.
656     Options optsStorage;
657     if (nullptr == options) {
658         options = &optsStorage;
659     } else if (options->fSubset) {
660         SkIRect size = SkIRect::MakeSize(info.dimensions());
661         if (!size.contains(*options->fSubset)) {
662             return kInvalidInput;
663         }
664 
665         // We only support subsetting in the x-dimension for scanline decoder.
666         // Subsetting in the y-dimension can be accomplished using skipScanlines().
667         if (options->fSubset->top() != 0 || options->fSubset->height() != info.height()) {
668             return kInvalidInput;
669         }
670     }
671 
672     // Scanline decoding only supports decoding the first frame.
673     if (options->fFrameIndex != 0) {
674         return kUnimplemented;
675     }
676 
677     // The void* dst and rowbytes in handleFrameIndex or only used for decoding prior
678     // frames, which is not supported here anyway, so it is safe to pass nullptr/0.
679     const Result frameIndexResult = this->handleFrameIndex(info, nullptr, 0, *options);
680     if (frameIndexResult != kSuccess) {
681         return frameIndexResult;
682     }
683 
684     // FIXME: Support subsets somehow?
685     if (!this->dimensionsSupported(info.dimensions())) {
686         return kInvalidScale;
687     }
688 
689     const Result result = this->onStartScanlineDecode(info, *options);
690     if (result != SkCodec::kSuccess) {
691         return result;
692     }
693 
694     // FIXME: See startIncrementalDecode. That method set fNeedsRewind to false
695     // so that when onStartScanlineDecode calls rewindIfNeeded it would not
696     // rewind. But it also relies on that call to rewindIfNeeded to set
697     // fNeedsRewind to true for future decodes. When
698     // fUsingCallbackForHandleFrameIndex is true, that call to rewindIfNeeded is
699     // skipped, so this method sets it back to true.
700     SkASSERT(fUsingCallbackForHandleFrameIndex || fNeedsRewind);
701     fNeedsRewind = true;
702 
703     fCurrScanline = 0;
704     fDstInfo = info;
705     fOptions = *options;
706     return kSuccess;
707 }
708 
getScanlines(void * dst,int countLines,size_t rowBytes)709 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) {
710     if (fCurrScanline < 0) {
711         return 0;
712     }
713 
714     SkASSERT(!fDstInfo.isEmpty());
715     if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) {
716         return 0;
717     }
718 
719     const int linesDecoded = this->onGetScanlines(dst, countLines, rowBytes);
720     if (linesDecoded < countLines) {
721         this->fillIncompleteImage(this->dstInfo(), dst, rowBytes, this->options().fZeroInitialized,
722                 countLines, linesDecoded);
723     }
724     fCurrScanline += countLines;
725     return linesDecoded;
726 }
727 
skipScanlines(int countLines)728 bool SkCodec::skipScanlines(int countLines) {
729     if (fCurrScanline < 0) {
730         return false;
731     }
732 
733     SkASSERT(!fDstInfo.isEmpty());
734     if (countLines < 0 || fCurrScanline + countLines > fDstInfo.height()) {
735         // Arguably, we could just skip the scanlines which are remaining,
736         // and return true. We choose to return false so the client
737         // can catch their bug.
738         return false;
739     }
740 
741     bool result = this->onSkipScanlines(countLines);
742     fCurrScanline += countLines;
743     return result;
744 }
745 
outputScanline(int inputScanline) const746 int SkCodec::outputScanline(int inputScanline) const {
747     SkASSERT(0 <= inputScanline && inputScanline < fEncodedInfo.height());
748     return this->onOutputScanline(inputScanline);
749 }
750 
onOutputScanline(int inputScanline) const751 int SkCodec::onOutputScanline(int inputScanline) const {
752     switch (this->getScanlineOrder()) {
753         case kTopDown_SkScanlineOrder:
754             return inputScanline;
755         case kBottomUp_SkScanlineOrder:
756             return fEncodedInfo.height() - inputScanline - 1;
757         default:
758             // This case indicates an interlaced gif and is implemented by SkGifCodec.
759             SkASSERT(false);
760             return 0;
761     }
762 }
763 
fillIncompleteImage(const SkImageInfo & info,void * dst,size_t rowBytes,ZeroInitialized zeroInit,int linesRequested,int linesDecoded)764 void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t rowBytes,
765         ZeroInitialized zeroInit, int linesRequested, int linesDecoded) {
766     if (kYes_ZeroInitialized == zeroInit) {
767         return;
768     }
769 
770     const int linesRemaining = linesRequested - linesDecoded;
771     SkSampler* sampler = this->getSampler(false);
772 
773     const int fillWidth = sampler          ? sampler->fillWidth()      :
774                           fOptions.fSubset ? fOptions.fSubset->width() :
775                                              info.width()              ;
776     void* fillDst = this->getScanlineOrder() == kBottomUp_SkScanlineOrder ? dst :
777                         SkTAddOffset<void>(dst, linesDecoded * rowBytes);
778     const auto fillInfo = info.makeWH(fillWidth, linesRemaining);
779     SkSampler::Fill(fillInfo, fillDst, rowBytes, kNo_ZeroInitialized);
780 }
781 
sk_select_xform_format(SkColorType colorType,bool forColorTable,skcms_PixelFormat * outFormat)782 bool sk_select_xform_format(SkColorType colorType, bool forColorTable,
783                             skcms_PixelFormat* outFormat) {
784     SkASSERT(outFormat);
785 
786     switch (colorType) {
787         case kRGBA_8888_SkColorType:
788             *outFormat = skcms_PixelFormat_RGBA_8888;
789             break;
790         case kBGRA_8888_SkColorType:
791             *outFormat = skcms_PixelFormat_BGRA_8888;
792             break;
793         case kRGB_565_SkColorType:
794             if (forColorTable) {
795 #if defined(SK_PMCOLOR_IS_RGBA)
796                 *outFormat = skcms_PixelFormat_RGBA_8888;
797 #else
798                 *outFormat = skcms_PixelFormat_BGRA_8888;
799 #endif
800                 break;
801             }
802             *outFormat = skcms_PixelFormat_BGR_565;
803             break;
804         case kRGBA_F16_SkColorType:
805             *outFormat = skcms_PixelFormat_RGBA_hhhh;
806             break;
807         case kBGR_101010x_XR_SkColorType:
808             *outFormat = skcms_PixelFormat_BGR_101010x_XR;
809             break;
810         case kGray_8_SkColorType:
811             *outFormat = skcms_PixelFormat_G_8;
812             break;
813         default:
814             return false;
815     }
816     return true;
817 }
818 
initializeColorXform(const SkImageInfo & dstInfo,SkEncodedInfo::Alpha encodedAlpha,bool srcIsOpaque)819 bool SkCodec::initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha encodedAlpha,
820                                    bool srcIsOpaque) {
821     fXformTime = kNo_XformTime;
822     bool needsColorXform = false;
823     if (this->usesColorXform()) {
824         if (kRGBA_F16_SkColorType == dstInfo.colorType() ||
825                 kBGR_101010x_XR_SkColorType == dstInfo.colorType()) {
826             needsColorXform = true;
827             if (dstInfo.colorSpace()) {
828                 dstInfo.colorSpace()->toProfile(&fDstProfile);
829             } else {
830                 // Use the srcProfile to avoid conversion.
831                 const auto* srcProfile = fEncodedInfo.profile();
832                 fDstProfile = srcProfile ? *srcProfile : *skcms_sRGB_profile();
833             }
834         } else if (dstInfo.colorSpace()) {
835             dstInfo.colorSpace()->toProfile(&fDstProfile);
836             const auto* srcProfile = fEncodedInfo.profile();
837             if (!srcProfile) {
838                 srcProfile = skcms_sRGB_profile();
839             }
840             if (!skcms_ApproximatelyEqualProfiles(srcProfile, &fDstProfile) ) {
841                 needsColorXform = true;
842             }
843         }
844     }
845 
846     if (!this->conversionSupported(dstInfo, srcIsOpaque, needsColorXform)) {
847         return false;
848     }
849 
850     if (needsColorXform) {
851         fXformTime = SkEncodedInfo::kPalette_Color != fEncodedInfo.color()
852                           || kRGBA_F16_SkColorType == dstInfo.colorType()
853                 ? kDecodeRow_XformTime : kPalette_XformTime;
854         if (!sk_select_xform_format(dstInfo.colorType(), fXformTime == kPalette_XformTime,
855                                     &fDstXformFormat)) {
856             return false;
857         }
858         if (encodedAlpha == SkEncodedInfo::kUnpremul_Alpha
859                 && dstInfo.alphaType() == kPremul_SkAlphaType) {
860             fDstXformAlphaFormat = skcms_AlphaFormat_PremulAsEncoded;
861         } else {
862             fDstXformAlphaFormat = skcms_AlphaFormat_Unpremul;
863         }
864     }
865     return true;
866 }
867 
applyColorXform(void * dst,const void * src,int count) const868 void SkCodec::applyColorXform(void* dst, const void* src, int count) const {
869     // It is okay for srcProfile to be null. This will use sRGB.
870     const auto* srcProfile = fEncodedInfo.profile();
871     SkAssertResult(skcms_Transform(src, fSrcXformFormat, skcms_AlphaFormat_Unpremul, srcProfile,
872                                    dst, fDstXformFormat, fDstXformAlphaFormat, &fDstProfile,
873                                    count));
874 }
875 
getFrameInfo()876 std::vector<SkCodec::FrameInfo> SkCodec::getFrameInfo() {
877     const int frameCount = this->getFrameCount();
878     SkASSERT(frameCount >= 0);
879     if (frameCount <= 0) {
880         return std::vector<FrameInfo>{};
881     }
882 
883     if (frameCount == 1 && !this->onGetFrameInfo(0, nullptr)) {
884         // Not animated.
885         return std::vector<FrameInfo>{};
886     }
887 
888     std::vector<FrameInfo> result(frameCount);
889     for (int i = 0; i < frameCount; ++i) {
890         SkAssertResult(this->onGetFrameInfo(i, &result[i]));
891     }
892     return result;
893 }
894 
ResultToString(Result result)895 const char* SkCodec::ResultToString(Result result) {
896     switch (result) {
897         case kSuccess:
898             return "success";
899         case kIncompleteInput:
900             return "incomplete input";
901         case kErrorInInput:
902             return "error in input";
903         case kInvalidConversion:
904             return "invalid conversion";
905         case kInvalidScale:
906             return "invalid scale";
907         case kInvalidParameters:
908             return "invalid parameters";
909         case kInvalidInput:
910             return "invalid input";
911         case kCouldNotRewind:
912             return "could not rewind";
913         case kInternalError:
914             return "internal error";
915         case kUnimplemented:
916             return "unimplemented";
917         default:
918             SkASSERT(false);
919             return "bogus result value";
920     }
921 }
922 
fillIn(SkCodec::FrameInfo * frameInfo,bool fullyReceived) const923 void SkFrame::fillIn(SkCodec::FrameInfo* frameInfo, bool fullyReceived) const {
924     SkASSERT(frameInfo);
925 
926     frameInfo->fRequiredFrame = fRequiredFrame;
927     frameInfo->fDuration = fDuration;
928     frameInfo->fFullyReceived = fullyReceived;
929     frameInfo->fAlphaType = fHasAlpha ? kUnpremul_SkAlphaType
930                                       : kOpaque_SkAlphaType;
931     frameInfo->fHasAlphaWithinBounds = this->reportedAlpha() != SkEncodedInfo::kOpaque_Alpha;
932     frameInfo->fDisposalMethod = fDisposalMethod;
933     frameInfo->fBlend = fBlend;
934     frameInfo->fFrameRect = fRect;
935 }
936 
independent(const SkFrame & frame)937 static bool independent(const SkFrame& frame) {
938     return frame.getRequiredFrame() == SkCodec::kNoFrame;
939 }
940 
restore_bg(const SkFrame & frame)941 static bool restore_bg(const SkFrame& frame) {
942     return frame.getDisposalMethod() == SkCodecAnimation::DisposalMethod::kRestoreBGColor;
943 }
944 
945 // As its name suggests, this method computes a frame's alpha (e.g. completely
946 // opaque, unpremul, binary) and its required frame (a preceding frame that
947 // this frame depends on, to draw the complete image at this frame's point in
948 // the animation stream), and calls this frame's setter methods with that
949 // computed information.
950 //
951 // A required frame of kNoFrame means that this frame is independent: drawing
952 // the complete image at this frame's point in the animation stream does not
953 // require first preparing the pixel buffer based on another frame. Instead,
954 // drawing can start from an uninitialized pixel buffer.
955 //
956 // "Uninitialized" is from the SkCodec's caller's point of view. In the SkCodec
957 // implementation, for independent frames, first party Skia code (in src/codec)
958 // will typically fill the buffer with a uniform background color (e.g.
959 // transparent black) before calling into third party codec-specific code (e.g.
960 // libjpeg or libpng). Pixels outside of the frame's rect will remain this
961 // background color after drawing this frame. For incomplete decodes, pixels
962 // inside that rect may be (at least temporarily) set to that background color.
963 // In an incremental decode, later passes may then overwrite that background
964 // color.
965 //
966 // Determining kNoFrame or otherwise involves testing a number of conditions
967 // sequentially. The first satisfied condition results in setting the required
968 // frame to kNoFrame (an "INDx" condition) or to a non-negative frame number (a
969 // "DEPx" condition), and the function returning early. Those "INDx" and "DEPx"
970 // labels also map to comments in the function body.
971 //
972 //  - IND1: this frame is the first frame.
973 //  - IND2: this frame fills out the whole image, and it is completely opaque
974 //          or it overwrites (not blends with) the previous frame.
975 //  - IND3: all preceding frames' disposals are kRestorePrevious.
976 //  - IND4: the prevFrame's disposal is kRestoreBGColor, and it fills out the
977 //          whole image or it is itself otherwise independent.
978 //  - DEP5: this frame reports alpha (it is not completely opaque) and it
979 //          blends with (not overwrites) the previous frame.
980 //  - IND6: this frame's rect covers the rects of all preceding frames back to
981 //          and including the most recent independent frame before this frame.
982 //  - DEP7: unconditional.
983 //
984 // The "prevFrame" variable initially points to the previous frame (also known
985 // as the prior frame), but that variable may iterate further backwards over
986 // the course of this computation.
setAlphaAndRequiredFrame(SkFrame * frame)987 void SkFrameHolder::setAlphaAndRequiredFrame(SkFrame* frame) {
988     const bool reportsAlpha = frame->reportedAlpha() != SkEncodedInfo::kOpaque_Alpha;
989     const auto screenRect = SkIRect::MakeWH(fScreenWidth, fScreenHeight);
990     const auto frameRect = frame_rect_on_screen(frame->frameRect(), screenRect);
991 
992     const int i = frame->frameId();
993     if (0 == i) {
994         frame->setHasAlpha(reportsAlpha || frameRect != screenRect);
995         frame->setRequiredFrame(SkCodec::kNoFrame);  // IND1
996         return;
997     }
998 
999 
1000     const bool blendWithPrevFrame = frame->getBlend() == SkCodecAnimation::Blend::kSrcOver;
1001     if ((!reportsAlpha || !blendWithPrevFrame) && frameRect == screenRect) {
1002         frame->setHasAlpha(reportsAlpha);
1003         frame->setRequiredFrame(SkCodec::kNoFrame);  // IND2
1004         return;
1005     }
1006 
1007     const SkFrame* prevFrame = this->getFrame(i-1);
1008     while (prevFrame->getDisposalMethod() == SkCodecAnimation::DisposalMethod::kRestorePrevious) {
1009         const int prevId = prevFrame->frameId();
1010         if (0 == prevId) {
1011             frame->setHasAlpha(true);
1012             frame->setRequiredFrame(SkCodec::kNoFrame);  // IND3
1013             return;
1014         }
1015 
1016         prevFrame = this->getFrame(prevId - 1);
1017     }
1018 
1019     const bool clearPrevFrame = restore_bg(*prevFrame);
1020     auto prevFrameRect = frame_rect_on_screen(prevFrame->frameRect(), screenRect);
1021 
1022     if (clearPrevFrame) {
1023         if (prevFrameRect == screenRect || independent(*prevFrame)) {
1024             frame->setHasAlpha(true);
1025             frame->setRequiredFrame(SkCodec::kNoFrame);  // IND4
1026             return;
1027         }
1028     }
1029 
1030     if (reportsAlpha && blendWithPrevFrame) {
1031         // Note: We could be more aggressive here. If prevFrame clears
1032         // to background color and covers its required frame (and that
1033         // frame is independent), prevFrame could be marked independent.
1034         // Would this extra complexity be worth it?
1035         frame->setRequiredFrame(prevFrame->frameId());  // DEP5
1036         frame->setHasAlpha(prevFrame->hasAlpha() || clearPrevFrame);
1037         return;
1038     }
1039 
1040     while (frameRect.contains(prevFrameRect)) {
1041         const int prevRequiredFrame = prevFrame->getRequiredFrame();
1042         if (prevRequiredFrame == SkCodec::kNoFrame) {
1043             frame->setRequiredFrame(SkCodec::kNoFrame);  // IND6
1044             frame->setHasAlpha(true);
1045             return;
1046         }
1047 
1048         prevFrame = this->getFrame(prevRequiredFrame);
1049         prevFrameRect = frame_rect_on_screen(prevFrame->frameRect(), screenRect);
1050     }
1051 
1052     frame->setRequiredFrame(prevFrame->frameId());  // DEP7
1053     if (restore_bg(*prevFrame)) {
1054         frame->setHasAlpha(true);
1055         return;
1056     }
1057     SkASSERT(prevFrame->getDisposalMethod() == SkCodecAnimation::DisposalMethod::kKeep);
1058     frame->setHasAlpha(prevFrame->hasAlpha() || (reportsAlpha && !blendWithPrevFrame));
1059 }
1060 
getEncodedData() const1061 std::unique_ptr<SkStream> SkCodec::getEncodedData() const {
1062     SkASSERT(fStream);
1063     if (!fStream) {
1064         return nullptr;
1065     }
1066     return fStream->duplicate();
1067 }
1068