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