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