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