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