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