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