• 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 "SkBmpCodec.h"
9 #include "SkCodec.h"
10 #include "SkCodecPriv.h"
11 #include "SkColorSpace.h"
12 #include "SkColorSpaceXform_Base.h"
13 #include "SkData.h"
14 #include "SkFrameHolder.h"
15 #include "SkGifCodec.h"
16 #include "SkHalf.h"
17 #ifdef SK_HAS_HEIF_LIBRARY
18 #include "SkHeifCodec.h"
19 #endif
20 #include "SkIcoCodec.h"
21 #include "SkJpegCodec.h"
22 #ifdef SK_HAS_PNG_LIBRARY
23 #include "SkPngCodec.h"
24 #endif
25 #include "SkRawCodec.h"
26 #include "SkStream.h"
27 #include "SkWbmpCodec.h"
28 #include "SkWebpCodec.h"
29 
30 struct DecoderProc {
31     bool (*IsFormat)(const void*, size_t);
32     std::unique_ptr<SkCodec> (*MakeFromStream)(std::unique_ptr<SkStream>, SkCodec::Result*);
33 };
34 
35 static constexpr DecoderProc gDecoderProcs[] = {
36 #ifdef SK_HAS_JPEG_LIBRARY
37     { SkJpegCodec::IsJpeg, SkJpegCodec::MakeFromStream },
38 #endif
39 #ifdef SK_HAS_WEBP_LIBRARY
40     { SkWebpCodec::IsWebp, SkWebpCodec::MakeFromStream },
41 #endif
42     { SkGifCodec::IsGif, SkGifCodec::MakeFromStream },
43 #ifdef SK_HAS_PNG_LIBRARY
44     { SkIcoCodec::IsIco, SkIcoCodec::MakeFromStream },
45 #endif
46     { SkBmpCodec::IsBmp, SkBmpCodec::MakeFromStream },
47     { SkWbmpCodec::IsWbmp, SkWbmpCodec::MakeFromStream },
48 #ifdef SK_HAS_HEIF_LIBRARY
49     { SkHeifCodec::IsHeif, SkHeifCodec::MakeFromStream },
50 #endif
51 };
52 
MakeFromStream(std::unique_ptr<SkStream> stream,Result * outResult,SkPngChunkReader * chunkReader)53 std::unique_ptr<SkCodec> SkCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
54                                                  Result* outResult, SkPngChunkReader* chunkReader) {
55     Result resultStorage;
56     if (!outResult) {
57         outResult = &resultStorage;
58     }
59 
60     if (!stream) {
61         *outResult = kInvalidInput;
62         return nullptr;
63     }
64 
65     constexpr size_t bytesToRead = MinBufferedBytesNeeded();
66 
67     char buffer[bytesToRead];
68     size_t bytesRead = stream->peek(buffer, bytesToRead);
69 
70     // It is also possible to have a complete image less than bytesToRead bytes
71     // (e.g. a 1 x 1 wbmp), meaning peek() would return less than bytesToRead.
72     // Assume that if bytesRead < bytesToRead, but > 0, the stream is shorter
73     // than bytesToRead, so pass that directly to the decoder.
74     // It also is possible the stream uses too small a buffer for peeking, but
75     // we trust the caller to use a large enough buffer.
76 
77     if (0 == bytesRead) {
78         // TODO: After implementing peek in CreateJavaOutputStreamAdaptor.cpp, this
79         // printf could be useful to notice failures.
80         // SkCodecPrintf("Encoded image data failed to peek!\n");
81 
82         // It is possible the stream does not support peeking, but does support
83         // rewinding.
84         // Attempt to read() and pass the actual amount read to the decoder.
85         bytesRead = stream->read(buffer, bytesToRead);
86         if (!stream->rewind()) {
87             SkCodecPrintf("Encoded image data could not peek or rewind to determine format!\n");
88             *outResult = kCouldNotRewind;
89             return nullptr;
90         }
91     }
92 
93     // PNG is special, since we want to be able to supply an SkPngChunkReader.
94     // But this code follows the same pattern as the loop.
95 #ifdef SK_HAS_PNG_LIBRARY
96     if (SkPngCodec::IsPng(buffer, bytesRead)) {
97         return SkPngCodec::MakeFromStream(std::move(stream), outResult, chunkReader);
98     } else
99 #endif
100     {
101         for (DecoderProc proc : gDecoderProcs) {
102             if (proc.IsFormat(buffer, bytesRead)) {
103                 return proc.MakeFromStream(std::move(stream), outResult);
104             }
105         }
106 
107 #ifdef SK_CODEC_DECODES_RAW
108         // Try to treat the input as RAW if all the other checks failed.
109         return SkRawCodec::MakeFromStream(std::move(stream), outResult);
110 #endif
111     }
112 
113     if (bytesRead < bytesToRead) {
114         *outResult = kIncompleteInput;
115     } else {
116         *outResult = kUnimplemented;
117     }
118 
119     return nullptr;
120 }
121 
MakeFromData(sk_sp<SkData> data,SkPngChunkReader * reader)122 std::unique_ptr<SkCodec> SkCodec::MakeFromData(sk_sp<SkData> data, SkPngChunkReader* reader) {
123     if (!data) {
124         return nullptr;
125     }
126     return MakeFromStream(SkMemoryStream::Make(std::move(data)), nullptr, reader);
127 }
128 
SkCodec(int width,int height,const SkEncodedInfo & info,XformFormat srcFormat,std::unique_ptr<SkStream> stream,sk_sp<SkColorSpace> colorSpace,SkEncodedOrigin origin)129 SkCodec::SkCodec(int width, int height, const SkEncodedInfo& info,
130         XformFormat srcFormat, std::unique_ptr<SkStream> stream,
131         sk_sp<SkColorSpace> colorSpace, SkEncodedOrigin origin)
132     : fEncodedInfo(info)
133     , fSrcInfo(info.makeImageInfo(width, height, std::move(colorSpace)))
134     , fSrcXformFormat(srcFormat)
135     , fStream(std::move(stream))
136     , fNeedsRewind(false)
137     , fOrigin(origin)
138     , fDstInfo()
139     , fOptions()
140     , fCurrScanline(-1)
141     , fStartedIncrementalDecode(false)
142 {}
143 
SkCodec(const SkEncodedInfo & info,const SkImageInfo & imageInfo,XformFormat srcFormat,std::unique_ptr<SkStream> stream,SkEncodedOrigin origin)144 SkCodec::SkCodec(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
145         XformFormat srcFormat, std::unique_ptr<SkStream> stream,
146         SkEncodedOrigin origin)
147     : fEncodedInfo(info)
148     , fSrcInfo(imageInfo)
149     , fSrcXformFormat(srcFormat)
150     , fStream(std::move(stream))
151     , fNeedsRewind(false)
152     , fOrigin(origin)
153     , fDstInfo()
154     , fOptions()
155     , fCurrScanline(-1)
156     , fStartedIncrementalDecode(false)
157 {}
158 
~SkCodec()159 SkCodec::~SkCodec() {}
160 
conversionSupported(const SkImageInfo & dst,SkColorType srcColor,bool srcIsOpaque,const SkColorSpace * srcCS) const161 bool SkCodec::conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
162                                   bool srcIsOpaque, const SkColorSpace* srcCS) const {
163     if (!valid_alpha(dst.alphaType(), srcIsOpaque)) {
164         return false;
165     }
166 
167     switch (dst.colorType()) {
168         case kRGBA_8888_SkColorType:
169         case kBGRA_8888_SkColorType:
170             return true;
171         case kRGBA_F16_SkColorType:
172             return dst.colorSpace() && dst.colorSpace()->gammaIsLinear();
173         case kRGB_565_SkColorType:
174             return srcIsOpaque;
175         case kGray_8_SkColorType:
176             return kGray_8_SkColorType == srcColor && srcIsOpaque &&
177                    !needs_color_xform(dst, srcCS, false);
178         case kAlpha_8_SkColorType:
179             // conceptually we can convert anything into alpha_8, but we haven't actually coded
180             // all of those other conversions yet, so only return true for the case we have codec.
181             return fSrcInfo.colorType() == kAlpha_8_SkColorType;;
182         default:
183             return false;
184     }
185 
186 }
187 
rewindIfNeeded()188 bool SkCodec::rewindIfNeeded() {
189     // Store the value of fNeedsRewind so we can update it. Next read will
190     // require a rewind.
191     const bool needsRewind = fNeedsRewind;
192     fNeedsRewind = true;
193     if (!needsRewind) {
194         return true;
195     }
196 
197     // startScanlineDecode will need to be called before decoding scanlines.
198     fCurrScanline = -1;
199     // startIncrementalDecode will need to be called before incrementalDecode.
200     fStartedIncrementalDecode = false;
201 
202     // Some codecs do not have a stream.  They may hold onto their own data or another codec.
203     // They must handle rewinding themselves.
204     if (fStream && !fStream->rewind()) {
205         return false;
206     }
207 
208     return this->onRewind();
209 }
210 
zero_rect(const SkImageInfo & dstInfo,void * pixels,size_t rowBytes,SkIRect frameRect)211 static void zero_rect(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes,
212                       SkIRect frameRect) {
213     if (!frameRect.intersect(dstInfo.bounds())) {
214         return;
215     }
216     const auto info = dstInfo.makeWH(frameRect.width(), frameRect.height());
217     const size_t bpp = SkColorTypeBytesPerPixel(dstInfo.colorType());
218     const size_t offset = frameRect.x() * bpp + frameRect.y() * rowBytes;
219     auto* eraseDst = SkTAddOffset<void>(pixels, offset);
220     SkSampler::Fill(info, eraseDst, rowBytes, 0, SkCodec::kNo_ZeroInitialized);
221 }
222 
handleFrameIndex(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options & options)223 SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels, size_t rowBytes,
224                                           const Options& options) {
225     const int index = options.fFrameIndex;
226     if (0 == index) {
227         if (!this->conversionSupported(info, fSrcInfo.colorType(), fEncodedInfo.opaque(),
228                                       fSrcInfo.colorSpace())
229             || !this->initializeColorXform(info, fEncodedInfo.alpha(), options.fPremulBehavior))
230         {
231             return kInvalidConversion;
232         }
233         return kSuccess;
234     }
235 
236     if (index < 0) {
237         return kInvalidParameters;
238     }
239 
240     if (options.fSubset) {
241         // If we add support for this, we need to update the code that zeroes
242         // a kRestoreBGColor frame.
243         return kInvalidParameters;
244     }
245 
246     if (index >= this->onGetFrameCount()) {
247         return kIncompleteInput;
248     }
249 
250     const auto* frameHolder = this->getFrameHolder();
251     SkASSERT(frameHolder);
252 
253     const auto* frame = frameHolder->getFrame(index);
254     SkASSERT(frame);
255 
256     if (!this->conversionSupported(info, fSrcInfo.colorType(), !frame->hasAlpha(),
257                                    fSrcInfo.colorSpace())) {
258         return kInvalidConversion;
259     }
260 
261     const int requiredFrame = frame->getRequiredFrame();
262     if (requiredFrame != kNone) {
263         if (options.fPriorFrame != kNone) {
264             // Check for a valid frame as a starting point. Alternatively, we could
265             // treat an invalid frame as not providing one, but rejecting it will
266             // make it easier to catch the mistake.
267             if (options.fPriorFrame < requiredFrame || options.fPriorFrame >= index) {
268                 return kInvalidParameters;
269             }
270             const auto* prevFrame = frameHolder->getFrame(options.fPriorFrame);
271             switch (prevFrame->getDisposalMethod()) {
272                 case SkCodecAnimation::DisposalMethod::kRestorePrevious:
273                     return kInvalidParameters;
274                 case SkCodecAnimation::DisposalMethod::kRestoreBGColor:
275                     // If a frame after the required frame is provided, there is no
276                     // need to clear, since it must be covered by the desired frame.
277                     if (options.fPriorFrame == requiredFrame) {
278                         SkIRect prevRect = prevFrame->frameRect();
279                         if (info.dimensions() != fSrcInfo.dimensions()) {
280                             auto src = SkRect::Make(fSrcInfo.dimensions());
281                             auto dst = SkRect::Make(info.dimensions());
282                             SkMatrix map = SkMatrix::MakeRectToRect(src, dst,
283                                     SkMatrix::kCenter_ScaleToFit);
284                             SkRect asRect = SkRect::Make(prevRect);
285                             if (!map.mapRect(&asRect)) {
286                                 return kInternalError;
287                             }
288                             asRect.roundIn(&prevRect);
289                             if (prevRect.isEmpty()) {
290                                 // Down-scaling shrank the empty portion to nothing,
291                                 // so nothing to zero.
292                                 break;
293                             }
294                             if (!prevRect.intersect(SkIRect::MakeSize(info.dimensions()))) {
295                                 SkCodecPrintf("rectangles do not intersect!");
296                                 SkASSERT(false);
297                                 break;
298                             }
299                         }
300                         zero_rect(info, pixels, rowBytes, prevRect);
301                     }
302                     break;
303                 default:
304                     break;
305             }
306         } else {
307             Options prevFrameOptions(options);
308             prevFrameOptions.fFrameIndex = requiredFrame;
309             prevFrameOptions.fZeroInitialized = kNo_ZeroInitialized;
310             const Result result = this->getPixels(info, pixels, rowBytes, &prevFrameOptions);
311             if (result != kSuccess) {
312                 return result;
313             }
314             const auto* prevFrame = frameHolder->getFrame(requiredFrame);
315             const auto disposalMethod = prevFrame->getDisposalMethod();
316             if (disposalMethod == SkCodecAnimation::DisposalMethod::kRestoreBGColor) {
317                 zero_rect(info, pixels, rowBytes, prevFrame->frameRect());
318             }
319         }
320     }
321 
322     return this->initializeColorXform(info, frame->reportedAlpha(), options.fPremulBehavior)
323         ? kSuccess : kInvalidConversion;
324 }
325 
getPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options * options)326 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
327                                    const Options* options) {
328     if (kUnknown_SkColorType == info.colorType()) {
329         return kInvalidConversion;
330     }
331     if (nullptr == pixels) {
332         return kInvalidParameters;
333     }
334     if (rowBytes < info.minRowBytes()) {
335         return kInvalidParameters;
336     }
337 
338     if (!this->rewindIfNeeded()) {
339         return kCouldNotRewind;
340     }
341 
342     // Default options.
343     Options optsStorage;
344     if (nullptr == options) {
345         options = &optsStorage;
346     } else {
347         if (options->fSubset) {
348             SkIRect subset(*options->fSubset);
349             if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) {
350                 // FIXME: How to differentiate between not supporting subset at all
351                 // and not supporting this particular subset?
352                 return kUnimplemented;
353             }
354         }
355     }
356 
357     const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes,
358                                                            *options);
359     if (frameIndexResult != kSuccess) {
360         return frameIndexResult;
361     }
362 
363     // FIXME: Support subsets somehow? Note that this works for SkWebpCodec
364     // because it supports arbitrary scaling/subset combinations.
365     if (!this->dimensionsSupported(info.dimensions())) {
366         return kInvalidScale;
367     }
368 
369     fDstInfo = info;
370     fOptions = *options;
371 
372     // On an incomplete decode, the subclass will specify the number of scanlines that it decoded
373     // successfully.
374     int rowsDecoded = 0;
375     const Result result = this->onGetPixels(info, pixels, rowBytes, *options, &rowsDecoded);
376 
377     // A return value of kIncompleteInput indicates a truncated image stream.
378     // In this case, we will fill any uninitialized memory with a default value.
379     // Some subclasses will take care of filling any uninitialized memory on
380     // their own.  They indicate that all of the memory has been filled by
381     // setting rowsDecoded equal to the height.
382     if ((kIncompleteInput == result || kErrorInInput == result) && rowsDecoded != info.height()) {
383         // FIXME: (skbug.com/5772) fillIncompleteImage will fill using the swizzler's width, unless
384         // there is a subset. In that case, it will use the width of the subset. From here, the
385         // subset will only be non-null in the case of SkWebpCodec, but it treats the subset
386         // differenty from the other codecs, and it needs to use the width specified by the info.
387         // Set the subset to null so SkWebpCodec uses the correct width.
388         fOptions.fSubset = nullptr;
389         this->fillIncompleteImage(info, pixels, rowBytes, options->fZeroInitialized, info.height(),
390                 rowsDecoded);
391     }
392 
393     return result;
394 }
395 
startIncrementalDecode(const SkImageInfo & info,void * pixels,size_t rowBytes,const SkCodec::Options * options)396 SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* pixels,
397         size_t rowBytes, const SkCodec::Options* options) {
398     fStartedIncrementalDecode = false;
399 
400     if (kUnknown_SkColorType == info.colorType()) {
401         return kInvalidConversion;
402     }
403     if (nullptr == pixels) {
404         return kInvalidParameters;
405     }
406 
407     // FIXME: If the rows come after the rows of a previous incremental decode,
408     // we might be able to skip the rewind, but only the implementation knows
409     // that. (e.g. PNG will always need to rewind, since we called longjmp, but
410     // a bottom-up BMP could skip rewinding if the new rows are above the old
411     // rows.)
412     if (!this->rewindIfNeeded()) {
413         return kCouldNotRewind;
414     }
415 
416     // Set options.
417     Options optsStorage;
418     if (nullptr == options) {
419         options = &optsStorage;
420     } else {
421         if (options->fSubset) {
422             SkIRect size = SkIRect::MakeSize(info.dimensions());
423             if (!size.contains(*options->fSubset)) {
424                 return kInvalidParameters;
425             }
426 
427             const int top = options->fSubset->top();
428             const int bottom = options->fSubset->bottom();
429             if (top < 0 || top >= info.height() || top >= bottom || bottom > info.height()) {
430                 return kInvalidParameters;
431             }
432         }
433     }
434 
435     const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes,
436                                                            *options);
437     if (frameIndexResult != kSuccess) {
438         return frameIndexResult;
439     }
440 
441     if (!this->dimensionsSupported(info.dimensions())) {
442         return kInvalidScale;
443     }
444 
445     fDstInfo = info;
446     fOptions = *options;
447 
448     const Result result = this->onStartIncrementalDecode(info, pixels, rowBytes, fOptions);
449     if (kSuccess == result) {
450         fStartedIncrementalDecode = true;
451     } else if (kUnimplemented == result) {
452         // FIXME: This is temporarily necessary, until we transition SkCodec
453         // implementations from scanline decoding to incremental decoding.
454         // SkAndroidCodec will first attempt to use incremental decoding, but
455         // will fall back to scanline decoding if incremental returns
456         // kUnimplemented. rewindIfNeeded(), above, set fNeedsRewind to true
457         // (after potentially rewinding), but we do not want the next call to
458         // startScanlineDecode() to do a rewind.
459         fNeedsRewind = false;
460     }
461     return result;
462 }
463 
464 
startScanlineDecode(const SkImageInfo & info,const SkCodec::Options * options)465 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info,
466         const SkCodec::Options* options) {
467     // Reset fCurrScanline in case of failure.
468     fCurrScanline = -1;
469 
470     if (!this->rewindIfNeeded()) {
471         return kCouldNotRewind;
472     }
473 
474     // Set options.
475     Options optsStorage;
476     if (nullptr == options) {
477         options = &optsStorage;
478     } else if (options->fSubset) {
479         SkIRect size = SkIRect::MakeSize(info.dimensions());
480         if (!size.contains(*options->fSubset)) {
481             return kInvalidInput;
482         }
483 
484         // We only support subsetting in the x-dimension for scanline decoder.
485         // Subsetting in the y-dimension can be accomplished using skipScanlines().
486         if (options->fSubset->top() != 0 || options->fSubset->height() != info.height()) {
487             return kInvalidInput;
488         }
489     }
490 
491     // Scanline decoding only supports decoding the first frame.
492     if (options->fFrameIndex != 0) {
493         return kUnimplemented;
494     }
495 
496     // The void* dst and rowbytes in handleFrameIndex or only used for decoding prior
497     // frames, which is not supported here anyway, so it is safe to pass nullptr/0.
498     const Result frameIndexResult = this->handleFrameIndex(info, nullptr, 0, *options);
499     if (frameIndexResult != kSuccess) {
500         return frameIndexResult;
501     }
502 
503     // FIXME: Support subsets somehow?
504     if (!this->dimensionsSupported(info.dimensions())) {
505         return kInvalidScale;
506     }
507 
508     const Result result = this->onStartScanlineDecode(info, *options);
509     if (result != SkCodec::kSuccess) {
510         return result;
511     }
512 
513     fCurrScanline = 0;
514     fDstInfo = info;
515     fOptions = *options;
516     return kSuccess;
517 }
518 
getScanlines(void * dst,int countLines,size_t rowBytes)519 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) {
520     if (fCurrScanline < 0) {
521         return 0;
522     }
523 
524     SkASSERT(!fDstInfo.isEmpty());
525     if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) {
526         return 0;
527     }
528 
529     const int linesDecoded = this->onGetScanlines(dst, countLines, rowBytes);
530     if (linesDecoded < countLines) {
531         this->fillIncompleteImage(this->dstInfo(), dst, rowBytes, this->options().fZeroInitialized,
532                 countLines, linesDecoded);
533     }
534     fCurrScanline += countLines;
535     return linesDecoded;
536 }
537 
skipScanlines(int countLines)538 bool SkCodec::skipScanlines(int countLines) {
539     if (fCurrScanline < 0) {
540         return false;
541     }
542 
543     SkASSERT(!fDstInfo.isEmpty());
544     if (countLines < 0 || fCurrScanline + countLines > fDstInfo.height()) {
545         // Arguably, we could just skip the scanlines which are remaining,
546         // and return true. We choose to return false so the client
547         // can catch their bug.
548         return false;
549     }
550 
551     bool result = this->onSkipScanlines(countLines);
552     fCurrScanline += countLines;
553     return result;
554 }
555 
outputScanline(int inputScanline) const556 int SkCodec::outputScanline(int inputScanline) const {
557     SkASSERT(0 <= inputScanline && inputScanline < this->getInfo().height());
558     return this->onOutputScanline(inputScanline);
559 }
560 
onOutputScanline(int inputScanline) const561 int SkCodec::onOutputScanline(int inputScanline) const {
562     switch (this->getScanlineOrder()) {
563         case kTopDown_SkScanlineOrder:
564             return inputScanline;
565         case kBottomUp_SkScanlineOrder:
566             return this->getInfo().height() - inputScanline - 1;
567         default:
568             // This case indicates an interlaced gif and is implemented by SkGifCodec.
569             SkASSERT(false);
570             return 0;
571     }
572 }
573 
onGetFillValue(const SkImageInfo & dstInfo) const574 uint64_t SkCodec::onGetFillValue(const SkImageInfo& dstInfo) const {
575     switch (dstInfo.colorType()) {
576         case kRGBA_F16_SkColorType: {
577             static constexpr uint64_t transparentColor = 0;
578             static constexpr uint64_t opaqueColor = ((uint64_t) SK_Half1) << 48;
579             return (kOpaque_SkAlphaType == fSrcInfo.alphaType()) ? opaqueColor : transparentColor;
580         }
581         default: {
582             // This not only handles the kN32 case, but also k565, kGray8, since
583             // the low bits are zeros.
584             return (kOpaque_SkAlphaType == fSrcInfo.alphaType()) ?
585                     SK_ColorBLACK : SK_ColorTRANSPARENT;
586         }
587     }
588 }
589 
fill_proc(const SkImageInfo & info,void * dst,size_t rowBytes,uint64_t colorOrIndex,SkCodec::ZeroInitialized zeroInit,SkSampler * sampler)590 static void fill_proc(const SkImageInfo& info, void* dst, size_t rowBytes,
591         uint64_t colorOrIndex, SkCodec::ZeroInitialized zeroInit, SkSampler* sampler) {
592     if (sampler) {
593         sampler->fill(info, dst, rowBytes, colorOrIndex, zeroInit);
594     } else {
595         SkSampler::Fill(info, dst, rowBytes, colorOrIndex, zeroInit);
596     }
597 }
598 
fillIncompleteImage(const SkImageInfo & info,void * dst,size_t rowBytes,ZeroInitialized zeroInit,int linesRequested,int linesDecoded)599 void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t rowBytes,
600         ZeroInitialized zeroInit, int linesRequested, int linesDecoded) {
601 
602     void* fillDst;
603     const uint64_t fillValue = this->getFillValue(info);
604     const int linesRemaining = linesRequested - linesDecoded;
605     SkSampler* sampler = this->getSampler(false);
606 
607     int fillWidth = info.width();
608     if (fOptions.fSubset) {
609         fillWidth = fOptions.fSubset->width();
610     }
611 
612     switch (this->getScanlineOrder()) {
613         case kTopDown_SkScanlineOrder: {
614             const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining);
615             fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes);
616             fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler);
617             break;
618         }
619         case kBottomUp_SkScanlineOrder: {
620             fillDst = dst;
621             const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining);
622             fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler);
623             break;
624         }
625     }
626 }
627 
select_xform_format_ct(SkColorType colorType)628 static inline SkColorSpaceXform::ColorFormat select_xform_format_ct(SkColorType colorType) {
629     switch (colorType) {
630         case kRGBA_8888_SkColorType:
631             return SkColorSpaceXform::kRGBA_8888_ColorFormat;
632         case kBGRA_8888_SkColorType:
633             return SkColorSpaceXform::kBGRA_8888_ColorFormat;
634         case kRGB_565_SkColorType:
635 #ifdef SK_PMCOLOR_IS_RGBA
636             return SkColorSpaceXform::kRGBA_8888_ColorFormat;
637 #else
638             return SkColorSpaceXform::kBGRA_8888_ColorFormat;
639 #endif
640         default:
641             SkASSERT(false);
642             return SkColorSpaceXform::kRGBA_8888_ColorFormat;
643     }
644 }
645 
initializeColorXform(const SkImageInfo & dstInfo,SkEncodedInfo::Alpha encodedAlpha,SkTransferFunctionBehavior premulBehavior)646 bool SkCodec::initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha encodedAlpha,
647                                    SkTransferFunctionBehavior premulBehavior) {
648     fColorXform = nullptr;
649     fXformOnDecode = false;
650     if (!this->usesColorXform()) {
651         return true;
652     }
653     // FIXME: In SkWebpCodec, if a frame is blending with a prior frame, we don't need
654     // a colorXform to do a color correct premul, since the blend step will handle
655     // premultiplication. But there is no way to know whether we need to blend from
656     // inside this call.
657     bool needsColorCorrectPremul = needs_premul(dstInfo.alphaType(), encodedAlpha) &&
658                                    SkTransferFunctionBehavior::kRespect == premulBehavior;
659     if (needs_color_xform(dstInfo, fSrcInfo.colorSpace(), needsColorCorrectPremul)) {
660         fColorXform = SkColorSpaceXform_Base::New(fSrcInfo.colorSpace(), dstInfo.colorSpace(),
661                                                   premulBehavior);
662         if (!fColorXform) {
663             return false;
664         }
665 
666         // We will apply the color xform when reading the color table unless F16 is requested.
667         fXformOnDecode = SkEncodedInfo::kPalette_Color != fEncodedInfo.color()
668             || kRGBA_F16_SkColorType == dstInfo.colorType();
669         if (fXformOnDecode) {
670             fDstXformFormat = select_xform_format(dstInfo.colorType());
671         } else {
672             fDstXformFormat = select_xform_format_ct(dstInfo.colorType());
673         }
674     }
675 
676     return true;
677 }
678 
applyColorXform(void * dst,const void * src,int count,SkAlphaType at) const679 void SkCodec::applyColorXform(void* dst, const void* src, int count, SkAlphaType at) const {
680     SkASSERT(fColorXform);
681     SkAssertResult(fColorXform->apply(fDstXformFormat, dst,
682                                       fSrcXformFormat, src,
683                                       count, at));
684 }
685 
applyColorXform(void * dst,const void * src,int count) const686 void SkCodec::applyColorXform(void* dst, const void* src, int count) const {
687     auto alphaType = select_xform_alpha(fDstInfo.alphaType(), fSrcInfo.alphaType());
688     this->applyColorXform(dst, src, count, alphaType);
689 }
690 
getFrameInfo()691 std::vector<SkCodec::FrameInfo> SkCodec::getFrameInfo() {
692     const int frameCount = this->getFrameCount();
693     SkASSERT(frameCount >= 0);
694     if (frameCount <= 0) {
695         return std::vector<FrameInfo>{};
696     }
697 
698     if (frameCount == 1 && !this->onGetFrameInfo(0, nullptr)) {
699         // Not animated.
700         return std::vector<FrameInfo>{};
701     }
702 
703     std::vector<FrameInfo> result(frameCount);
704     for (int i = 0; i < frameCount; ++i) {
705         SkAssertResult(this->onGetFrameInfo(i, &result[i]));
706     }
707     return result;
708 }
709 
ResultToString(Result result)710 const char* SkCodec::ResultToString(Result result) {
711     switch (result) {
712         case kSuccess:
713             return "success";
714         case kIncompleteInput:
715             return "incomplete input";
716         case kErrorInInput:
717             return "error in input";
718         case kInvalidConversion:
719             return "invalid conversion";
720         case kInvalidScale:
721             return "invalid scale";
722         case kInvalidParameters:
723             return "invalid parameters";
724         case kInvalidInput:
725             return "invalid input";
726         case kCouldNotRewind:
727             return "could not rewind";
728         case kInternalError:
729             return "internal error";
730         case kUnimplemented:
731             return "unimplemented";
732         default:
733             SkASSERT(false);
734             return "bogus result value";
735     }
736 }
737