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