Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkWebpCodec.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/SkRect.h"
18#include "include/core/SkSize.h"
25#include "modules/skcms/skcms.h"
27#include "src/codec/SkSampler.h"
32
33#include <algorithm>
34#include <cstdint>
35#include <cstring>
36#include <utility>
37
38// A WebP decoder on top of (subset of) libwebp
39// For more information on WebP image format, and libwebp library, see:
40// https://code.google.com/speed/webp/
41// http://www.webmproject.org/code/#libwebp-webp-image-library
42// https://chromium.googlesource.com/webm/libwebp
43
44// If moving libwebp out of skia source tree, path for webp headers must be
45// updated accordingly. Here, we enforce using local copy in webp sub-directory.
46#include "webp/decode.h" // NO_G3_REWRITE
47#include "webp/demux.h" // NO_G3_REWRITE
48#include "webp/mux_types.h" // NO_G3_REWRITE
49
50bool SkWebpCodec::IsWebp(const void* buf, size_t bytesRead) {
51 // WEBP starts with the following:
52 // RIFFXXXXWEBPVP
53 // Where XXXX is unspecified.
54 const char* bytes = static_cast<const char*>(buf);
55 return bytesRead >= 14 && !memcmp(bytes, "RIFF", 4) && !memcmp(&bytes[8], "WEBPVP", 6);
56}
57
58// Parse headers of RIFF container, and check for valid Webp (VP8) content.
59// Returns an SkWebpCodec on success
60std::unique_ptr<SkCodec> SkWebpCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
61 Result* result) {
63 if (!stream) {
65 return nullptr;
66 }
67 // Webp demux needs a contiguous data buffer.
68 sk_sp<SkData> data = nullptr;
69 if (stream->getMemoryBase()) {
70 // It is safe to make without copy because we'll hold onto the stream.
72 } else {
73 data = SkCopyStreamToData(stream.get());
74
75 // If we are forced to copy the stream to a data, we can go ahead and delete the stream.
76 stream.reset(nullptr);
77 }
78
79 // It's a little strange that the |demux| will outlive |webpData|, though it needs the
80 // pointer in |webpData| to remain valid. This works because the pointer remains valid
81 // until the SkData is freed.
82 WebPData webpData = { data->bytes(), data->size() };
83 WebPDemuxState state;
84 SkAutoTCallVProc<WebPDemuxer, WebPDemuxDelete> demux(WebPDemuxPartial(&webpData, &state));
85 switch (state) {
86 case WEBP_DEMUX_PARSE_ERROR:
88 return nullptr;
89 case WEBP_DEMUX_PARSING_HEADER:
91 return nullptr;
92 case WEBP_DEMUX_PARSED_HEADER:
93 case WEBP_DEMUX_DONE:
94 SkASSERT(demux);
95 break;
96 }
97
98 const int width = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH);
99 const int height = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT);
100
101 // Validate the image size that's about to be decoded.
102 {
103 const int64_t size = sk_64_mul(width, height);
104 // now check that if we are 4-bytes per pixel, we also don't overflow
105 if (!SkTFitsIn<int32_t>(size) || SkTo<int32_t>(size) > (0x7FFFFFFF >> 2)) {
107 return nullptr;
108 }
109 }
110
111 std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
112 {
113 WebPChunkIterator chunkIterator;
115 if (WebPDemuxGetChunk(demux, "ICCP", 1, &chunkIterator)) {
116 // FIXME: I think this could be MakeWithoutCopy
117 auto chunk = SkData::MakeWithCopy(chunkIterator.chunk.bytes, chunkIterator.chunk.size);
118 profile = SkEncodedInfo::ICCProfile::Make(std::move(chunk));
119 }
120 if (profile && profile->profile()->data_color_space != skcms_Signature_RGB) {
121 profile = nullptr;
122 }
123 }
124
126 {
127 WebPChunkIterator chunkIterator;
129 if (WebPDemuxGetChunk(demux, "EXIF", 1, &chunkIterator)) {
130 SkParseEncodedOrigin(chunkIterator.chunk.bytes, chunkIterator.chunk.size, &origin);
131 }
132 }
133
134 // Get the first frame and its "features" to determine the color and alpha types.
135 WebPIterator frame;
137 if (!WebPDemuxGetFrame(demux, 1, &frame)) {
139 return nullptr;
140 }
141
142 WebPBitstreamFeatures features;
143 switch (WebPGetFeatures(frame.fragment.bytes, frame.fragment.size, &features)) {
144 case VP8_STATUS_OK:
145 break;
146 case VP8_STATUS_SUSPENDED:
147 case VP8_STATUS_NOT_ENOUGH_DATA:
149 return nullptr;
150 default:
152 return nullptr;
153 }
154
155 const bool hasAlpha = SkToBool(frame.has_alpha)
156 || frame.width != width || frame.height != height;
159 switch (features.format) {
160 case 0:
161 // This indicates a "mixed" format. We could see this for
162 // animated webps (multiple fragments).
163 // We could also guess kYUV here, but I think it makes more
164 // sense to guess kBGRA which is likely closer to the final
165 // output. Otherwise, we might end up converting
166 // BGRA->YUVA->BGRA.
167 [[fallthrough]];
168 case 2:
169 // This is the lossless format (BGRA).
170 if (hasAlpha) {
173 } else {
176 }
177 break;
178 case 1:
179 // This is the lossy format (YUV).
180 if (hasAlpha) {
183 } else {
186 }
187 break;
188 default:
190 return nullptr;
191 }
192
193
194 *result = kSuccess;
195 SkEncodedInfo info = SkEncodedInfo::Make(width, height, color, alpha, 8, std::move(profile));
196 return std::unique_ptr<SkCodec>(new SkWebpCodec(std::move(info), std::move(stream),
197 demux.release(), std::move(data), origin));
198}
199
200static WEBP_CSP_MODE webp_decode_mode(SkColorType dstCT, bool premultiply) {
201 switch (dstCT) {
203 return premultiply ? MODE_bgrA : MODE_BGRA;
205 return premultiply ? MODE_rgbA : MODE_RGBA;
207 return MODE_RGB_565;
208 default:
209 return MODE_LAST;
210 }
211}
212
213SkWebpCodec::Frame* SkWebpCodec::FrameHolder::appendNewFrame(bool hasAlpha) {
214 const int i = this->size();
215 fFrames.emplace_back(i, hasAlpha ? SkEncodedInfo::kUnpremul_Alpha
216 : SkEncodedInfo::kOpaque_Alpha);
217 return &fFrames[i];
218}
219
220bool SkWebpCodec::onGetValidSubset(SkIRect* desiredSubset) const {
221 if (!desiredSubset) {
222 return false;
223 }
224
225 if (!this->bounds().contains(*desiredSubset)) {
226 return false;
227 }
228
229 // As stated below, libwebp snaps to even left and top. Make sure top and left are even, so we
230 // decode this exact subset.
231 // Leave right and bottom unmodified, so we suggest a slightly larger subset than requested.
232 desiredSubset->fLeft = (desiredSubset->fLeft >> 1) << 1;
233 desiredSubset->fTop = (desiredSubset->fTop >> 1) << 1;
234 return true;
235}
236
238 auto flags = WebPDemuxGetI(fDemux.get(), WEBP_FF_FORMAT_FLAGS);
239 if (!(flags & ANIMATION_FLAG)) {
240 return 0;
241 }
242
243 int loopCount = WebPDemuxGetI(fDemux.get(), WEBP_FF_LOOP_COUNT);
244 if (0 == loopCount) {
246 }
247
248 loopCount--;
249 return loopCount;
250}
251
253 auto flags = WebPDemuxGetI(fDemux.get(), WEBP_FF_FORMAT_FLAGS);
254 if (!(flags & ANIMATION_FLAG)) {
255 return 1;
256 }
257
258 const uint32_t oldFrameCount = fFrameHolder.size();
259 if (fFailed) {
260 return oldFrameCount;
261 }
262
263 const uint32_t frameCount = WebPDemuxGetI(fDemux, WEBP_FF_FRAME_COUNT);
264 if (oldFrameCount == frameCount) {
265 // We have already parsed this.
266 return frameCount;
267 }
268
269 fFrameHolder.reserve(frameCount);
270
271 for (uint32_t i = oldFrameCount; i < frameCount; i++) {
272 WebPIterator iter;
274
275 if (!WebPDemuxGetFrame(fDemux.get(), i + 1, &iter)) {
276 fFailed = true;
277 break;
278 }
279
280 // libwebp only reports complete frames of an animated image.
281 SkASSERT(iter.complete);
282
283 Frame* frame = fFrameHolder.appendNewFrame(iter.has_alpha);
284 frame->setXYWH(iter.x_offset, iter.y_offset, iter.width, iter.height);
285 frame->setDisposalMethod(iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ?
288 frame->setDuration(iter.duration);
289 if (WEBP_MUX_BLEND != iter.blend_method) {
291 }
292 fFrameHolder.setAlphaAndRequiredFrame(frame);
293 }
294
295 return fFrameHolder.size();
296
297}
298
299const SkFrame* SkWebpCodec::FrameHolder::onGetFrame(int i) const {
300 return static_cast<const SkFrame*>(this->frame(i));
301}
302
303const SkWebpCodec::Frame* SkWebpCodec::FrameHolder::frame(int i) const {
304 SkASSERT(i >= 0 && i < this->size());
305 return &fFrames[i];
306}
307
308bool SkWebpCodec::onGetFrameInfo(int i, FrameInfo* frameInfo) const {
309 if (i >= fFrameHolder.size()) {
310 return false;
311 }
312
313 const Frame* frame = fFrameHolder.frame(i);
314 if (!frame) {
315 return false;
316 }
317
318 if (frameInfo) {
319 // libwebp only reports fully received frames for an
320 // animated image.
321 frame->fillIn(frameInfo, true);
322 }
323
324 return true;
325}
326
328 switch (colorType) {
331 return true;
332 default:
333 return false;
334 }
335}
336
337// Requires that the src input be unpremultiplied (or opaque).
338static void blend_line(SkColorType dstCT, void* dst,
339 SkColorType srcCT, const void* src,
340 SkAlphaType dstAt,
341 bool srcHasAlpha,
342 int width) {
343 SkRasterPipeline_MemoryCtx dst_ctx = { dst, 0 },
344 src_ctx = { const_cast<void*>(src), 0 };
345
347
348 p.appendLoadDst(dstCT, &dst_ctx);
349 if (kUnpremul_SkAlphaType == dstAt) {
350 p.append(SkRasterPipelineOp::premul_dst);
351 }
352
353 p.appendLoad(srcCT, &src_ctx);
354 if (srcHasAlpha) {
355 p.append(SkRasterPipelineOp::premul);
356 }
357
358 p.append(SkRasterPipelineOp::srcover);
359
360 if (kUnpremul_SkAlphaType == dstAt) {
361 p.append(SkRasterPipelineOp::unpremul);
362 }
363 p.appendStore(dstCT, &dst_ctx);
364
365 p.run(0,0, width,1);
366}
367
368SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
369 const Options& options, int* rowsDecodedPtr) {
370 const int index = options.fFrameIndex;
371 SkASSERT(0 == index || index < fFrameHolder.size());
372 SkASSERT(0 == index || !options.fSubset);
373
374 WebPDecoderConfig config;
375 if (0 == WebPInitDecoderConfig(&config)) {
376 // ABI mismatch.
377 // FIXME: New enum for this?
378 return kInvalidInput;
379 }
380
381 // Free any memory associated with the buffer. Must be called last, so we declare it first.
383
384 WebPIterator frame;
386 // If this succeeded in onGetFrameCount(), it should succeed again here.
387 SkAssertResult(WebPDemuxGetFrame(fDemux, index + 1, &frame));
388
389 const bool independent = index == 0 ? true :
390 (fFrameHolder.frame(index)->getRequiredFrame() == kNoFrame);
391 // Get the frameRect. libwebp will have already signaled an error if this is not fully
392 // contained by the canvas.
393 auto frameRect = SkIRect::MakeXYWH(frame.x_offset, frame.y_offset, frame.width, frame.height);
394 SkASSERT(this->bounds().contains(frameRect));
395 const bool frameIsSubset = frameRect != this->bounds();
396 if (independent && frameIsSubset) {
398 }
399
400 int dstX = frameRect.x();
401 int dstY = frameRect.y();
402 int subsetWidth = frameRect.width();
403 int subsetHeight = frameRect.height();
404 if (options.fSubset) {
405 SkIRect subset = *options.fSubset;
406 SkASSERT(this->bounds().contains(subset));
407 SkASSERT(SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTop));
408 SkASSERT(this->getValidSubset(&subset) && subset == *options.fSubset);
409
410 if (!SkIRect::Intersects(subset, frameRect)) {
411 return kSuccess;
412 }
413
414 int minXOffset = std::min(dstX, subset.x());
415 int minYOffset = std::min(dstY, subset.y());
416 dstX -= minXOffset;
417 dstY -= minYOffset;
418 frameRect.offset(-minXOffset, -minYOffset);
419 subset.offset(-minXOffset, -minYOffset);
420
421 // Just like we require that the requested subset x and y offset are even, libwebp
422 // guarantees that the frame x and y offset are even (it's actually impossible to specify
423 // an odd frame offset). So we can still guarantee that the adjusted offsets are even.
424 SkASSERT(SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTop));
425
426 SkIRect intersection;
427 SkAssertResult(intersection.intersect(frameRect, subset));
428 subsetWidth = intersection.width();
429 subsetHeight = intersection.height();
430
431 config.options.use_cropping = 1;
432 config.options.crop_left = subset.x();
433 config.options.crop_top = subset.y();
434 config.options.crop_width = subsetWidth;
435 config.options.crop_height = subsetHeight;
436 }
437
438 // Ignore the frame size and offset when determining if scaling is necessary.
439 int scaledWidth = subsetWidth;
440 int scaledHeight = subsetHeight;
441 SkISize srcSize = options.fSubset ? options.fSubset->size() : this->dimensions();
442 if (srcSize != dstInfo.dimensions()) {
443 config.options.use_scaling = 1;
444
445 if (frameIsSubset) {
446 float scaleX = ((float) dstInfo.width()) / srcSize.width();
447 float scaleY = ((float) dstInfo.height()) / srcSize.height();
448
449 // We need to be conservative here and floor rather than round.
450 // Otherwise, we may find ourselves decoding off the end of memory.
451 dstX = scaleX * dstX;
452 scaledWidth = scaleX * scaledWidth;
453 dstY = scaleY * dstY;
454 scaledHeight = scaleY * scaledHeight;
455 if (0 == scaledWidth || 0 == scaledHeight) {
456 return kSuccess;
457 }
458 } else {
459 scaledWidth = dstInfo.width();
460 scaledHeight = dstInfo.height();
461 }
462
463 config.options.scaled_width = scaledWidth;
464 config.options.scaled_height = scaledHeight;
465 }
466
467 const bool blendWithPrevFrame = !independent && frame.blend_method == WEBP_MUX_BLEND
468 && frame.has_alpha;
469
470 auto webpInfo = dstInfo;
471 if (!frame.has_alpha) {
472 webpInfo = webpInfo.makeAlphaType(kOpaque_SkAlphaType);
473 } else if (this->colorXform() || blendWithPrevFrame) {
474 // the colorXform and blend_line expect unpremul.
475 webpInfo = webpInfo.makeAlphaType(kUnpremul_SkAlphaType);
476 }
477 if (this->colorXform()) {
478 // Swizzling between RGBA and BGRA is zero cost in a color transform. So when we have a
479 // color transform, we should decode to whatever is easiest for libwebp, and then let the
480 // color transform swizzle if necessary.
481 // Lossy webp is encoded as YUV (so RGBA and BGRA are the same cost). Lossless webp is
482 // encoded as BGRA. This means decoding to BGRA is either faster or the same cost as RGBA.
483 webpInfo = webpInfo.makeColorType(kBGRA_8888_SkColorType);
484 }
485
486 SkBitmap webpDst;
487 if ((this->colorXform() && !is_8888(dstInfo.colorType())) || blendWithPrevFrame) {
488 // We will decode the entire image and then perform the color transform. libwebp
489 // does not provide a row-by-row API. This is a shame particularly when we do not want
490 // 8888, since we will need to create another image sized buffer.
491 webpDst.allocPixels(webpInfo);
492 } else {
493 // libwebp can decode directly into the output memory.
494 webpDst.installPixels(webpInfo, dst, rowBytes);
495 }
496
497 config.output.colorspace = webp_decode_mode(webpInfo.colorType(),
498 webpInfo.alphaType() == kPremul_SkAlphaType);
499 config.output.is_external_memory = 1;
500
501 config.output.u.RGBA.rgba = reinterpret_cast<uint8_t*>(webpDst.getAddr(dstX, dstY));
502 config.output.u.RGBA.stride = static_cast<int>(webpDst.rowBytes());
503 config.output.u.RGBA.size = webpDst.computeByteSize();
504
505 SkAutoTCallVProc<WebPIDecoder, WebPIDelete> idec(WebPIDecode(nullptr, 0, &config));
506 if (!idec) {
507 return kInvalidInput;
508 }
509
510 int rowsDecoded = 0;
512 switch (WebPIUpdate(idec, frame.fragment.bytes, frame.fragment.size)) {
513 case VP8_STATUS_OK:
514 rowsDecoded = scaledHeight;
516 break;
517 case VP8_STATUS_SUSPENDED:
518 if (!WebPIDecGetRGB(idec, &rowsDecoded, nullptr, nullptr, nullptr)
519 || rowsDecoded <= 0) {
520 return kInvalidInput;
521 }
522 *rowsDecodedPtr = rowsDecoded + dstY;
524 break;
525 default:
526 return kInvalidInput;
527 }
528
529 const size_t dstBpp = dstInfo.bytesPerPixel();
530 dst = SkTAddOffset<void>(dst, dstBpp * dstX + rowBytes * dstY);
531 const size_t srcRowBytes = config.output.u.RGBA.stride;
532
533 const auto dstCT = dstInfo.colorType();
534 if (this->colorXform()) {
535 uint32_t* xformSrc = (uint32_t*) config.output.u.RGBA.rgba;
536 SkBitmap tmp;
537 void* xformDst;
538
539 if (blendWithPrevFrame) {
540 // Xform into temporary bitmap big enough for one row.
541 tmp.allocPixels(dstInfo.makeWH(scaledWidth, 1));
542 xformDst = tmp.getPixels();
543 } else {
544 xformDst = dst;
545 }
546
547 for (int y = 0; y < rowsDecoded; y++) {
548 this->applyColorXform(xformDst, xformSrc, scaledWidth);
549 if (blendWithPrevFrame) {
550 blend_line(dstCT, dst, dstCT, xformDst,
551 dstInfo.alphaType(), frame.has_alpha, scaledWidth);
552 dst = SkTAddOffset<void>(dst, rowBytes);
553 } else {
554 xformDst = SkTAddOffset<void>(xformDst, rowBytes);
555 }
556 xformSrc = SkTAddOffset<uint32_t>(xformSrc, srcRowBytes);
557 }
558 } else if (blendWithPrevFrame) {
559 const uint8_t* src = config.output.u.RGBA.rgba;
560
561 for (int y = 0; y < rowsDecoded; y++) {
562 blend_line(dstCT, dst, webpDst.colorType(), src,
563 dstInfo.alphaType(), frame.has_alpha, scaledWidth);
564 src = SkTAddOffset<const uint8_t>(src, srcRowBytes);
565 dst = SkTAddOffset<void>(dst, rowBytes);
566 }
567 }
568
569 return result;
570}
571
572SkWebpCodec::SkWebpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
573 WebPDemuxer* demux, sk_sp<SkData> data, SkEncodedOrigin origin)
574 : INHERITED(std::move(info), skcms_PixelFormat_BGRA_8888, std::move(stream),
575 origin)
576 , fDemux(demux)
577 , fData(std::move(data))
578 , fFailed(false)
579{
580 const auto& eInfo = this->getEncodedInfo();
581 fFrameHolder.setScreenSize(eInfo.width(), eInfo.height());
582}
583
584namespace SkWebpDecoder {
585bool IsWebp(const void* data, size_t len) {
586 return SkWebpCodec::IsWebp(data, len);
587}
588
589std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream> stream,
590 SkCodec::Result* outResult,
591 SkCodecs::DecodeContext) {
592 SkCodec::Result resultStorage;
593 if (!outResult) {
594 outResult = &resultStorage;
595 }
596 return SkWebpCodec::MakeFromStream(std::move(stream), outResult);
597}
598
599std::unique_ptr<SkCodec> Decode(sk_sp<SkData> data,
600 SkCodec::Result* outResult,
601 SkCodecs::DecodeContext) {
602 if (!data) {
603 if (outResult) {
604 *outResult = SkCodec::kInvalidInput;
605 }
606 return nullptr;
607 }
608 return Decode(SkMemoryStream::Make(std::move(data)), outResult, nullptr);
609}
610} // namespace SkWebpDecoder
const char * options
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
SkColor4f color
kUnpremul_SkAlphaType
static constexpr bool SkIsAlign2(T x)
Definition SkAlign.h:19
SkAlphaType
Definition SkAlphaType.h:26
@ kOpaque_SkAlphaType
pixel is opaque
Definition SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkAssertResult(cond)
Definition SkAssert.h:123
#define SkASSERT(cond)
Definition SkAssert.h:116
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
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition SkColorType.h:22
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition SkColorType.h:24
SkEncodedOrigin
@ kDefault_SkEncodedOrigin
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static int64_t sk_64_mul(int64_t a, int64_t b)
Definition SkMath.h:33
static bool contains(const SkRect &r, SkPoint p)
bool SkParseEncodedOrigin(const void *data, size_t data_length, SkEncodedOrigin *orientation)
#define INHERITED(method,...)
sk_sp< SkData > SkCopyStreamToData(SkStream *stream)
Definition SkStream.cpp:937
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
static bool is_8888(SkColorType colorType)
static WEBP_CSP_MODE webp_decode_mode(SkColorType dstCT, bool premultiply)
static void blend_line(SkColorType dstCT, void *dst, SkColorType srcCT, const void *src, SkAlphaType dstAt, bool srcHasAlpha, int width)
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition SkBitmap.cpp:258
bool installPixels(const SkImageInfo &info, void *pixels, size_t rowBytes, void(*releaseProc)(void *addr, void *context), void *context)
Definition SkBitmap.cpp:323
size_t computeByteSize() const
Definition SkBitmap.h:293
void * getAddr(int x, int y) const
Definition SkBitmap.cpp:406
size_t rowBytes() const
Definition SkBitmap.h:238
SkColorType colorType() const
Definition SkBitmap.h:160
void * getPixels() const
Definition SkBitmap.h:283
bool getValidSubset(SkIRect *desiredSubset) const
Definition SkCodec.h:285
SkISize dimensions() const
Definition SkCodec.h:230
const SkImageInfo & dstInfo() const
Definition SkCodec.h:878
SkStream * stream()
Definition SkCodec.h:865
void applyColorXform(void *dst, const void *src, int count) const
Definition SkCodec.cpp:853
SkIRect bounds() const
Definition SkCodec.h:231
const SkEncodedInfo & getEncodedInfo() const
Definition SkCodec.h:788
@ kIncompleteInput
Definition SkCodec.h:84
@ kInvalidInput
Definition SkCodec.h:109
@ kSuccess
Definition SkCodec.h:80
static constexpr int kRepetitionCountInfinite
Definition SkCodec.h:759
bool colorXform() const
Definition SkCodec.h:906
static constexpr int kNoFrame
Definition SkCodec.h:650
const Options & options() const
Definition SkCodec.h:880
static sk_sp< SkData > MakeWithoutCopy(const void *data, size_t length)
Definition SkData.h:116
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition SkData.cpp:111
static std::unique_ptr< ICCProfile > Make(sk_sp< SkData >)
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
Definition SkStream.cpp:314
static void Fill(const SkImageInfo &info, void *dst, size_t rowBytes, SkCodec::ZeroInitialized zeroInit)
Definition SkSampler.cpp:20
virtual size_t getLength() const
Definition SkStream.h:137
virtual const void * getMemoryBase()
Definition SkStream.h:141
bool onGetFrameInfo(int, FrameInfo *) const override
int onGetFrameCount() override
static bool IsWebp(const void *, size_t)
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, Result *)
bool onGetValidSubset(SkIRect *) const override
int onGetRepetitionCount() override
Result onGetPixels(const SkImageInfo &, void *, size_t, const Options &, int *) override
double frame
Definition examples.cpp:31
AtkStateType state
FlutterSemanticsFlag flags
GAsyncResult * result
double y
SK_API std::unique_ptr< SkCodec > Decode(std::unique_ptr< SkStream >, SkCodec::Result *, SkCodecs::DecodeContext=nullptr)
SK_API bool IsWebp(const void *, size_t)
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
Definition ref_ptr.h:256
int32_t height
int32_t width
@ skcms_PixelFormat_BGRA_8888
@ skcms_Signature_RGB
const SkIRect * fSubset
Definition SkCodec.h:347
ZeroInitialized fZeroInitialized
Definition SkCodec.h:329
static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha, int bitsPerComponent)
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
static bool Intersects(const SkIRect &a, const SkIRect &b)
Definition SkRect.h:535
constexpr SkISize size() const
Definition SkRect.h:172
constexpr int32_t height() const
Definition SkRect.h:165
int32_t fTop
smaller y-axis bounds
Definition SkRect.h:34
constexpr int32_t width() const
Definition SkRect.h:158
void offset(int32_t dx, int32_t dy)
Definition SkRect.h:367
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
int32_t fLeft
smaller x-axis bounds
Definition SkRect.h:33
constexpr int32_t width() const
Definition SkSize.h:36
constexpr int32_t height() const
Definition SkSize.h:37
SkImageInfo makeWH(int newWidth, int newHeight) const
SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const
int bytesPerPixel() const
SkISize dimensions() const
int width() const
SkAlphaType alphaType() const
SkColorType colorType() const
int height() const
SkImageInfo makeColorType(SkColorType newColorType) const