1 /*
2 * Copyright 2018 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 "src/codec/SkWuffsCodec.h"
9
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkPaint.h"
13 #include "include/private/SkMalloc.h"
14 #include "src/codec/SkFrameHolder.h"
15 #include "src/codec/SkSampler.h"
16 #include "src/codec/SkScalingCodec.h"
17 #include "src/core/SkDraw.h"
18 #include "src/core/SkMatrixProvider.h"
19 #include "src/core/SkRasterClip.h"
20 #include "src/core/SkStreamPriv.h"
21 #include "src/core/SkUtils.h"
22
23 #include <limits.h>
24
25 // Documentation on the Wuffs language and standard library (in general) and
26 // its image decoding API (in particular) is at:
27 //
28 // - https://github.com/google/wuffs/tree/master/doc
29 // - https://github.com/google/wuffs/blob/master/doc/std/image-decoders.md
30
31 // Wuffs ships as a "single file C library" or "header file library" as per
32 // https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
33 //
34 // As we have not #define'd WUFFS_IMPLEMENTATION, the #include here is
35 // including a header file, even though that file name ends in ".c".
36 #if defined(WUFFS_IMPLEMENTATION)
37 #error "SkWuffsCodec should not #define WUFFS_IMPLEMENTATION"
38 #endif
39 #include "wuffs-v0.3.c"
40 // Commit count 2514 is Wuffs 0.3.0-alpha.4.
41 #if WUFFS_VERSION_BUILD_METADATA_COMMIT_COUNT < 2514
42 #error "Wuffs version is too old. Upgrade to the latest version."
43 #endif
44
45 #define SK_WUFFS_CODEC_BUFFER_SIZE 4096
46
47 // Configuring a Skia build with
48 // SK_WUFFS_FAVORS_PERFORMANCE_OVER_ADDITIONAL_MEMORY_SAFETY can improve decode
49 // performance by some fixed amount (independent of the image size), which can
50 // be a noticeable proportional improvement if the input is relatively small.
51 //
52 // The Wuffs library is still memory-safe either way, in that there are no
53 // out-of-bounds reads or writes, and the library endeavours not to read
54 // uninitialized memory. There are just fewer compiler-enforced guarantees
55 // against reading uninitialized memory. For more detail, see
56 // https://github.com/google/wuffs/blob/master/doc/note/initialization.md#partial-zero-initialization
57 #if defined(SK_WUFFS_FAVORS_PERFORMANCE_OVER_ADDITIONAL_MEMORY_SAFETY)
58 #define SK_WUFFS_INITIALIZE_FLAGS WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED
59 #else
60 #define SK_WUFFS_INITIALIZE_FLAGS WUFFS_INITIALIZE__DEFAULT_OPTIONS
61 #endif
62
fill_buffer(wuffs_base__io_buffer * b,SkStream * s)63 static bool fill_buffer(wuffs_base__io_buffer* b, SkStream* s) {
64 b->compact();
65 size_t num_read = s->read(b->data.ptr + b->meta.wi, b->data.len - b->meta.wi);
66 b->meta.wi += num_read;
67 b->meta.closed = s->isAtEnd();
68 return num_read > 0;
69 }
70
seek_buffer(wuffs_base__io_buffer * b,SkStream * s,uint64_t pos)71 static bool seek_buffer(wuffs_base__io_buffer* b, SkStream* s, uint64_t pos) {
72 // Try to re-position the io_buffer's meta.ri read-index first, which is
73 // cheaper than seeking in the backing SkStream.
74 if ((pos >= b->meta.pos) && (pos - b->meta.pos <= b->meta.wi)) {
75 b->meta.ri = pos - b->meta.pos;
76 return true;
77 }
78 // Seek in the backing SkStream.
79 if ((pos > SIZE_MAX) || (!s->seek(pos))) {
80 return false;
81 }
82 b->meta.wi = 0;
83 b->meta.ri = 0;
84 b->meta.pos = pos;
85 b->meta.closed = false;
86 return true;
87 }
88
wuffs_disposal_to_skia_disposal(wuffs_base__animation_disposal w)89 static SkCodecAnimation::DisposalMethod wuffs_disposal_to_skia_disposal(
90 wuffs_base__animation_disposal w) {
91 switch (w) {
92 case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_BACKGROUND:
93 return SkCodecAnimation::DisposalMethod::kRestoreBGColor;
94 case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS:
95 return SkCodecAnimation::DisposalMethod::kRestorePrevious;
96 default:
97 return SkCodecAnimation::DisposalMethod::kKeep;
98 }
99 }
100
to_alpha_type(bool opaque)101 static SkAlphaType to_alpha_type(bool opaque) {
102 return opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
103 }
104
reset_and_decode_image_config(wuffs_gif__decoder * decoder,wuffs_base__image_config * imgcfg,wuffs_base__io_buffer * b,SkStream * s)105 static SkCodec::Result reset_and_decode_image_config(wuffs_gif__decoder* decoder,
106 wuffs_base__image_config* imgcfg,
107 wuffs_base__io_buffer* b,
108 SkStream* s) {
109 // Calling decoder->initialize will memset most or all of it to zero,
110 // depending on SK_WUFFS_INITIALIZE_FLAGS.
111 wuffs_base__status status =
112 decoder->initialize(sizeof__wuffs_gif__decoder(), WUFFS_VERSION, SK_WUFFS_INITIALIZE_FLAGS);
113 if (status.repr != nullptr) {
114 SkCodecPrintf("initialize: %s", status.message());
115 return SkCodec::kInternalError;
116 }
117
118 // See https://bugs.chromium.org/p/skia/issues/detail?id=12055
119 decoder->set_quirk_enabled(WUFFS_GIF__QUIRK_IGNORE_TOO_MUCH_PIXEL_DATA, true);
120
121 while (true) {
122 status = decoder->decode_image_config(imgcfg, b);
123 if (status.repr == nullptr) {
124 break;
125 } else if (status.repr != wuffs_base__suspension__short_read) {
126 SkCodecPrintf("decode_image_config: %s", status.message());
127 return SkCodec::kErrorInInput;
128 } else if (!fill_buffer(b, s)) {
129 return SkCodec::kIncompleteInput;
130 }
131 }
132
133 // A GIF image's natural color model is indexed color: 1 byte per pixel,
134 // indexing a 256-element palette.
135 //
136 // For Skia, we override that to decode to 4 bytes per pixel, BGRA or RGBA.
137 uint32_t pixfmt = WUFFS_BASE__PIXEL_FORMAT__INVALID;
138 switch (kN32_SkColorType) {
139 case kBGRA_8888_SkColorType:
140 pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL;
141 break;
142 case kRGBA_8888_SkColorType:
143 pixfmt = WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL;
144 break;
145 default:
146 return SkCodec::kInternalError;
147 }
148 if (imgcfg) {
149 imgcfg->pixcfg.set(pixfmt, WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, imgcfg->pixcfg.width(),
150 imgcfg->pixcfg.height());
151 }
152
153 return SkCodec::kSuccess;
154 }
155
156 // -------------------------------- Class definitions
157
158 class SkWuffsCodec;
159
160 class SkWuffsFrame final : public SkFrame {
161 public:
162 SkWuffsFrame(wuffs_base__frame_config* fc);
163
164 uint64_t ioPosition() const;
165
166 // SkFrame overrides.
167 SkEncodedInfo::Alpha onReportedAlpha() const override;
168
169 private:
170 uint64_t fIOPosition;
171 SkEncodedInfo::Alpha fReportedAlpha;
172
173 using INHERITED = SkFrame;
174 };
175
176 // SkWuffsFrameHolder is a trivial indirector that forwards its calls onto a
177 // SkWuffsCodec. It is a separate class as SkWuffsCodec would otherwise
178 // inherit from both SkCodec and SkFrameHolder, and Skia style discourages
179 // multiple inheritance (e.g. with its "typedef Foo INHERITED" convention).
180 class SkWuffsFrameHolder final : public SkFrameHolder {
181 public:
SkWuffsFrameHolder()182 SkWuffsFrameHolder() : INHERITED() {}
183
184 void init(SkWuffsCodec* codec, int width, int height);
185
186 // SkFrameHolder overrides.
187 const SkFrame* onGetFrame(int i) const override;
188
189 private:
190 const SkWuffsCodec* fCodec;
191
192 using INHERITED = SkFrameHolder;
193 };
194
195 class SkWuffsCodec final : public SkScalingCodec {
196 public:
197 SkWuffsCodec(SkEncodedInfo&& encodedInfo,
198 std::unique_ptr<SkStream> stream,
199 std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> dec,
200 std::unique_ptr<uint8_t, decltype(&sk_free)> workbuf_ptr,
201 size_t workbuf_len,
202 wuffs_base__image_config imgcfg,
203 wuffs_base__io_buffer iobuf);
204
205 const SkWuffsFrame* frame(int i) const;
206
207 private:
208 // SkCodec overrides.
209 SkEncodedImageFormat onGetEncodedFormat() const override;
210 Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, int*) override;
211 const SkFrameHolder* getFrameHolder() const override;
212 Result onStartIncrementalDecode(const SkImageInfo& dstInfo,
213 void* dst,
214 size_t rowBytes,
215 const SkCodec::Options& options) override;
216 Result onIncrementalDecode(int* rowsDecoded) override;
217 int onGetFrameCount() override;
218 bool onGetFrameInfo(int, FrameInfo*) const override;
219 int onGetRepetitionCount() override;
220
221 // Two separate implementations of onStartIncrementalDecode and
222 // onIncrementalDecode, named "one pass" and "two pass" decoding. One pass
223 // decoding writes directly from the Wuffs image decoder to the dst buffer
224 // (the dst argument to onStartIncrementalDecode). Two pass decoding first
225 // writes into an intermediate buffer, and then composites and transforms
226 // the intermediate buffer into the dst buffer.
227 //
228 // In the general case, we need the two pass decoder, because of Skia API
229 // features that Wuffs doesn't support (e.g. color correction, scaling,
230 // RGB565). But as an optimization, we use one pass decoding (it's faster
231 // and uses less memory) if applicable (see the assignment to
232 // fIncrDecOnePass that calculates when we can do so).
233 Result onStartIncrementalDecodeOnePass(const SkImageInfo& dstInfo,
234 uint8_t* dst,
235 size_t rowBytes,
236 const SkCodec::Options& options,
237 uint32_t pixelFormat,
238 size_t bytesPerPixel);
239 Result onStartIncrementalDecodeTwoPass();
240 Result onIncrementalDecodeOnePass();
241 Result onIncrementalDecodeTwoPass();
242
243 void onGetFrameCountInternal();
244 Result seekFrame(int frameIndex);
245 Result resetDecoder();
246 const char* decodeFrameConfig();
247 const char* decodeFrame();
248 void updateNumFullyReceivedFrames();
249
250 SkWuffsFrameHolder fFrameHolder;
251 std::unique_ptr<SkStream> fStream;
252 std::unique_ptr<uint8_t, decltype(&sk_free)> fWorkbufPtr;
253 size_t fWorkbufLen;
254
255 std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> fDecoder;
256
257 const uint64_t fFirstFrameIOPosition;
258 wuffs_base__frame_config fFrameConfig;
259 wuffs_base__pixel_config fPixelConfig;
260 wuffs_base__pixel_buffer fPixelBuffer;
261 wuffs_base__io_buffer fIOBuffer;
262
263 // Incremental decoding state.
264 uint8_t* fIncrDecDst;
265 size_t fIncrDecRowBytes;
266 wuffs_base__pixel_blend fIncrDecPixelBlend;
267 bool fIncrDecOnePass;
268 bool fFirstCallToIncrementalDecode;
269
270 // Lazily allocated intermediate pixel buffer, for two pass decoding.
271 std::unique_ptr<uint8_t, decltype(&sk_free)> fTwoPassPixbufPtr;
272 size_t fTwoPassPixbufLen;
273
274 uint64_t fNumFullyReceivedFrames;
275 std::vector<SkWuffsFrame> fFrames;
276 bool fFramesComplete;
277
278 // If calling an fDecoder method returns an incomplete status, then
279 // fDecoder is suspended in a coroutine (i.e. waiting on I/O or halted on a
280 // non-recoverable error). To keep its internal proof-of-safety invariants
281 // consistent, there's only two things you can safely do with a suspended
282 // Wuffs object: resume the coroutine, or reset all state (memset to zero
283 // and start again).
284 //
285 // If fDecoderIsSuspended, and we aren't sure that we're going to resume
286 // the coroutine, then we will need to call this->resetDecoder before
287 // calling other fDecoder methods.
288 bool fDecoderIsSuspended;
289
290 uint8_t fBuffer[SK_WUFFS_CODEC_BUFFER_SIZE];
291
292 using INHERITED = SkScalingCodec;
293 };
294
295 // -------------------------------- SkWuffsFrame implementation
296
SkWuffsFrame(wuffs_base__frame_config * fc)297 SkWuffsFrame::SkWuffsFrame(wuffs_base__frame_config* fc)
298 : INHERITED(fc->index()),
299 fIOPosition(fc->io_position()),
300 fReportedAlpha(fc->opaque_within_bounds() ? SkEncodedInfo::kOpaque_Alpha
301 : SkEncodedInfo::kUnpremul_Alpha) {
302 wuffs_base__rect_ie_u32 r = fc->bounds();
303 this->setXYWH(r.min_incl_x, r.min_incl_y, r.width(), r.height());
304 this->setDisposalMethod(wuffs_disposal_to_skia_disposal(fc->disposal()));
305 this->setDuration(fc->duration() / WUFFS_BASE__FLICKS_PER_MILLISECOND);
306 this->setBlend(fc->overwrite_instead_of_blend() ? SkCodecAnimation::Blend::kSrc
307 : SkCodecAnimation::Blend::kSrcOver);
308 }
309
ioPosition() const310 uint64_t SkWuffsFrame::ioPosition() const {
311 return fIOPosition;
312 }
313
onReportedAlpha() const314 SkEncodedInfo::Alpha SkWuffsFrame::onReportedAlpha() const {
315 return fReportedAlpha;
316 }
317
318 // -------------------------------- SkWuffsFrameHolder implementation
319
init(SkWuffsCodec * codec,int width,int height)320 void SkWuffsFrameHolder::init(SkWuffsCodec* codec, int width, int height) {
321 fCodec = codec;
322 // Initialize SkFrameHolder's (the superclass) fields.
323 fScreenWidth = width;
324 fScreenHeight = height;
325 }
326
onGetFrame(int i) const327 const SkFrame* SkWuffsFrameHolder::onGetFrame(int i) const {
328 return fCodec->frame(i);
329 };
330
331 // -------------------------------- SkWuffsCodec implementation
332
SkWuffsCodec(SkEncodedInfo && encodedInfo,std::unique_ptr<SkStream> stream,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)333 SkWuffsCodec::SkWuffsCodec(SkEncodedInfo&& encodedInfo,
334 std::unique_ptr<SkStream> stream,
335 std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> dec,
336 std::unique_ptr<uint8_t, decltype(&sk_free)> workbuf_ptr,
337 size_t workbuf_len,
338 wuffs_base__image_config imgcfg,
339 wuffs_base__io_buffer iobuf)
340 : INHERITED(std::move(encodedInfo),
341 skcms_PixelFormat_RGBA_8888,
342 // Pass a nullptr SkStream to the SkCodec constructor. We
343 // manage the stream ourselves, as the default SkCodec behavior
344 // is too trigger-happy on rewinding the stream.
345 nullptr),
346 fFrameHolder(),
347 fStream(std::move(stream)),
348 fWorkbufPtr(std::move(workbuf_ptr)),
349 fWorkbufLen(workbuf_len),
350 fDecoder(std::move(dec)),
351 fFirstFrameIOPosition(imgcfg.first_frame_io_position()),
352 fFrameConfig(wuffs_base__null_frame_config()),
353 fPixelConfig(imgcfg.pixcfg),
354 fPixelBuffer(wuffs_base__null_pixel_buffer()),
355 fIOBuffer(wuffs_base__empty_io_buffer()),
356 fIncrDecDst(nullptr),
357 fIncrDecRowBytes(0),
358 fIncrDecPixelBlend(WUFFS_BASE__PIXEL_BLEND__SRC),
359 fIncrDecOnePass(false),
360 fFirstCallToIncrementalDecode(false),
361 fTwoPassPixbufPtr(nullptr, &sk_free),
362 fTwoPassPixbufLen(0),
363 fNumFullyReceivedFrames(0),
364 fFramesComplete(false),
365 fDecoderIsSuspended(false) {
366 fFrameHolder.init(this, imgcfg.pixcfg.width(), imgcfg.pixcfg.height());
367
368 // Initialize fIOBuffer's fields, copying any outstanding data from iobuf to
369 // fIOBuffer, as iobuf's backing array may not be valid for the lifetime of
370 // this SkWuffsCodec object, but fIOBuffer's backing array (fBuffer) is.
371 SkASSERT(iobuf.data.len == SK_WUFFS_CODEC_BUFFER_SIZE);
372 memmove(fBuffer, iobuf.data.ptr, iobuf.meta.wi);
373 fIOBuffer.data = wuffs_base__make_slice_u8(fBuffer, SK_WUFFS_CODEC_BUFFER_SIZE);
374 fIOBuffer.meta = iobuf.meta;
375 }
376
frame(int i) const377 const SkWuffsFrame* SkWuffsCodec::frame(int i) const {
378 if ((0 <= i) && (static_cast<size_t>(i) < fFrames.size())) {
379 return &fFrames[i];
380 }
381 return nullptr;
382 }
383
onGetEncodedFormat() const384 SkEncodedImageFormat SkWuffsCodec::onGetEncodedFormat() const {
385 return SkEncodedImageFormat::kGIF;
386 }
387
onGetPixels(const SkImageInfo & dstInfo,void * dst,size_t rowBytes,const Options & options,int * rowsDecoded)388 SkCodec::Result SkWuffsCodec::onGetPixels(const SkImageInfo& dstInfo,
389 void* dst,
390 size_t rowBytes,
391 const Options& options,
392 int* rowsDecoded) {
393 SkCodec::Result result = this->onStartIncrementalDecode(dstInfo, dst, rowBytes, options);
394 if (result != kSuccess) {
395 return result;
396 }
397 return this->onIncrementalDecode(rowsDecoded);
398 }
399
getFrameHolder() const400 const SkFrameHolder* SkWuffsCodec::getFrameHolder() const {
401 return &fFrameHolder;
402 }
403
onStartIncrementalDecode(const SkImageInfo & dstInfo,void * dst,size_t rowBytes,const SkCodec::Options & options)404 SkCodec::Result SkWuffsCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo,
405 void* dst,
406 size_t rowBytes,
407 const SkCodec::Options& options) {
408 if (!dst) {
409 return SkCodec::kInvalidParameters;
410 }
411 if (options.fSubset) {
412 return SkCodec::kUnimplemented;
413 }
414 SkCodec::Result result = this->seekFrame(options.fFrameIndex);
415 if (result != SkCodec::kSuccess) {
416 return result;
417 }
418
419 const char* status = this->decodeFrameConfig();
420 if (status == wuffs_base__suspension__short_read) {
421 return SkCodec::kIncompleteInput;
422 } else if (status != nullptr) {
423 SkCodecPrintf("decodeFrameConfig: %s", status);
424 return SkCodec::kErrorInInput;
425 }
426
427 uint32_t pixelFormat = WUFFS_BASE__PIXEL_FORMAT__INVALID;
428 size_t bytesPerPixel = 0;
429
430 switch (dstInfo.colorType()) {
431 case kRGB_565_SkColorType:
432 pixelFormat = WUFFS_BASE__PIXEL_FORMAT__BGR_565;
433 bytesPerPixel = 2;
434 break;
435 case kBGRA_8888_SkColorType:
436 pixelFormat = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL;
437 bytesPerPixel = 4;
438 break;
439 case kRGBA_8888_SkColorType:
440 pixelFormat = WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL;
441 bytesPerPixel = 4;
442 break;
443 default:
444 break;
445 }
446
447 // We can use "one pass" decoding if we have a Skia pixel format that Wuffs
448 // supports...
449 fIncrDecOnePass = (pixelFormat != WUFFS_BASE__PIXEL_FORMAT__INVALID) &&
450 // ...and no color profile (as Wuffs does not support them)...
451 (!getEncodedInfo().profile()) &&
452 // ...and we use the identity transform (as Wuffs does
453 // not support scaling).
454 (this->dimensions() == dstInfo.dimensions());
455
456 result = fIncrDecOnePass ? this->onStartIncrementalDecodeOnePass(
457 dstInfo, static_cast<uint8_t*>(dst), rowBytes, options,
458 pixelFormat, bytesPerPixel)
459 : this->onStartIncrementalDecodeTwoPass();
460 if (result != SkCodec::kSuccess) {
461 return result;
462 }
463
464 fIncrDecDst = static_cast<uint8_t*>(dst);
465 fIncrDecRowBytes = rowBytes;
466 fFirstCallToIncrementalDecode = true;
467 return SkCodec::kSuccess;
468 }
469
onStartIncrementalDecodeOnePass(const SkImageInfo & dstInfo,uint8_t * dst,size_t rowBytes,const SkCodec::Options & options,uint32_t pixelFormat,size_t bytesPerPixel)470 SkCodec::Result SkWuffsCodec::onStartIncrementalDecodeOnePass(const SkImageInfo& dstInfo,
471 uint8_t* dst,
472 size_t rowBytes,
473 const SkCodec::Options& options,
474 uint32_t pixelFormat,
475 size_t bytesPerPixel) {
476 wuffs_base__pixel_config pixelConfig;
477 pixelConfig.set(pixelFormat, WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, dstInfo.width(),
478 dstInfo.height());
479
480 wuffs_base__table_u8 table;
481 table.ptr = dst;
482 table.width = static_cast<size_t>(dstInfo.width()) * bytesPerPixel;
483 table.height = dstInfo.height();
484 table.stride = rowBytes;
485
486 wuffs_base__status status = fPixelBuffer.set_from_table(&pixelConfig, table);
487 if (status.repr != nullptr) {
488 SkCodecPrintf("set_from_table: %s", status.message());
489 return SkCodec::kInternalError;
490 }
491
492 // SRC is usually faster than SRC_OVER, but for a dependent frame, dst is
493 // assumed to hold the previous frame's pixels (after processing the
494 // DisposalMethod). For one-pass decoding, we therefore use SRC_OVER.
495 if ((options.fFrameIndex != 0) &&
496 (this->frame(options.fFrameIndex)->getRequiredFrame() != SkCodec::kNoFrame)) {
497 fIncrDecPixelBlend = WUFFS_BASE__PIXEL_BLEND__SRC_OVER;
498 } else {
499 SkSampler::Fill(dstInfo, dst, rowBytes, options.fZeroInitialized);
500 fIncrDecPixelBlend = WUFFS_BASE__PIXEL_BLEND__SRC;
501 }
502
503 return SkCodec::kSuccess;
504 }
505
onStartIncrementalDecodeTwoPass()506 SkCodec::Result SkWuffsCodec::onStartIncrementalDecodeTwoPass() {
507 // Either re-use the previously allocated "two pass" pixel buffer (and
508 // memset to zero), or allocate (and zero initialize) a new one.
509 bool already_zeroed = false;
510
511 if (!fTwoPassPixbufPtr) {
512 uint64_t pixbuf_len = fPixelConfig.pixbuf_len();
513 void* pixbuf_ptr_raw = (pixbuf_len <= SIZE_MAX)
514 ? sk_malloc_flags(pixbuf_len, SK_MALLOC_ZERO_INITIALIZE)
515 : nullptr;
516 if (!pixbuf_ptr_raw) {
517 return SkCodec::kInternalError;
518 }
519 fTwoPassPixbufPtr.reset(reinterpret_cast<uint8_t*>(pixbuf_ptr_raw));
520 fTwoPassPixbufLen = SkToSizeT(pixbuf_len);
521 already_zeroed = true;
522 }
523
524 wuffs_base__status status = fPixelBuffer.set_from_slice(
525 &fPixelConfig, wuffs_base__make_slice_u8(fTwoPassPixbufPtr.get(), fTwoPassPixbufLen));
526 if (status.repr != nullptr) {
527 SkCodecPrintf("set_from_slice: %s", status.message());
528 return SkCodec::kInternalError;
529 }
530
531 if (!already_zeroed) {
532 uint32_t src_bits_per_pixel = fPixelConfig.pixel_format().bits_per_pixel();
533 if ((src_bits_per_pixel == 0) || (src_bits_per_pixel % 8 != 0)) {
534 return SkCodec::kInternalError;
535 }
536 size_t src_bytes_per_pixel = src_bits_per_pixel / 8;
537
538 wuffs_base__rect_ie_u32 frame_rect = fFrameConfig.bounds();
539 wuffs_base__table_u8 pixels = fPixelBuffer.plane(0);
540
541 uint8_t* ptr = pixels.ptr + (frame_rect.min_incl_y * pixels.stride) +
542 (frame_rect.min_incl_x * src_bytes_per_pixel);
543 size_t len = frame_rect.width() * src_bytes_per_pixel;
544
545 // As an optimization, issue a single sk_bzero call, if possible.
546 // Otherwise, zero out each row separately.
547 if ((len == pixels.stride) && (frame_rect.min_incl_y < frame_rect.max_excl_y)) {
548 sk_bzero(ptr, len * (frame_rect.max_excl_y - frame_rect.min_incl_y));
549 } else {
550 for (uint32_t y = frame_rect.min_incl_y; y < frame_rect.max_excl_y; y++) {
551 sk_bzero(ptr, len);
552 ptr += pixels.stride;
553 }
554 }
555 }
556
557 fIncrDecPixelBlend = WUFFS_BASE__PIXEL_BLEND__SRC;
558 return SkCodec::kSuccess;
559 }
560
onIncrementalDecode(int * rowsDecoded)561 SkCodec::Result SkWuffsCodec::onIncrementalDecode(int* rowsDecoded) {
562 if (!fIncrDecDst) {
563 return SkCodec::kInternalError;
564 }
565
566 if (rowsDecoded) {
567 *rowsDecoded = dstInfo().height();
568 }
569
570 SkCodec::Result result =
571 fIncrDecOnePass ? this->onIncrementalDecodeOnePass() : this->onIncrementalDecodeTwoPass();
572 if (result == SkCodec::kSuccess) {
573 fIncrDecDst = nullptr;
574 fIncrDecRowBytes = 0;
575 fIncrDecPixelBlend = WUFFS_BASE__PIXEL_BLEND__SRC;
576 fIncrDecOnePass = false;
577 }
578 return result;
579 }
580
onIncrementalDecodeOnePass()581 SkCodec::Result SkWuffsCodec::onIncrementalDecodeOnePass() {
582 const char* status = this->decodeFrame();
583 if (status != nullptr) {
584 if (status == wuffs_base__suspension__short_read) {
585 return SkCodec::kIncompleteInput;
586 } else {
587 SkCodecPrintf("decodeFrame: %s", status);
588 return SkCodec::kErrorInInput;
589 }
590 }
591 return SkCodec::kSuccess;
592 }
593
onIncrementalDecodeTwoPass()594 SkCodec::Result SkWuffsCodec::onIncrementalDecodeTwoPass() {
595 SkCodec::Result result = SkCodec::kSuccess;
596 const char* status = this->decodeFrame();
597 bool independent;
598 SkAlphaType alphaType;
599 const int index = options().fFrameIndex;
600 if (index == 0) {
601 independent = true;
602 alphaType = to_alpha_type(getEncodedInfo().opaque());
603 } else {
604 const SkWuffsFrame* f = this->frame(index);
605 independent = f->getRequiredFrame() == SkCodec::kNoFrame;
606 alphaType = to_alpha_type(f->reportedAlpha() == SkEncodedInfo::kOpaque_Alpha);
607 }
608 if (status != nullptr) {
609 if (status == wuffs_base__suspension__short_read) {
610 result = SkCodec::kIncompleteInput;
611 } else {
612 SkCodecPrintf("decodeFrame: %s", status);
613 result = SkCodec::kErrorInInput;
614 }
615
616 if (!independent) {
617 // For a dependent frame, we cannot blend the partial result, since
618 // that will overwrite the contribution from prior frames.
619 return result;
620 }
621 }
622
623 uint32_t src_bits_per_pixel = fPixelBuffer.pixcfg.pixel_format().bits_per_pixel();
624 if ((src_bits_per_pixel == 0) || (src_bits_per_pixel % 8 != 0)) {
625 return SkCodec::kInternalError;
626 }
627 size_t src_bytes_per_pixel = src_bits_per_pixel / 8;
628
629 wuffs_base__rect_ie_u32 frame_rect = fFrameConfig.bounds();
630 if (fFirstCallToIncrementalDecode) {
631 if (frame_rect.width() > (SIZE_MAX / src_bytes_per_pixel)) {
632 return SkCodec::kInternalError;
633 }
634
635 auto bounds = SkIRect::MakeLTRB(frame_rect.min_incl_x, frame_rect.min_incl_y,
636 frame_rect.max_excl_x, frame_rect.max_excl_y);
637
638 // If the frame rect does not fill the output, ensure that those pixels are not
639 // left uninitialized.
640 if (independent && (bounds != this->bounds() || result != kSuccess)) {
641 SkSampler::Fill(dstInfo(), fIncrDecDst, fIncrDecRowBytes, options().fZeroInitialized);
642 }
643 fFirstCallToIncrementalDecode = false;
644 } else {
645 // Existing clients intend to only show frames beyond the first if they
646 // are complete (based on FrameInfo::fFullyReceived), since it might
647 // look jarring to draw a partial frame over an existing frame. If they
648 // changed their behavior and expected to continue decoding a partial
649 // frame after the first one, we'll need to update our blending code.
650 // Otherwise, if the frame were interlaced and not independent, the
651 // second pass may have an overlapping dirty_rect with the first,
652 // resulting in blending with the first pass.
653 SkASSERT(index == 0);
654 }
655
656 // If the frame's dirty rect is empty, no need to swizzle.
657 wuffs_base__rect_ie_u32 dirty_rect = fDecoder->frame_dirty_rect();
658 if (!dirty_rect.is_empty()) {
659 wuffs_base__table_u8 pixels = fPixelBuffer.plane(0);
660
661 // The Wuffs model is that the dst buffer is the image, not the frame.
662 // The expectation is that you allocate the buffer once, but re-use it
663 // for the N frames, regardless of each frame's top-left co-ordinate.
664 //
665 // To get from the start (in the X-direction) of the image to the start
666 // of the dirty_rect, we adjust s by (dirty_rect.min_incl_x * src_bytes_per_pixel).
667 uint8_t* s = pixels.ptr + (dirty_rect.min_incl_y * pixels.stride) +
668 (dirty_rect.min_incl_x * src_bytes_per_pixel);
669
670 // Currently, this is only used for GIF, which will never have an ICC profile. When it is
671 // used for other formats that might have one, we will need to transform from profiles that
672 // do not have corresponding SkColorSpaces.
673 SkASSERT(!getEncodedInfo().profile());
674
675 auto srcInfo =
676 getInfo().makeWH(dirty_rect.width(), dirty_rect.height()).makeAlphaType(alphaType);
677 SkBitmap src;
678 src.installPixels(srcInfo, s, pixels.stride);
679 SkPaint paint;
680 if (independent) {
681 paint.setBlendMode(SkBlendMode::kSrc);
682 }
683
684 SkDraw draw;
685 draw.fDst.reset(dstInfo(), fIncrDecDst, fIncrDecRowBytes);
686 SkMatrix matrix = SkMatrix::RectToRect(SkRect::Make(this->dimensions()),
687 SkRect::Make(this->dstInfo().dimensions()));
688 SkMatrixProvider matrixProvider(matrix);
689 draw.fMatrixProvider = &matrixProvider;
690 SkRasterClip rc(SkIRect::MakeSize(this->dstInfo().dimensions()));
691 draw.fRC = &rc;
692
693 SkMatrix translate = SkMatrix::Translate(dirty_rect.min_incl_x, dirty_rect.min_incl_y);
694 draw.drawBitmap(src, translate, nullptr, SkSamplingOptions(), paint);
695 }
696
697 if (result == SkCodec::kSuccess) {
698 // On success, we are done using the "two pass" pixel buffer for this
699 // frame. We have the option of releasing its memory, but there is a
700 // trade-off. If decoding a subsequent frame will also need "two pass"
701 // decoding, it would have to re-allocate the buffer instead of just
702 // re-using it. On the other hand, if there is no subsequent frame, and
703 // the SkWuffsCodec object isn't deleted soon, then we are holding
704 // megabytes of memory longer than we need to.
705 //
706 // For example, when the Chromium web browser decodes the <img> tags in
707 // a HTML page, the SkCodec object can live until navigating away from
708 // the page, which can be much longer than when the pixels are fully
709 // decoded, especially for a still (non-animated) image. Even for
710 // looping animations, caching the decoded frames (at the higher HTML
711 // renderer layer) may mean that each frame is only decoded once (at
712 // the lower SkCodec layer), in sequence.
713 //
714 // The heuristic we use here is to free the memory if we have decoded
715 // the last frame of the animation (or, for still images, the only
716 // frame). The output of the next decode request (if any) should be the
717 // same either way, but the steady state memory use should hopefully be
718 // lower than always keeping the fTwoPassPixbufPtr buffer up until the
719 // SkWuffsCodec destructor runs.
720 //
721 // This only applies to "two pass" decoding. "One pass" decoding does
722 // not allocate, free or otherwise use fTwoPassPixbufPtr.
723 if (fFramesComplete && (static_cast<size_t>(options().fFrameIndex) == fFrames.size() - 1)) {
724 fTwoPassPixbufPtr.reset(nullptr);
725 fTwoPassPixbufLen = 0;
726 }
727 }
728
729 return result;
730 }
731
onGetFrameCount()732 int SkWuffsCodec::onGetFrameCount() {
733 // It is valid, in terms of the SkCodec API, to call SkCodec::getFrameCount
734 // while in an incremental decode (after onStartIncrementalDecode returns
735 // and before onIncrementalDecode returns kSuccess).
736 //
737 // We should not advance the SkWuffsCodec' stream while doing so, even
738 // though other SkCodec implementations can return increasing values from
739 // onGetFrameCount when given more data. If we tried to do so, the
740 // subsequent resume of the incremental decode would continue reading from
741 // a different position in the I/O stream, leading to an incorrect error.
742 //
743 // Other SkCodec implementations can move the stream forward during
744 // onGetFrameCount because they assume that the stream is rewindable /
745 // seekable. For example, an alternative GIF implementation may choose to
746 // store, for each frame walked past when merely counting the number of
747 // frames, the I/O position of each of the frame's GIF data blocks. (A GIF
748 // frame's compressed data can have multiple data blocks, each at most 255
749 // bytes in length). Obviously, this can require O(numberOfFrames) extra
750 // memory to store these I/O positions. The constant factor is small, but
751 // it's still O(N), not O(1).
752 //
753 // Wuffs and SkWuffsCodec try to minimize relying on the rewindable /
754 // seekable assumption. By design, Wuffs per se aims for O(1) memory use
755 // (after any pixel buffers are allocated) instead of O(N), and its I/O
756 // type, wuffs_base__io_buffer, is not necessarily rewindable or seekable.
757 //
758 // The Wuffs API provides a limited, optional form of seeking, to the start
759 // of an animation frame's data, but does not provide arbitrary save and
760 // load of its internal state whilst in the middle of an animation frame.
761 bool incrementalDecodeIsInProgress = fIncrDecDst != nullptr;
762
763 if (!fFramesComplete && !incrementalDecodeIsInProgress) {
764 this->onGetFrameCountInternal();
765 this->updateNumFullyReceivedFrames();
766 }
767 return fFrames.size();
768 }
769
onGetFrameCountInternal()770 void SkWuffsCodec::onGetFrameCountInternal() {
771 size_t n = fFrames.size();
772 int i = n ? n - 1 : 0;
773 if (this->seekFrame(i) != SkCodec::kSuccess) {
774 return;
775 }
776
777 // Iterate through the frames, converting from Wuffs'
778 // wuffs_base__frame_config type to Skia's SkWuffsFrame type.
779 for (; i < INT_MAX; i++) {
780 const char* status = this->decodeFrameConfig();
781 if (status == nullptr) {
782 // No-op.
783 } else if (status == wuffs_base__note__end_of_data) {
784 break;
785 } else {
786 return;
787 }
788
789 if (static_cast<size_t>(i) < fFrames.size()) {
790 continue;
791 }
792 fFrames.emplace_back(&fFrameConfig);
793 SkWuffsFrame* f = &fFrames[fFrames.size() - 1];
794 fFrameHolder.setAlphaAndRequiredFrame(f);
795 }
796
797 fFramesComplete = true;
798 }
799
onGetFrameInfo(int i,SkCodec::FrameInfo * frameInfo) const800 bool SkWuffsCodec::onGetFrameInfo(int i, SkCodec::FrameInfo* frameInfo) const {
801 const SkWuffsFrame* f = this->frame(i);
802 if (!f) {
803 return false;
804 }
805 if (frameInfo) {
806 f->fillIn(frameInfo, static_cast<uint64_t>(i) < this->fNumFullyReceivedFrames);
807 }
808 return true;
809 }
810
onGetRepetitionCount()811 int SkWuffsCodec::onGetRepetitionCount() {
812 // Convert from Wuffs's loop count to Skia's repeat count. Wuffs' uint32_t
813 // number is how many times to play the loop. Skia's int number is how many
814 // times to play the loop *after the first play*. Wuffs and Skia use 0 and
815 // kRepetitionCountInfinite respectively to mean loop forever.
816 uint32_t n = fDecoder->num_animation_loops();
817 if (n == 0) {
818 return SkCodec::kRepetitionCountInfinite;
819 }
820 n--;
821 return n < INT_MAX ? n : INT_MAX;
822 }
823
seekFrame(int frameIndex)824 SkCodec::Result SkWuffsCodec::seekFrame(int frameIndex) {
825 if (fDecoderIsSuspended) {
826 SkCodec::Result res = this->resetDecoder();
827 if (res != SkCodec::kSuccess) {
828 return res;
829 }
830 }
831
832 uint64_t pos = 0;
833 if (frameIndex < 0) {
834 return SkCodec::kInternalError;
835 } else if (frameIndex == 0) {
836 pos = fFirstFrameIOPosition;
837 } else if (static_cast<size_t>(frameIndex) < fFrames.size()) {
838 pos = fFrames[frameIndex].ioPosition();
839 } else {
840 return SkCodec::kInternalError;
841 }
842
843 if (!seek_buffer(&fIOBuffer, fStream.get(), pos)) {
844 return SkCodec::kInternalError;
845 }
846 wuffs_base__status status =
847 fDecoder->restart_frame(frameIndex, fIOBuffer.reader_io_position());
848 if (status.repr != nullptr) {
849 return SkCodec::kInternalError;
850 }
851 return SkCodec::kSuccess;
852 }
853
resetDecoder()854 SkCodec::Result SkWuffsCodec::resetDecoder() {
855 if (!fStream->rewind()) {
856 return SkCodec::kInternalError;
857 }
858 fIOBuffer.meta = wuffs_base__empty_io_buffer_meta();
859
860 SkCodec::Result result =
861 reset_and_decode_image_config(fDecoder.get(), nullptr, &fIOBuffer, fStream.get());
862 if (result == SkCodec::kIncompleteInput) {
863 return SkCodec::kInternalError;
864 } else if (result != SkCodec::kSuccess) {
865 return result;
866 }
867
868 fDecoderIsSuspended = false;
869 return SkCodec::kSuccess;
870 }
871
decodeFrameConfig()872 const char* SkWuffsCodec::decodeFrameConfig() {
873 while (true) {
874 wuffs_base__status status =
875 fDecoder->decode_frame_config(&fFrameConfig, &fIOBuffer);
876 if ((status.repr == wuffs_base__suspension__short_read) &&
877 fill_buffer(&fIOBuffer, fStream.get())) {
878 continue;
879 }
880 fDecoderIsSuspended = !status.is_complete();
881 this->updateNumFullyReceivedFrames();
882 return status.repr;
883 }
884 }
885
decodeFrame()886 const char* SkWuffsCodec::decodeFrame() {
887 while (true) {
888 wuffs_base__status status = fDecoder->decode_frame(
889 &fPixelBuffer, &fIOBuffer, fIncrDecPixelBlend,
890 wuffs_base__make_slice_u8(fWorkbufPtr.get(), fWorkbufLen), nullptr);
891 if ((status.repr == wuffs_base__suspension__short_read) &&
892 fill_buffer(&fIOBuffer, fStream.get())) {
893 continue;
894 }
895 fDecoderIsSuspended = !status.is_complete();
896 this->updateNumFullyReceivedFrames();
897 return status.repr;
898 }
899 }
900
updateNumFullyReceivedFrames()901 void SkWuffsCodec::updateNumFullyReceivedFrames() {
902 // num_decoded_frames's return value, n, can change over time, both up and
903 // down, as we seek back and forth in the underlying stream.
904 // fNumFullyReceivedFrames is the highest n we've seen.
905 uint64_t n = fDecoder->num_decoded_frames();
906 if (fNumFullyReceivedFrames < n) {
907 fNumFullyReceivedFrames = n;
908 }
909 }
910
911 // -------------------------------- SkWuffsCodec.h functions
912
SkWuffsCodec_IsFormat(const void * buf,size_t bytesRead)913 bool SkWuffsCodec_IsFormat(const void* buf, size_t bytesRead) {
914 constexpr const char* gif_ptr = "GIF8";
915 constexpr size_t gif_len = 4;
916 return (bytesRead >= gif_len) && (memcmp(buf, gif_ptr, gif_len) == 0);
917 }
918
SkWuffsCodec_MakeFromStream(std::unique_ptr<SkStream> stream,SkCodec::Result * result)919 std::unique_ptr<SkCodec> SkWuffsCodec_MakeFromStream(std::unique_ptr<SkStream> stream,
920 SkCodec::Result* result) {
921 // Some clients (e.g. Android) need to be able to seek the stream, but may
922 // not provide a seekable stream. Copy the stream to one that can seek.
923 if (!stream->hasPosition() || !stream->hasLength()) {
924 auto data = SkCopyStreamToData(stream.get());
925 stream.reset(new SkMemoryStream(std::move(data)));
926 }
927
928 uint8_t buffer[SK_WUFFS_CODEC_BUFFER_SIZE];
929 wuffs_base__io_buffer iobuf =
930 wuffs_base__make_io_buffer(wuffs_base__make_slice_u8(buffer, SK_WUFFS_CODEC_BUFFER_SIZE),
931 wuffs_base__empty_io_buffer_meta());
932 wuffs_base__image_config imgcfg = wuffs_base__null_image_config();
933
934 // Wuffs is primarily a C library, not a C++ one. Furthermore, outside of
935 // the wuffs_base__etc types, the sizeof a file format specific type like
936 // GIF's wuffs_gif__decoder can vary between Wuffs versions. If p is of
937 // type wuffs_gif__decoder*, then the supported API treats p as a pointer
938 // to an opaque type: a private implementation detail. The API is always
939 // "set_foo(p, etc)" and not "p->foo = etc".
940 //
941 // See https://en.wikipedia.org/wiki/Opaque_pointer#C
942 //
943 // Thus, we don't use C++'s new operator (which requires knowing the sizeof
944 // the struct at compile time). Instead, we use sk_malloc_canfail, with
945 // sizeof__wuffs_gif__decoder returning the appropriate value for the
946 // (statically or dynamically) linked version of the Wuffs library.
947 //
948 // As a C (not C++) library, none of the Wuffs types have constructors or
949 // destructors.
950 //
951 // In RAII style, we can still use std::unique_ptr with these pointers, but
952 // we pair the pointer with sk_free instead of C++'s delete.
953 void* decoder_raw = sk_malloc_canfail(sizeof__wuffs_gif__decoder());
954 if (!decoder_raw) {
955 *result = SkCodec::kInternalError;
956 return nullptr;
957 }
958 std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> decoder(
959 reinterpret_cast<wuffs_gif__decoder*>(decoder_raw), &sk_free);
960
961 SkCodec::Result reset_result =
962 reset_and_decode_image_config(decoder.get(), &imgcfg, &iobuf, stream.get());
963 if (reset_result != SkCodec::kSuccess) {
964 *result = reset_result;
965 return nullptr;
966 }
967
968 uint32_t width = imgcfg.pixcfg.width();
969 uint32_t height = imgcfg.pixcfg.height();
970 if ((width == 0) || (width > INT_MAX) || (height == 0) || (height > INT_MAX)) {
971 *result = SkCodec::kInvalidInput;
972 return nullptr;
973 }
974
975 uint64_t workbuf_len = decoder->workbuf_len().max_incl;
976 void* workbuf_ptr_raw = nullptr;
977 if (workbuf_len) {
978 workbuf_ptr_raw = workbuf_len <= SIZE_MAX ? sk_malloc_canfail(workbuf_len) : nullptr;
979 if (!workbuf_ptr_raw) {
980 *result = SkCodec::kInternalError;
981 return nullptr;
982 }
983 }
984 std::unique_ptr<uint8_t, decltype(&sk_free)> workbuf_ptr(
985 reinterpret_cast<uint8_t*>(workbuf_ptr_raw), &sk_free);
986
987 SkEncodedInfo::Color color =
988 (imgcfg.pixcfg.pixel_format().repr == WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL)
989 ? SkEncodedInfo::kBGRA_Color
990 : SkEncodedInfo::kRGBA_Color;
991
992 // In Skia's API, the alpha we calculate here and return is only for the
993 // first frame.
994 SkEncodedInfo::Alpha alpha = imgcfg.first_frame_is_opaque() ? SkEncodedInfo::kOpaque_Alpha
995 : SkEncodedInfo::kBinary_Alpha;
996
997 SkEncodedInfo encodedInfo = SkEncodedInfo::Make(width, height, color, alpha, 8);
998
999 *result = SkCodec::kSuccess;
1000 return std::unique_ptr<SkCodec>(new SkWuffsCodec(std::move(encodedInfo), std::move(stream),
1001 std::move(decoder), std::move(workbuf_ptr),
1002 workbuf_len, imgcfg, iobuf));
1003 }
1004