57#if defined(WUFFS_IMPLEMENTATION)
58#error "SkWuffsCodec should not #define WUFFS_IMPLEMENTATION"
60#include "wuffs-v0.3.c"
62#if WUFFS_VERSION_BUILD_METADATA_COMMIT_COUNT < 2514
63#error "Wuffs version is too old. Upgrade to the latest version."
66#define SK_WUFFS_CODEC_BUFFER_SIZE 4096
78#if defined(SK_WUFFS_FAVORS_PERFORMANCE_OVER_ADDITIONAL_MEMORY_SAFETY)
79#define SK_WUFFS_INITIALIZE_FLAGS WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED
81#define SK_WUFFS_INITIALIZE_FLAGS WUFFS_INITIALIZE__DEFAULT_OPTIONS
86 size_t num_read =
s->read(
b->data.ptr +
b->meta.wi,
b->data.len -
b->meta.wi);
87 b->meta.wi += num_read;
109 b->meta.closed =
false;
116 if ((
pos >=
b->meta.pos) && (
pos -
b->meta.pos <=
b->meta.wi)) {
117 b->meta.ri =
pos -
b->meta.pos;
121 if ((
pos > SIZE_MAX) || (!
s->seek(
pos))) {
127 b->meta.closed =
false;
132 wuffs_base__animation_disposal
w) {
134 case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_BACKGROUND:
136 case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS:
148 wuffs_base__image_config* imgcfg,
149 wuffs_base__io_buffer*
b,
153 wuffs_base__status status =
155 if (status.repr !=
nullptr) {
161 decoder->set_quirk_enabled(WUFFS_GIF__QUIRK_IGNORE_TOO_MUCH_PIXEL_DATA,
true);
164 status = decoder->decode_image_config(imgcfg,
b);
165 if (status.repr ==
nullptr) {
167 }
else if (status.repr != wuffs_base__suspension__short_read) {
179 uint32_t pixfmt = WUFFS_BASE__PIXEL_FORMAT__INVALID;
180 switch (kN32_SkColorType) {
182 pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL;
185 pixfmt = WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL;
191 imgcfg->pixcfg.set(pixfmt, WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, imgcfg->pixcfg.width(),
192 imgcfg->pixcfg.height());
212 uint64_t fIOPosition;
240 std::unique_ptr<SkStream>
stream,
242 std::unique_ptr<wuffs_gif__decoder,
decltype(&
sk_free)> dec,
243 std::unique_ptr<uint8_t,
decltype(&
sk_free)> workbuf_ptr,
245 wuffs_base__image_config imgcfg,
246 wuffs_base__io_buffer iobuf);
261 Result onIncrementalDecode(
int* rowsDecoded)
override;
262 int onGetFrameCount()
override;
263 bool onGetFrameInfo(
int,
FrameInfo*)
const override;
264 int onGetRepetitionCount()
override;
282 uint32_t pixelFormat,
283 size_t bytesPerPixel);
284 Result onStartIncrementalDecodeTwoPass();
285 Result onIncrementalDecodeOnePass();
286 Result onIncrementalDecodeTwoPass();
288 void onGetFrameCountInternal();
289 Result seekFrame(
int frameIndex);
291 const char* decodeFrameConfig();
292 const char* decodeFrame();
293 void updateNumFullyReceivedFrames();
296 std::unique_ptr<SkStream> fPrivStream;
297 std::unique_ptr<uint8_t,
decltype(&
sk_free)> fWorkbufPtr;
300 std::unique_ptr<wuffs_gif__decoder,
decltype(&
sk_free)> fDecoder;
302 const uint64_t fFirstFrameIOPosition;
303 wuffs_base__frame_config fFrameConfig;
304 wuffs_base__pixel_config fPixelConfig;
305 wuffs_base__pixel_buffer fPixelBuffer;
306 wuffs_base__io_buffer fIOBuffer;
309 uint8_t* fIncrDecDst;
310 size_t fIncrDecRowBytes;
311 wuffs_base__pixel_blend fIncrDecPixelBlend;
312 bool fIncrDecOnePass;
313 bool fFirstCallToIncrementalDecode;
316 std::unique_ptr<uint8_t,
decltype(&
sk_free)> fTwoPassPixbufPtr;
317 size_t fTwoPassPixbufLen;
319 uint64_t fNumFullyReceivedFrames;
320 std::vector<SkWuffsFrame> fFrames;
321 bool fFramesComplete;
333 bool fDecoderIsSuspended;
346 fIOPosition(fc->io_position()),
347 fReportedAlpha(fc->opaque_within_bounds() ?
SkEncodedInfo::kOpaque_Alpha
349 wuffs_base__rect_ie_u32 r = fc->bounds();
350 this->
setXYWH(r.min_incl_x, r.min_incl_y, r.width(), r.height());
352 this->
setDuration(fc->duration() / WUFFS_BASE__FLICKS_PER_MILLISECOND);
362 return fReportedAlpha;
381 std::unique_ptr<SkStream>
stream,
383 std::unique_ptr<wuffs_gif__decoder,
decltype(&
sk_free)> dec,
384 std::unique_ptr<uint8_t,
decltype(&
sk_free)> workbuf_ptr,
386 wuffs_base__image_config imgcfg,
387 wuffs_base__io_buffer iobuf)
396 fWorkbufPtr(
std::move(workbuf_ptr)),
397 fWorkbufLen(workbuf_len),
398 fDecoder(
std::move(dec)),
399 fFirstFrameIOPosition(imgcfg.first_frame_io_position()),
400 fFrameConfig(wuffs_base__null_frame_config()),
401 fPixelConfig(imgcfg.pixcfg),
402 fPixelBuffer(wuffs_base__null_pixel_buffer()),
403 fIOBuffer(wuffs_base__empty_io_buffer()),
404 fIncrDecDst(nullptr),
406 fIncrDecPixelBlend(WUFFS_BASE__PIXEL_BLEND__SRC),
407 fIncrDecOnePass(
false),
408 fFirstCallToIncrementalDecode(
false),
409 fTwoPassPixbufPtr(nullptr, &
sk_free),
410 fTwoPassPixbufLen(0),
411 fNumFullyReceivedFrames(0),
412 fFramesComplete(
false),
413 fDecoderIsSuspended(
false),
415 fFrameHolder.
init(
this, imgcfg.pixcfg.width(), imgcfg.pixcfg.height());
421 memmove(fBuffer, iobuf.data.ptr, iobuf.meta.wi);
423 fIOBuffer.meta = iobuf.meta;
427 if ((0 <=
i) && (
static_cast<size_t>(
i) < fFrames.size())) {
446 return this->onIncrementalDecode(rowsDecoded);
450 return &fFrameHolder;
468 const char* status = this->decodeFrameConfig();
469 if (status == wuffs_base__suspension__short_read) {
471 }
else if (status !=
nullptr) {
476 uint32_t pixelFormat = WUFFS_BASE__PIXEL_FORMAT__INVALID;
477 size_t bytesPerPixel = 0;
481 pixelFormat = WUFFS_BASE__PIXEL_FORMAT__BGR_565;
485 pixelFormat = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL;
489 pixelFormat = WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL;
498 fIncrDecOnePass = (pixelFormat != WUFFS_BASE__PIXEL_FORMAT__INVALID) &&
505 result = fIncrDecOnePass ? this->onStartIncrementalDecodeOnePass(
507 pixelFormat, bytesPerPixel)
508 : this->onStartIncrementalDecodeTwoPass();
513 fIncrDecDst =
static_cast<uint8_t*
>(
dst);
514 fIncrDecRowBytes = rowBytes;
515 fFirstCallToIncrementalDecode =
true;
523 uint32_t pixelFormat,
524 size_t bytesPerPixel) {
525 wuffs_base__pixel_config pixelConfig;
526 pixelConfig.set(pixelFormat, WUFFS_BASE__PIXEL_SUBSAMPLING__NONE,
dstInfo.
width(),
529 wuffs_base__table_u8
table;
533 table.stride = rowBytes;
535 wuffs_base__status status = fPixelBuffer.set_from_table(&pixelConfig,
table);
536 if (status.repr !=
nullptr) {
546 fIncrDecPixelBlend = WUFFS_BASE__PIXEL_BLEND__SRC_OVER;
549 fIncrDecPixelBlend = WUFFS_BASE__PIXEL_BLEND__SRC;
558 bool already_zeroed =
false;
560 if (!fTwoPassPixbufPtr) {
561 uint64_t pixbuf_len = fPixelConfig.pixbuf_len();
562 void* pixbuf_ptr_raw = (pixbuf_len <= SIZE_MAX)
565 if (!pixbuf_ptr_raw) {
568 fTwoPassPixbufPtr.reset(
reinterpret_cast<uint8_t*
>(pixbuf_ptr_raw));
569 fTwoPassPixbufLen =
SkToSizeT(pixbuf_len);
570 already_zeroed =
true;
573 wuffs_base__status status = fPixelBuffer.set_from_slice(
574 &fPixelConfig, wuffs_base__make_slice_u8(fTwoPassPixbufPtr.get(), fTwoPassPixbufLen));
575 if (status.repr !=
nullptr) {
580 if (!already_zeroed) {
581 uint32_t src_bits_per_pixel = fPixelConfig.pixel_format().bits_per_pixel();
582 if ((src_bits_per_pixel == 0) || (src_bits_per_pixel % 8 != 0)) {
585 size_t src_bytes_per_pixel = src_bits_per_pixel / 8;
587 wuffs_base__rect_ie_u32 frame_rect = fFrameConfig.bounds();
588 wuffs_base__table_u8 pixels = fPixelBuffer.plane(0);
590 uint8_t* ptr = pixels.ptr + (frame_rect.min_incl_y * pixels.stride) +
591 (frame_rect.min_incl_x * src_bytes_per_pixel);
592 size_t len = frame_rect.width() * src_bytes_per_pixel;
596 if ((
len == pixels.stride) && (frame_rect.min_incl_y < frame_rect.max_excl_y)) {
597 sk_bzero(ptr,
len * (frame_rect.max_excl_y - frame_rect.min_incl_y));
599 for (uint32_t
y = frame_rect.min_incl_y;
y < frame_rect.max_excl_y;
y++) {
601 ptr += pixels.stride;
606 fIncrDecPixelBlend = WUFFS_BASE__PIXEL_BLEND__SRC;
620 fIncrDecOnePass ? this->onIncrementalDecodeOnePass() : this->onIncrementalDecodeTwoPass();
622 fIncrDecDst =
nullptr;
623 fIncrDecRowBytes = 0;
624 fIncrDecPixelBlend = WUFFS_BASE__PIXEL_BLEND__SRC;
625 fIncrDecOnePass =
false;
631 const char* status = this->decodeFrame();
632 if (status !=
nullptr) {
633 if (status == wuffs_base__suspension__short_read) {
645 const char* status = this->decodeFrame();
657 if (status !=
nullptr) {
658 if (status == wuffs_base__suspension__short_read) {
672 uint32_t src_bits_per_pixel = fPixelBuffer.pixcfg.pixel_format().bits_per_pixel();
673 if ((src_bits_per_pixel == 0) || (src_bits_per_pixel % 8 != 0)) {
676 size_t src_bytes_per_pixel = src_bits_per_pixel / 8;
678 wuffs_base__rect_ie_u32 frame_rect = fFrameConfig.bounds();
679 if (fFirstCallToIncrementalDecode) {
680 if (frame_rect.width() > (SIZE_MAX / src_bytes_per_pixel)) {
685 frame_rect.max_excl_x, frame_rect.max_excl_y);
692 fFirstCallToIncrementalDecode =
false;
706 wuffs_base__rect_ie_u32 dirty_rect = fDecoder->frame_dirty_rect();
707 if (!dirty_rect.is_empty()) {
708 wuffs_base__table_u8 pixels = fPixelBuffer.plane(0);
716 uint8_t*
s = pixels.ptr + (dirty_rect.min_incl_y * pixels.stride) +
717 (dirty_rect.min_incl_x * src_bytes_per_pixel);
727 src.installPixels(srcInfo,
s, pixels.stride);
734 draw.fDst.reset(
dstInfo(), fIncrDecDst, fIncrDecRowBytes);
771 if (fFramesComplete && (
static_cast<size_t>(
options().fFrameIndex) == fFrames.size() - 1)) {
772 fTwoPassPixbufPtr.reset(
nullptr);
773 fTwoPassPixbufLen = 0;
780int SkWuffsCodec::onGetFrameCount() {
813 bool incrementalDecodeIsInProgress = fIncrDecDst !=
nullptr;
815 if (!fFramesComplete && !incrementalDecodeIsInProgress) {
816 this->onGetFrameCountInternal();
817 this->updateNumFullyReceivedFrames();
819 return fFrames.size();
822void SkWuffsCodec::onGetFrameCountInternal() {
823 size_t n = fFrames.size();
824 int i = n ? n - 1 : 0;
831 for (;
i < INT_MAX;
i++) {
832 const char* status = this->decodeFrameConfig();
833 if (status ==
nullptr) {
835 }
else if (status == wuffs_base__note__end_of_data) {
841 if (
static_cast<size_t>(
i) < fFrames.size()) {
844 fFrames.emplace_back(&fFrameConfig);
849 fFramesComplete =
true;
863 f->fillIn(frameInfo,
static_cast<uint64_t
>(
i) < this->fNumFullyReceivedFrames);
868int SkWuffsCodec::onGetRepetitionCount() {
873 uint32_t n = fDecoder->num_animation_loops();
878 return n < INT_MAX ? n : INT_MAX;
882 if (fDecoderIsSuspended) {
890 if (frameIndex < 0) {
892 }
else if (frameIndex == 0) {
893 pos = fFirstFrameIOPosition;
894 }
else if (
static_cast<size_t>(frameIndex) < fFrames.size()) {
895 pos = fFrames[frameIndex].ioPosition();
903 wuffs_base__status status =
904 fDecoder->restart_frame(frameIndex, fIOBuffer.reader_io_position());
905 if (status.repr !=
nullptr) {
912 if (!fPrivStream->rewind()) {
915 fIOBuffer.meta = wuffs_base__empty_io_buffer_meta();
925 fDecoderIsSuspended =
false;
929const char* SkWuffsCodec::decodeFrameConfig() {
931 wuffs_base__status status =
932 fDecoder->decode_frame_config(&fFrameConfig, &fIOBuffer);
933 if ((status.repr == wuffs_base__suspension__short_read) &&
937 fDecoderIsSuspended = !status.is_complete();
938 this->updateNumFullyReceivedFrames();
943const char* SkWuffsCodec::decodeFrame() {
945 wuffs_base__status status = fDecoder->decode_frame(
946 &fPixelBuffer, &fIOBuffer, fIncrDecPixelBlend,
947 wuffs_base__make_slice_u8(fWorkbufPtr.get(), fWorkbufLen),
nullptr);
948 if ((status.repr == wuffs_base__suspension__short_read) &&
952 fDecoderIsSuspended = !status.is_complete();
953 this->updateNumFullyReceivedFrames();
958void SkWuffsCodec::updateNumFullyReceivedFrames() {
962 uint64_t n = fDecoder->num_decoded_frames();
963 if (fNumFullyReceivedFrames < n) {
964 fNumFullyReceivedFrames = n;
972 return fPrivStream->duplicate();
977bool IsGif(
const void* buf,
size_t bytesRead) {
978 constexpr const char* gif_ptr =
"GIF8";
979 constexpr size_t gif_len = 4;
980 return (bytesRead >= gif_len) && (memcmp(buf, gif_ptr, gif_len) == 0);
992 bool canSeek =
stream->hasPosition() &&
stream->hasLength();
999 stream = std::make_unique<SkMemoryStream>(std::move(
data));
1005 wuffs_base__io_buffer iobuf =
1007 wuffs_base__empty_io_buffer_meta());
1008 wuffs_base__image_config imgcfg = wuffs_base__null_image_config();
1034 std::unique_ptr<wuffs_gif__decoder,
decltype(&
sk_free)> decoder(
1035 reinterpret_cast<wuffs_gif__decoder*
>(decoder_raw), &
sk_free);
1044 uint32_t
width = imgcfg.pixcfg.width();
1045 uint32_t
height = imgcfg.pixcfg.height();
1051 uint64_t workbuf_len = decoder->workbuf_len().max_incl;
1052 void* workbuf_ptr_raw =
nullptr;
1054 workbuf_ptr_raw = workbuf_len <= SIZE_MAX ?
sk_malloc_canfail(workbuf_len) :
nullptr;
1055 if (!workbuf_ptr_raw) {
1060 std::unique_ptr<uint8_t,
decltype(&
sk_free)> workbuf_ptr(
1061 reinterpret_cast<uint8_t*
>(workbuf_ptr_raw), &
sk_free);
1064 (imgcfg.pixcfg.pixel_format().repr == WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL)
1076 return std::unique_ptr<SkCodec>(
new SkWuffsCodec(std::move(encodedInfo), std::move(
stream),
1078 std::move(decoder), std::move(workbuf_ptr),
1079 workbuf_len, imgcfg, iobuf));
1087 outResult = &resultStorage;
sk_bzero(glyphs, sizeof(glyphs))
@ kOpaque_SkAlphaType
pixel is opaque
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
#define SkCodecPrintf(...)
static bool independent(const SkFrame &frame)
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
SK_API void * sk_malloc_flags(size_t size, unsigned flags)
@ SK_MALLOC_ZERO_INITIALIZE
SK_API void sk_free(void *)
static void * sk_malloc_canfail(size_t size)
sk_sp< SkData > SkCopyStreamToData(SkStream *stream)
constexpr size_t SkToSizeT(S x)
static SkCodecAnimation::DisposalMethod wuffs_disposal_to_skia_disposal(wuffs_base__animation_disposal w)
static SkCodec::Result reset_and_decode_image_config(wuffs_gif__decoder *decoder, wuffs_base__image_config *imgcfg, wuffs_base__io_buffer *b, SkStream *s)
static SkAlphaType to_alpha_type(bool opaque)
static bool seek_buffer(wuffs_base__io_buffer *b, SkStream *s, uint64_t pos)
#define SK_WUFFS_CODEC_BUFFER_SIZE
#define SK_WUFFS_INITIALIZE_FLAGS
static bool fill_buffer(wuffs_base__io_buffer *b, SkStream *s)
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
SkISize dimensions() const
const SkImageInfo & dstInfo() const
const SkEncodedInfo & getEncodedInfo() const
static constexpr int kRepetitionCountInfinite
static constexpr int kNoFrame
SkImageInfo getInfo() const
const Options & options() const
void setAlphaAndRequiredFrame(SkFrame *)
void setBlend(SkCodecAnimation::Blend blend)
void setDuration(int duration)
void setDisposalMethod(SkCodecAnimation::DisposalMethod disposalMethod)
void setXYWH(int x, int y, int width, int height)
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
static SkMatrix Translate(SkScalar dx, SkScalar dy)
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
static void Fill(const SkImageInfo &info, void *dst, size_t rowBytes, SkCodec::ZeroInitialized zeroInit)
SkScalingCodec(SkEncodedInfo &&info, XformFormat srcFormat, std::unique_ptr< SkStream > stream, SkEncodedOrigin origin=kTopLeft_SkEncodedOrigin)
const SkWuffsFrame * frame(int i) const
SkWuffsCodec(SkEncodedInfo &&encodedInfo, std::unique_ptr< SkStream > stream, bool canSeek, std::unique_ptr< wuffs_gif__decoder, decltype(&sk_free)> dec, std::unique_ptr< uint8_t, decltype(&sk_free)> workbuf_ptr, size_t workbuf_len, wuffs_base__image_config imgcfg, wuffs_base__io_buffer iobuf)
std::unique_ptr< SkStream > getEncodedData() const override
const SkFrame * onGetFrame(int i) const override
void init(SkWuffsCodec *codec, int width, int height)
SkWuffsFrame(wuffs_base__frame_config *fc)
SkEncodedInfo::Alpha onReportedAlpha() const override
uint64_t ioPosition() const
std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream > stream, SkCodec::SelectionPolicy selectionPolicy, SkCodec::Result *result)
SK_API std::unique_ptr< SkCodec > Decode(std::unique_ptr< SkStream >, SkCodec::Result *, SkCodecs::DecodeContext=nullptr)
SK_API bool IsGif(const void *, size_t)
unsigned useCenter Optional< SkMatrix > matrix
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 policy
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
SkSamplingOptions(SkFilterMode::kLinear))
@ skcms_PixelFormat_RGBA_8888
ZeroInitialized fZeroInitialized
const skcms_ICCProfile * profile() const
static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha, int bitsPerComponent)
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
static constexpr SkIRect MakeSize(const SkISize &size)
SkImageInfo makeWH(int newWidth, int newHeight) const
SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const
SkISize dimensions() const
SkColorType colorType() const
static SkRect Make(const SkISize &size)
std::shared_ptr< const fml::Mapping > data