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