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