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