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