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 "SkWuffsCodec.h"
9 
10 #include "../private/SkMalloc.h"
11 #include "SkFrameHolder.h"
12 #include "SkSampler.h"
13 #include "SkSwizzler.h"
14 #include "SkUtils.h"
15 
16 // Wuffs ships as a "single file C library" or "header file library" as per
17 // https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
18 //
19 // As we have not #define'd WUFFS_IMPLEMENTATION, the #include here is
20 // including a header file, even though that file name ends in ".c".
21 #if defined(WUFFS_IMPLEMENTATION)
22 #error "SkWuffsCodec should not #define WUFFS_IMPLEMENTATION"
23 #endif
24 #include "wuffs-v0.2.c"
25 #if WUFFS_VERSION_BUILD_METADATA_COMMIT_COUNT < 1655
26 #error "Wuffs version is too old. Upgrade to the latest version."
27 #endif
28 
29 #define SK_WUFFS_CODEC_BUFFER_SIZE 4096
30 
fill_buffer(wuffs_base__io_buffer * b,SkStream * s)31 static bool fill_buffer(wuffs_base__io_buffer* b, SkStream* s) {
32     b->compact();
33     size_t num_read = s->read(b->data.ptr + b->meta.wi, b->data.len - b->meta.wi);
34     b->meta.wi += num_read;
35     b->meta.closed = s->isAtEnd();
36     return num_read > 0;
37 }
38 
seek_buffer(wuffs_base__io_buffer * b,SkStream * s,uint64_t pos)39 static bool seek_buffer(wuffs_base__io_buffer* b, SkStream* s, uint64_t pos) {
40     // Try to re-position the io_buffer's meta.ri read-index first, which is
41     // cheaper than seeking in the backing SkStream.
42     if ((pos >= b->meta.pos) && (pos - b->meta.pos <= b->meta.wi)) {
43         b->meta.ri = pos - b->meta.pos;
44         return true;
45     }
46     // Seek in the backing SkStream.
47     if ((pos > SIZE_MAX) || (!s->seek(pos))) {
48         return false;
49     }
50     b->meta.wi = 0;
51     b->meta.ri = 0;
52     b->meta.pos = pos;
53     b->meta.closed = false;
54     return true;
55 }
56 
wuffs_blend_to_skia_alpha(wuffs_base__animation_blend w)57 static SkEncodedInfo::Alpha wuffs_blend_to_skia_alpha(wuffs_base__animation_blend w) {
58     return (w == WUFFS_BASE__ANIMATION_BLEND__OPAQUE) ? SkEncodedInfo::kOpaque_Alpha
59                                                       : SkEncodedInfo::kUnpremul_Alpha;
60 }
61 
wuffs_blend_to_skia_blend(wuffs_base__animation_blend w)62 static SkCodecAnimation::Blend wuffs_blend_to_skia_blend(wuffs_base__animation_blend w) {
63     return (w == WUFFS_BASE__ANIMATION_BLEND__SRC) ? SkCodecAnimation::Blend::kBG
64                                                    : SkCodecAnimation::Blend::kPriorFrame;
65 }
66 
wuffs_disposal_to_skia_disposal(wuffs_base__animation_disposal w)67 static SkCodecAnimation::DisposalMethod wuffs_disposal_to_skia_disposal(
68     wuffs_base__animation_disposal w) {
69     switch (w) {
70         case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_BACKGROUND:
71             return SkCodecAnimation::DisposalMethod::kRestoreBGColor;
72         case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS:
73             return SkCodecAnimation::DisposalMethod::kRestorePrevious;
74         default:
75             return SkCodecAnimation::DisposalMethod::kKeep;
76     }
77 }
78 
79 // -------------------------------- Class definitions
80 
81 class SkWuffsCodec;
82 
83 class SkWuffsFrame final : public SkFrame {
84 public:
85     SkWuffsFrame(wuffs_base__frame_config* fc);
86 
87     SkCodec::FrameInfo frameInfo(bool fullyReceived) const;
88     uint64_t           ioPosition() const;
89 
90     // SkFrame overrides.
91     SkEncodedInfo::Alpha onReportedAlpha() const override;
92 
93 private:
94     uint64_t             fIOPosition;
95     SkEncodedInfo::Alpha fReportedAlpha;
96 
97     typedef SkFrame INHERITED;
98 };
99 
100 // SkWuffsFrameHolder is a trivial indirector that forwards its calls onto a
101 // SkWuffsCodec. It is a separate class as SkWuffsCodec would otherwise
102 // inherit from both SkCodec and SkFrameHolder, and Skia style discourages
103 // multiple inheritance (e.g. with its "typedef Foo INHERITED" convention).
104 class SkWuffsFrameHolder final : public SkFrameHolder {
105 public:
SkWuffsFrameHolder()106     SkWuffsFrameHolder() : INHERITED() {}
107 
108     void init(SkWuffsCodec* codec, int width, int height);
109 
110     // SkFrameHolder overrides.
111     const SkFrame* onGetFrame(int i) const override;
112 
113 private:
114     const SkWuffsCodec* fCodec;
115 
116     typedef SkFrameHolder INHERITED;
117 };
118 
119 // SkWuffsSpySampler is a placeholder SkSampler implementation. The Skia API
120 // expects to manipulate the codec's sampler (i.e. call setSampleX and
121 // setSampleY) in between the startIncrementalDecode (SID) and
122 // incrementalDecode (ID) calls. But creating the SkSwizzler (the real sampler)
123 // requires knowing the destination buffer's dimensions, i.e. the animation
124 // frame's width and height. That width and height are decoded in ID, not SID.
125 //
126 // To break that circle, the SkWuffsSpySampler always exists, so its methods
127 // can be called between SID and ID. It doesn't actually do any sampling, it
128 // merely records the arguments given to setSampleX (explicitly) and setSampleY
129 // (implicitly, via the superclass' implementation). Inside ID, those recorded
130 // arguments are forwarded on to the SkSwizzler (the real sampler) when that
131 // SkSwizzler is created, after the frame width and height are known.
132 //
133 // Roughly speaking, the SkWuffsSpySampler is an eager proxy for the lazily
134 // constructed real sampler. But that laziness is out of necessity.
135 //
136 // The "Spy" name is because it records its arguments. See
137 // https://martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs
138 class SkWuffsSpySampler final : public SkSampler {
139 public:
SkWuffsSpySampler(int imageWidth)140     SkWuffsSpySampler(int imageWidth)
141         : INHERITED(), fFillWidth(0), fImageWidth(imageWidth), fSampleX(1) {}
142 
143     void reset();
144     int  sampleX() const;
145 
146     int fFillWidth;
147 
148 private:
149     // SkSampler overrides.
150     int fillWidth() const override;
151     int onSetSampleX(int sampleX) override;
152 
153     const int fImageWidth;
154 
155     int fSampleX;
156 
157     typedef SkSampler INHERITED;
158 };
159 
160 class SkWuffsCodec final : public SkCodec {
161 public:
162     SkWuffsCodec(SkEncodedInfo&&                                         encodedInfo,
163                  std::unique_ptr<SkStream>                               stream,
164                  std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> dec,
165                  std::unique_ptr<uint8_t, decltype(&sk_free)>            pixbuf_ptr,
166                  std::unique_ptr<uint8_t, decltype(&sk_free)>            workbuf_ptr,
167                  size_t                                                  workbuf_len,
168                  wuffs_base__image_config                                imgcfg,
169                  wuffs_base__pixel_buffer                                pixbuf,
170                  wuffs_base__io_buffer                                   iobuf);
171 
172     const SkWuffsFrame* frame(int i) const;
173 
174 private:
175     // SkCodec overrides.
176     SkEncodedImageFormat onGetEncodedFormat() const override;
177     Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, int*) override;
178     const SkFrameHolder* getFrameHolder() const override;
179     Result               onStartIncrementalDecode(const SkImageInfo&      dstInfo,
180                                                   void*                   dst,
181                                                   size_t                  rowBytes,
182                                                   const SkCodec::Options& options) override;
183     Result               onIncrementalDecode(int* rowsDecoded) override;
184     int                  onGetFrameCount() override;
185     bool                 onGetFrameInfo(int, FrameInfo*) const override;
186     int                  onGetRepetitionCount() override;
187     SkSampler*           getSampler(bool createIfNecessary) override;
188     bool                 conversionSupported(const SkImageInfo& dst, bool, bool) override;
189 
190     void   readFrames();
191     Result seekFrame(int frameIndex);
192 
193     Result      resetDecoder();
194     const char* decodeFrameConfig();
195     const char* decodeFrame();
196     void        updateNumFullyReceivedFrames();
197 
198     SkWuffsSpySampler                                       fSpySampler;
199     SkWuffsFrameHolder                                      fFrameHolder;
200     std::unique_ptr<SkStream>                               fStream;
201     std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> fDecoder;
202     std::unique_ptr<uint8_t, decltype(&sk_free)>            fPixbufPtr;
203     std::unique_ptr<uint8_t, decltype(&sk_free)>            fWorkbufPtr;
204     size_t                                                  fWorkbufLen;
205 
206     const uint64_t           fFirstFrameIOPosition;
207     wuffs_base__frame_config fFrameConfig;
208     wuffs_base__pixel_buffer fPixelBuffer;
209     wuffs_base__io_buffer    fIOBuffer;
210 
211     // Incremental decoding state.
212     uint8_t* fIncrDecDst;
213     size_t   fIncrDecRowBytes;
214 
215     std::unique_ptr<SkSwizzler> fSwizzler;
216     int                         fScaledHeight;
217 
218     uint64_t                  fNumFullyReceivedFrames;
219     std::vector<SkWuffsFrame> fFrames;
220     bool                      fFramesComplete;
221 
222     // If calling an fDecoder method returns an incomplete status, then
223     // fDecoder is suspended in a coroutine (i.e. waiting on I/O or halted on a
224     // non-recoverable error). To keep its internal proof-of-safety invariants
225     // consistent, there's only two things you can safely do with a suspended
226     // Wuffs object: resume the coroutine, or reset all state (memset to zero
227     // and start again).
228     //
229     // If fDecoderIsSuspended, and we aren't sure that we're going to resume
230     // the coroutine, then we will need to call this->resetDecoder before
231     // calling other fDecoder methods.
232     bool fDecoderIsSuspended;
233 
234     uint8_t fBuffer[SK_WUFFS_CODEC_BUFFER_SIZE];
235 
236     typedef SkCodec INHERITED;
237 };
238 
239 // -------------------------------- SkWuffsFrame implementation
240 
SkWuffsFrame(wuffs_base__frame_config * fc)241 SkWuffsFrame::SkWuffsFrame(wuffs_base__frame_config* fc)
242     : INHERITED(fc->index()),
243       fIOPosition(fc->io_position()),
244       fReportedAlpha(wuffs_blend_to_skia_alpha(fc->blend())) {
245     wuffs_base__rect_ie_u32 r = fc->bounds();
246     this->setXYWH(r.min_incl_x, r.min_incl_y, r.width(), r.height());
247     this->setDisposalMethod(wuffs_disposal_to_skia_disposal(fc->disposal()));
248     this->setDuration(fc->duration() / WUFFS_BASE__FLICKS_PER_MILLISECOND);
249     this->setBlend(wuffs_blend_to_skia_blend(fc->blend()));
250 }
251 
frameInfo(bool fullyReceived) const252 SkCodec::FrameInfo SkWuffsFrame::frameInfo(bool fullyReceived) const {
253     return ((SkCodec::FrameInfo){
254         .fRequiredFrame = getRequiredFrame(),
255         .fDuration = getDuration(),
256         .fFullyReceived = fullyReceived,
257         .fAlphaType = hasAlpha() ? kUnpremul_SkAlphaType : kOpaque_SkAlphaType,
258         .fDisposalMethod = getDisposalMethod(),
259     });
260 }
261 
ioPosition() const262 uint64_t SkWuffsFrame::ioPosition() const {
263     return fIOPosition;
264 }
265 
onReportedAlpha() const266 SkEncodedInfo::Alpha SkWuffsFrame::onReportedAlpha() const {
267     return fReportedAlpha;
268 }
269 
270 // -------------------------------- SkWuffsFrameHolder implementation
271 
init(SkWuffsCodec * codec,int width,int height)272 void SkWuffsFrameHolder::init(SkWuffsCodec* codec, int width, int height) {
273     fCodec = codec;
274     // Initialize SkFrameHolder's (the superclass) fields.
275     fScreenWidth = width;
276     fScreenHeight = height;
277 }
278 
onGetFrame(int i) const279 const SkFrame* SkWuffsFrameHolder::onGetFrame(int i) const {
280     return fCodec->frame(i);
281 };
282 
283 // -------------------------------- SkWuffsSpySampler implementation
284 
reset()285 void SkWuffsSpySampler::reset() {
286     fFillWidth = 0;
287     fSampleX = 1;
288     this->setSampleY(1);
289 }
290 
sampleX() const291 int SkWuffsSpySampler::sampleX() const {
292     return fSampleX;
293 }
294 
fillWidth() const295 int SkWuffsSpySampler::fillWidth() const {
296     return fFillWidth;
297 }
298 
onSetSampleX(int sampleX)299 int SkWuffsSpySampler::onSetSampleX(int sampleX) {
300     fSampleX = sampleX;
301     return get_scaled_dimension(fImageWidth, sampleX);
302 }
303 
304 // -------------------------------- SkWuffsCodec implementation
305 
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) > pixbuf_ptr,std::unique_ptr<uint8_t,decltype(& sk_free) > workbuf_ptr,size_t workbuf_len,wuffs_base__image_config imgcfg,wuffs_base__pixel_buffer pixbuf,wuffs_base__io_buffer iobuf)306 SkWuffsCodec::SkWuffsCodec(SkEncodedInfo&&                                         encodedInfo,
307                            std::unique_ptr<SkStream>                               stream,
308                            std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> dec,
309                            std::unique_ptr<uint8_t, decltype(&sk_free)>            pixbuf_ptr,
310                            std::unique_ptr<uint8_t, decltype(&sk_free)>            workbuf_ptr,
311                            size_t                                                  workbuf_len,
312                            wuffs_base__image_config                                imgcfg,
313                            wuffs_base__pixel_buffer                                pixbuf,
314                            wuffs_base__io_buffer                                   iobuf)
315     : INHERITED(std::move(encodedInfo),
316                 skcms_PixelFormat_RGBA_8888,
317                 // Pass a nullptr SkStream to the SkCodec constructor. We
318                 // manage the stream ourselves, as the default SkCodec behavior
319                 // is too trigger-happy on rewinding the stream.
320                 nullptr),
321       fSpySampler(imgcfg.pixcfg.width()),
322       fFrameHolder(),
323       fStream(std::move(stream)),
324       fDecoder(std::move(dec)),
325       fPixbufPtr(std::move(pixbuf_ptr)),
326       fWorkbufPtr(std::move(workbuf_ptr)),
327       fWorkbufLen(workbuf_len),
328       fFirstFrameIOPosition(imgcfg.first_frame_io_position()),
329       fFrameConfig(wuffs_base__null_frame_config()),
330       fPixelBuffer(pixbuf),
331       fIOBuffer(wuffs_base__null_io_buffer()),
332       fIncrDecDst(nullptr),
333       fIncrDecRowBytes(0),
334       fSwizzler(nullptr),
335       fScaledHeight(0),
336       fNumFullyReceivedFrames(0),
337       fFramesComplete(false),
338       fDecoderIsSuspended(false) {
339     fFrameHolder.init(this, imgcfg.pixcfg.width(), imgcfg.pixcfg.height());
340 
341     // Initialize fIOBuffer's fields, copying any outstanding data from iobuf to
342     // fIOBuffer, as iobuf's backing array may not be valid for the lifetime of
343     // this SkWuffsCodec object, but fIOBuffer's backing array (fBuffer) is.
344     SkASSERT(iobuf.data.len == SK_WUFFS_CODEC_BUFFER_SIZE);
345     memmove(fBuffer, iobuf.data.ptr, iobuf.meta.wi);
346     fIOBuffer.data = wuffs_base__make_slice_u8(fBuffer, SK_WUFFS_CODEC_BUFFER_SIZE);
347     fIOBuffer.meta = iobuf.meta;
348 }
349 
frame(int i) const350 const SkWuffsFrame* SkWuffsCodec::frame(int i) const {
351     if ((0 <= i) && (static_cast<size_t>(i) < fFrames.size())) {
352         return &fFrames[i];
353     }
354     return nullptr;
355 }
356 
onGetEncodedFormat() const357 SkEncodedImageFormat SkWuffsCodec::onGetEncodedFormat() const {
358     return SkEncodedImageFormat::kGIF;
359 }
360 
onGetPixels(const SkImageInfo & dstInfo,void * dst,size_t rowBytes,const Options & options,int * rowsDecoded)361 SkCodec::Result SkWuffsCodec::onGetPixels(const SkImageInfo& dstInfo,
362                                           void*              dst,
363                                           size_t             rowBytes,
364                                           const Options&     options,
365                                           int*               rowsDecoded) {
366     SkCodec::Result result = this->onStartIncrementalDecode(dstInfo, dst, rowBytes, options);
367     if (result != kSuccess) {
368         return result;
369     }
370     return this->onIncrementalDecode(rowsDecoded);
371 }
372 
getFrameHolder() const373 const SkFrameHolder* SkWuffsCodec::getFrameHolder() const {
374     return &fFrameHolder;
375 }
376 
onStartIncrementalDecode(const SkImageInfo & dstInfo,void * dst,size_t rowBytes,const SkCodec::Options & options)377 SkCodec::Result SkWuffsCodec::onStartIncrementalDecode(const SkImageInfo&      dstInfo,
378                                                        void*                   dst,
379                                                        size_t                  rowBytes,
380                                                        const SkCodec::Options& options) {
381     if (options.fSubset) {
382         return SkCodec::kUnimplemented;
383     }
384     SkCodec::Result result = this->seekFrame(options.fFrameIndex);
385     if (result != SkCodec::kSuccess) {
386         return result;
387     }
388 
389     fSpySampler.reset();
390     fSwizzler = nullptr;
391     fScaledHeight = 0;
392 
393     const char* status = this->decodeFrameConfig();
394     if (status == wuffs_base__suspension__short_read) {
395         return SkCodec::kIncompleteInput;
396     } else if (status != nullptr) {
397         SkCodecPrintf("decodeFrameConfig: %s", status);
398         return SkCodec::kErrorInInput;
399     }
400 
401     uint32_t src_bits_per_pixel =
402         wuffs_base__pixel_format__bits_per_pixel(fPixelBuffer.pixcfg.pixel_format());
403     if ((src_bits_per_pixel == 0) || (src_bits_per_pixel % 8 != 0)) {
404         return SkCodec::kInternalError;
405     }
406     size_t src_bytes_per_pixel = src_bits_per_pixel / 8;
407 
408     // Zero-initialize Wuffs' buffer covering the frame rect.
409     wuffs_base__rect_ie_u32 frame_rect = fFrameConfig.bounds();
410     wuffs_base__table_u8    pixels = fPixelBuffer.plane(0);
411     for (uint32_t y = frame_rect.min_incl_y; y < frame_rect.max_excl_y; y++) {
412         sk_bzero(pixels.ptr + (y * pixels.stride) + (frame_rect.min_incl_x * src_bytes_per_pixel),
413                  frame_rect.width() * src_bytes_per_pixel);
414     }
415 
416     fIncrDecDst = static_cast<uint8_t*>(dst);
417     fIncrDecRowBytes = rowBytes;
418     return SkCodec::kSuccess;
419 }
420 
independent_frame(SkCodec * codec,int frameIndex)421 static bool independent_frame(SkCodec* codec, int frameIndex) {
422     if (frameIndex == 0) {
423         return true;
424     }
425 
426     SkCodec::FrameInfo frameInfo;
427     SkAssertResult(codec->getFrameInfo(frameIndex, &frameInfo));
428     return frameInfo.fRequiredFrame == SkCodec::kNoFrame;
429 }
430 
blend(uint32_t * dst,const uint32_t * src,int width)431 static void blend(uint32_t* dst, const uint32_t* src, int width) {
432     while (width --> 0) {
433         if (*src != 0) {
434             *dst = *src;
435         }
436         src++;
437         dst++;
438     }
439 }
440 
onIncrementalDecode(int * rowsDecoded)441 SkCodec::Result SkWuffsCodec::onIncrementalDecode(int* rowsDecoded) {
442     if (!fIncrDecDst) {
443         return SkCodec::kInternalError;
444     }
445 
446     SkCodec::Result result = SkCodec::kSuccess;
447     const char*     status = this->decodeFrame();
448     const bool      independent = independent_frame(this, options().fFrameIndex);
449     if (status != nullptr) {
450         if (status == wuffs_base__suspension__short_read) {
451             result = SkCodec::kIncompleteInput;
452         } else {
453             SkCodecPrintf("decodeFrame: %s", status);
454             result = SkCodec::kErrorInInput;
455         }
456 
457         if (!independent) {
458             // For a dependent frame, we cannot blend the partial result, since
459             // that will overwrite the contribution from prior frames.
460             return result;
461         }
462     }
463 
464     uint32_t src_bits_per_pixel =
465         wuffs_base__pixel_format__bits_per_pixel(fPixelBuffer.pixcfg.pixel_format());
466     if ((src_bits_per_pixel == 0) || (src_bits_per_pixel % 8 != 0)) {
467         return SkCodec::kInternalError;
468     }
469     size_t src_bytes_per_pixel = src_bits_per_pixel / 8;
470 
471     wuffs_base__rect_ie_u32 frame_rect = fFrameConfig.bounds();
472     if (!fSwizzler) {
473         auto bounds = SkIRect::MakeLTRB(frame_rect.min_incl_x, frame_rect.min_incl_y,
474                                         frame_rect.max_excl_x, frame_rect.max_excl_y);
475         fSwizzler =
476             SkSwizzler::Make(this->getEncodedInfo(), nullptr, dstInfo(), this->options(), &bounds);
477         fSwizzler->setSampleX(fSpySampler.sampleX());
478         fSwizzler->setSampleY(fSpySampler.sampleY());
479         fScaledHeight = get_scaled_dimension(dstInfo().height(), fSpySampler.sampleY());
480 
481         if (frame_rect.width() > (SIZE_MAX / src_bytes_per_pixel)) {
482             return SkCodec::kInternalError;
483         }
484 
485         // If the frame rect does not fill the output, ensure that those pixels are not
486         // left uninitialized.
487         if (independent && (bounds != this->bounds() || result != kSuccess)) {
488             auto fillInfo = dstInfo().makeWH(fSwizzler->fillWidth(), fScaledHeight);
489             SkSampler::Fill(fillInfo, fIncrDecDst, fIncrDecRowBytes, options().fZeroInitialized);
490         }
491     }
492     if (fScaledHeight == 0) {
493         return SkCodec::kInternalError;
494     }
495 
496     // The semantics of *rowsDecoded is: say you have a 10 pixel high image
497     // (both the frame and the image). If you only decoded the first 3 rows,
498     // set this to 3, and then SkCodec (or the caller of incrementalDecode)
499     // would zero-initialize the remaining 7 (unless the memory was already
500     // zero-initialized).
501     //
502     // Now let's say that the image is still 10 pixels high, but the frame is
503     // from row 5 to 9. If you only decoded 3 rows, but you initialized the
504     // first 5, you could return 8, and the caller would zero-initialize the
505     // final 2. For GIF (where a frame can be smaller than the image and can be
506     // interlaced), we just zero-initialize all 10 rows ahead of time and
507     // return the height of the image, so the caller knows it doesn't need to
508     // do anything.
509     //
510     // Similarly, if the output is scaled, we zero-initialized all
511     // |fScaledHeight| rows (the scaled image height), so we inform the caller
512     // that it doesn't need to do anything.
513     if (rowsDecoded) {
514         *rowsDecoded = fScaledHeight;
515     }
516 
517     // If the frame's dirty rect is empty, no need to swizzle.
518     wuffs_base__rect_ie_u32 dirty_rect = fDecoder->frame_dirty_rect();
519     if (!dirty_rect.is_empty()) {
520         std::unique_ptr<uint8_t[]> tmpBuffer;
521         if (!independent) {
522             tmpBuffer.reset(new uint8_t[dstInfo().minRowBytes()]);
523         }
524         wuffs_base__table_u8 pixels = fPixelBuffer.plane(0);
525         const int            sampleY = fSwizzler->sampleY();
526         for (uint32_t y = dirty_rect.min_incl_y; y < dirty_rect.max_excl_y; y++) {
527             int dstY = y;
528             if (sampleY != 1) {
529                 if (!fSwizzler->rowNeeded(y)) {
530                     continue;
531                 }
532                 dstY /= sampleY;
533                 if (dstY >= fScaledHeight) {
534                     break;
535                 }
536             }
537 
538             // We don't adjust d by (frame_rect.min_incl_x * dst_bpp) as we
539             // have already accounted for that in swizzleRect, above.
540             uint8_t* d = fIncrDecDst + (dstY * fIncrDecRowBytes);
541 
542             // The Wuffs model is that the dst buffer is the image, not the frame.
543             // The expectation is that you allocate the buffer once, but re-use it
544             // for the N frames, regardless of each frame's top-left co-ordinate.
545             //
546             // To get from the start (in the X-direction) of the image to the start
547             // of the frame, we adjust s by (frame_rect.min_incl_x *
548             // src_bytes_per_pixel).
549             //
550             // We adjust (in the X-direction) by the frame rect, not the dirty
551             // rect, because the swizzler (which operates on rows) was
552             // configured with the frame rect's X range.
553             uint8_t* s =
554                 pixels.ptr + (y * pixels.stride) + (frame_rect.min_incl_x * src_bytes_per_pixel);
555             if (independent) {
556                 fSwizzler->swizzle(d, s);
557             } else {
558                 SkASSERT(tmpBuffer.get());
559                 fSwizzler->swizzle(tmpBuffer.get(), s);
560                 d = SkTAddOffset<uint8_t>(d, fSwizzler->swizzleOffsetBytes());
561                 const auto* swizzled = SkTAddOffset<uint32_t>(tmpBuffer.get(),
562                                                               fSwizzler->swizzleOffsetBytes());
563                 blend(reinterpret_cast<uint32_t*>(d), swizzled, fSwizzler->swizzleWidth());
564             }
565         }
566     }
567 
568     if (result == SkCodec::kSuccess) {
569         fSpySampler.reset();
570         fIncrDecDst = nullptr;
571         fIncrDecRowBytes = 0;
572         fSwizzler = nullptr;
573     } else {
574         // Make fSpySampler return whatever fSwizzler would have for fillWidth.
575         fSpySampler.fFillWidth = fSwizzler->fillWidth();
576     }
577     return result;
578 }
579 
onGetFrameCount()580 int SkWuffsCodec::onGetFrameCount() {
581     if (!fFramesComplete) {
582         this->readFrames();
583         this->updateNumFullyReceivedFrames();
584     }
585     return fFrames.size();
586 }
587 
onGetFrameInfo(int i,SkCodec::FrameInfo * frameInfo) const588 bool SkWuffsCodec::onGetFrameInfo(int i, SkCodec::FrameInfo* frameInfo) const {
589     const SkWuffsFrame* f = this->frame(i);
590     if (!f) {
591         return false;
592     }
593     if (frameInfo) {
594         *frameInfo = f->frameInfo(static_cast<uint64_t>(i) < this->fNumFullyReceivedFrames);
595     }
596     return true;
597 }
598 
onGetRepetitionCount()599 int SkWuffsCodec::onGetRepetitionCount() {
600     // Convert from Wuffs's loop count to Skia's repeat count. Wuffs' uint32_t
601     // number is how many times to play the loop. Skia's int number is how many
602     // times to play the loop *after the first play*. Wuffs and Skia use 0 and
603     // kRepetitionCountInfinite respectively to mean loop forever.
604     uint32_t n = fDecoder->num_animation_loops();
605     if (n == 0) {
606         return SkCodec::kRepetitionCountInfinite;
607     }
608     n--;
609     return n < INT_MAX ? n : INT_MAX;
610 }
611 
getSampler(bool createIfNecessary)612 SkSampler* SkWuffsCodec::getSampler(bool createIfNecessary) {
613     // fIncrDst being non-nullptr means that we are between an
614     // onStartIncrementalDecode call and the matching final (successful)
615     // onIncrementalDecode call.
616     if (createIfNecessary || fIncrDecDst) {
617         return &fSpySampler;
618     }
619     return nullptr;
620 }
621 
conversionSupported(const SkImageInfo & dst,bool srcIsOpaque,bool needsColorXform)622 bool SkWuffsCodec::conversionSupported(const SkImageInfo& dst, bool srcIsOpaque, bool needsColorXform) {
623     if (!this->INHERITED::conversionSupported(dst, srcIsOpaque, needsColorXform)) {
624         return false;
625     }
626 
627     switch (dst.colorType()) {
628         case kRGBA_8888_SkColorType:
629         case kBGRA_8888_SkColorType:
630             return true;
631         default:
632             // FIXME: Add skcms to support F16
633             // FIXME: Add support for 565 on the first frame
634             return false;
635     }
636 }
637 
readFrames()638 void SkWuffsCodec::readFrames() {
639     size_t n = fFrames.size();
640     int    i = n ? n - 1 : 0;
641     if (this->seekFrame(i) != SkCodec::kSuccess) {
642         return;
643     }
644 
645     // Iterate through the frames, converting from Wuffs'
646     // wuffs_base__frame_config type to Skia's SkWuffsFrame type.
647     for (; i < INT_MAX; i++) {
648         const char* status = this->decodeFrameConfig();
649         if (status == nullptr) {
650             // No-op.
651         } else if (status == wuffs_base__warning__end_of_data) {
652             break;
653         } else {
654             return;
655         }
656 
657         if (static_cast<size_t>(i) < fFrames.size()) {
658             continue;
659         }
660         fFrames.emplace_back(&fFrameConfig);
661         SkWuffsFrame* f = &fFrames[fFrames.size() - 1];
662         fFrameHolder.setAlphaAndRequiredFrame(f);
663     }
664 
665     fFramesComplete = true;
666 }
667 
seekFrame(int frameIndex)668 SkCodec::Result SkWuffsCodec::seekFrame(int frameIndex) {
669     if (fDecoderIsSuspended) {
670         SkCodec::Result res = this->resetDecoder();
671         if (res != SkCodec::kSuccess) {
672             return res;
673         }
674     }
675 
676     uint64_t pos = 0;
677     if (frameIndex < 0) {
678         return SkCodec::kInternalError;
679     } else if (frameIndex == 0) {
680         pos = fFirstFrameIOPosition;
681     } else if (static_cast<size_t>(frameIndex) < fFrames.size()) {
682         pos = fFrames[frameIndex].ioPosition();
683     } else {
684         return SkCodec::kInternalError;
685     }
686 
687     if (!seek_buffer(&fIOBuffer, fStream.get(), pos)) {
688         return SkCodec::kInternalError;
689     }
690     const char* status = fDecoder->restart_frame(frameIndex, fIOBuffer.reader_io_position());
691     if (status != nullptr) {
692         return SkCodec::kInternalError;
693     }
694     return SkCodec::kSuccess;
695 }
696 
697 // An overview of the Wuffs decoding API:
698 //
699 // An animated image (such as GIF) has an image header and then N frames. The
700 // image header gives e.g. the overall image's width and height. Each frame
701 // consists of a frame header (e.g. frame rectangle bounds, display duration)
702 // and a payload (the pixels).
703 //
704 // In Wuffs terminology, there is one image config and then N pairs of
705 // (frame_config, frame). To decode everything (without knowing N in advance)
706 // sequentially:
707 //  - call wuffs_gif__decoder::decode_image_config
708 //  - while (true) {
709 //  -   call wuffs_gif__decoder::decode_frame_config
710 //  -   if that returned wuffs_base__warning__end_of_data, break
711 //  -   call wuffs_gif__decoder::decode_frame
712 //  - }
713 //
714 // The first argument to each decode_foo method is the destination struct to
715 // store the decoded information.
716 //
717 // For random (instead of sequential) access to an image's frames, call
718 // wuffs_gif__decoder::restart_frame to prepare to decode the i'th frame.
719 // Essentially, it restores the state to be at the top of the while loop above.
720 // The wuffs_base__io_buffer's reader position will also need to be set at the
721 // right point in the source data stream. The position for the i'th frame is
722 // calculated by the i'th decode_frame_config call. You can only call
723 // restart_frame after decode_image_config is called, explicitly or implicitly
724 // (see below), as decoding a single frame might require for-all-frames
725 // information like the overall image dimensions and the global palette.
726 //
727 // All of those decode_xxx calls are optional. For example, if
728 // decode_image_config is not called, then the first decode_frame_config call
729 // will implicitly parse and verify the image header, before parsing the first
730 // frame's header. Similarly, you can call only decode_frame N times, without
731 // calling decode_image_config or decode_frame_config, if you already know
732 // metadata like N and each frame's rectangle bounds by some other means (e.g.
733 // this is a first party, statically known image).
734 //
735 // Specifically, starting with an unknown (but re-windable) GIF image, if you
736 // want to just find N (i.e. count the number of frames), you can loop calling
737 // only the decode_frame_config method and avoid calling the more expensive
738 // decode_frame method. In terms of the underlying GIF image format, this will
739 // skip over the LZW-encoded pixel data, avoiding the costly LZW decompression.
740 //
741 // Those decode_xxx methods are also suspendible. They will return early (with
742 // a status code that is_suspendible and therefore isn't is_complete) if there
743 // isn't enough source data to complete the operation: an incremental decode.
744 // Calling decode_xxx again with additional source data will resume the
745 // previous operation, instead of starting a new operation. Calling decode_yyy
746 // whilst decode_xxx is suspended will result in an error.
747 //
748 // Once an error is encountered, whether from invalid source data or from a
749 // programming error such as calling decode_yyy while suspended in decode_xxx,
750 // all subsequent calls will be no-ops that return an error. To reset the
751 // decoder into something that does productive work, memset the entire struct
752 // to zero, check the Wuffs version and then, in order to be able to call
753 // restart_frame, call decode_image_config. The io_buffer and its associated
754 // stream will also need to be rewound.
755 
reset_and_decode_image_config(wuffs_gif__decoder * decoder,wuffs_base__image_config * imgcfg,wuffs_base__io_buffer * b,SkStream * s)756 static SkCodec::Result reset_and_decode_image_config(wuffs_gif__decoder*       decoder,
757                                                      wuffs_base__image_config* imgcfg,
758                                                      wuffs_base__io_buffer*    b,
759                                                      SkStream*                 s) {
760     // Calling decoder->initialize will memset it to zero.
761     const char* status = decoder->initialize(sizeof__wuffs_gif__decoder(), WUFFS_VERSION, 0);
762     if (status != nullptr) {
763         SkCodecPrintf("initialize: %s", status);
764         return SkCodec::kInternalError;
765     }
766     while (true) {
767         status = decoder->decode_image_config(imgcfg, b->reader());
768         if (status == nullptr) {
769             break;
770         } else if (status != wuffs_base__suspension__short_read) {
771             SkCodecPrintf("decode_image_config: %s", status);
772             return SkCodec::kErrorInInput;
773         } else if (!fill_buffer(b, s)) {
774             return SkCodec::kIncompleteInput;
775         }
776     }
777 
778     // A GIF image's natural color model is indexed color: 1 byte per pixel,
779     // indexing a 256-element palette.
780     //
781     // For Skia, we override that to decode to 4 bytes per pixel, BGRA or RGBA.
782     wuffs_base__pixel_format pixfmt = 0;
783     switch (kN32_SkColorType) {
784         case kBGRA_8888_SkColorType:
785             pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL;
786             break;
787         case kRGBA_8888_SkColorType:
788             pixfmt = WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL;
789             break;
790         default:
791             return SkCodec::kInternalError;
792     }
793     imgcfg->pixcfg.set(pixfmt, WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, imgcfg->pixcfg.width(),
794                        imgcfg->pixcfg.height());
795 
796     return SkCodec::kSuccess;
797 }
798 
resetDecoder()799 SkCodec::Result SkWuffsCodec::resetDecoder() {
800     if (!fStream->rewind()) {
801         return SkCodec::kInternalError;
802     }
803     fIOBuffer.meta = wuffs_base__null_io_buffer_meta();
804 
805     SkCodec::Result result =
806         reset_and_decode_image_config(fDecoder.get(), nullptr, &fIOBuffer, fStream.get());
807     if (result == SkCodec::kIncompleteInput) {
808         return SkCodec::kInternalError;
809     } else if (result != SkCodec::kSuccess) {
810         return result;
811     }
812 
813     fDecoderIsSuspended = false;
814     return SkCodec::kSuccess;
815 }
816 
decodeFrameConfig()817 const char* SkWuffsCodec::decodeFrameConfig() {
818     while (true) {
819         const char* status = fDecoder->decode_frame_config(&fFrameConfig, fIOBuffer.reader());
820         if ((status == wuffs_base__suspension__short_read) &&
821             fill_buffer(&fIOBuffer, fStream.get())) {
822             continue;
823         }
824         fDecoderIsSuspended = !wuffs_base__status__is_complete(status);
825         this->updateNumFullyReceivedFrames();
826         return status;
827     }
828 }
829 
decodeFrame()830 const char* SkWuffsCodec::decodeFrame() {
831     while (true) {
832         const char* status =
833             fDecoder->decode_frame(&fPixelBuffer, fIOBuffer.reader(),
834                                    wuffs_base__make_slice_u8(fWorkbufPtr.get(), fWorkbufLen), NULL);
835         if ((status == wuffs_base__suspension__short_read) &&
836             fill_buffer(&fIOBuffer, fStream.get())) {
837             continue;
838         }
839         fDecoderIsSuspended = !wuffs_base__status__is_complete(status);
840         this->updateNumFullyReceivedFrames();
841         return status;
842     }
843 }
844 
updateNumFullyReceivedFrames()845 void SkWuffsCodec::updateNumFullyReceivedFrames() {
846     // num_decoded_frames's return value, n, can change over time, both up and
847     // down, as we seek back and forth in the underlying stream.
848     // fNumFullyReceivedFrames is the highest n we've seen.
849     uint64_t n = fDecoder->num_decoded_frames();
850     if (fNumFullyReceivedFrames < n) {
851         fNumFullyReceivedFrames = n;
852     }
853 }
854 
855 // -------------------------------- SkWuffsCodec.h functions
856 
SkWuffsCodec_IsFormat(const void * buf,size_t bytesRead)857 bool SkWuffsCodec_IsFormat(const void* buf, size_t bytesRead) {
858     constexpr const char* gif_ptr = "GIF8";
859     constexpr size_t      gif_len = 4;
860     return (bytesRead >= gif_len) && (memcmp(buf, gif_ptr, gif_len) == 0);
861 }
862 
SkWuffsCodec_MakeFromStream(std::unique_ptr<SkStream> stream,SkCodec::Result * result)863 std::unique_ptr<SkCodec> SkWuffsCodec_MakeFromStream(std::unique_ptr<SkStream> stream,
864                                                      SkCodec::Result*          result) {
865     uint8_t               buffer[SK_WUFFS_CODEC_BUFFER_SIZE];
866     wuffs_base__io_buffer iobuf =
867         wuffs_base__make_io_buffer(wuffs_base__make_slice_u8(buffer, SK_WUFFS_CODEC_BUFFER_SIZE),
868                                    wuffs_base__null_io_buffer_meta());
869     wuffs_base__image_config imgcfg = wuffs_base__null_image_config();
870 
871     // Wuffs is primarily a C library, not a C++ one. Furthermore, outside of
872     // the wuffs_base__etc types, the sizeof a file format specific type like
873     // GIF's wuffs_gif__decoder can vary between Wuffs versions. If p is of
874     // type wuffs_gif__decoder*, then the supported API treats p as a pointer
875     // to an opaque type: a private implementation detail. The API is always
876     // "set_foo(p, etc)" and not "p->foo = etc".
877     //
878     // See https://en.wikipedia.org/wiki/Opaque_pointer#C
879     //
880     // Thus, we don't use C++'s new operator (which requires knowing the sizeof
881     // the struct at compile time). Instead, we use sk_malloc_canfail, with
882     // sizeof__wuffs_gif__decoder returning the appropriate value for the
883     // (statically or dynamically) linked version of the Wuffs library.
884     //
885     // As a C (not C++) library, none of the Wuffs types have constructors or
886     // destructors.
887     //
888     // In RAII style, we can still use std::unique_ptr with these pointers, but
889     // we pair the pointer with sk_free instead of C++'s delete.
890     void* decoder_raw = sk_malloc_canfail(sizeof__wuffs_gif__decoder());
891     if (!decoder_raw) {
892         *result = SkCodec::kInternalError;
893         return nullptr;
894     }
895     std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> decoder(
896         reinterpret_cast<wuffs_gif__decoder*>(decoder_raw), &sk_free);
897 
898     SkCodec::Result reset_result =
899         reset_and_decode_image_config(decoder.get(), &imgcfg, &iobuf, stream.get());
900     if (reset_result != SkCodec::kSuccess) {
901         *result = reset_result;
902         return nullptr;
903     }
904 
905     uint32_t width = imgcfg.pixcfg.width();
906     uint32_t height = imgcfg.pixcfg.height();
907     if ((width == 0) || (width > INT_MAX) || (height == 0) || (height > INT_MAX)) {
908         *result = SkCodec::kInvalidInput;
909         return nullptr;
910     }
911 
912     uint64_t workbuf_len = decoder->workbuf_len().max_incl;
913     void*    workbuf_ptr_raw = nullptr;
914     if (workbuf_len) {
915         workbuf_ptr_raw = workbuf_len <= SIZE_MAX ? sk_malloc_canfail(workbuf_len) : nullptr;
916         if (!workbuf_ptr_raw) {
917             *result = SkCodec::kInternalError;
918             return nullptr;
919         }
920     }
921     std::unique_ptr<uint8_t, decltype(&sk_free)> workbuf_ptr(
922         reinterpret_cast<uint8_t*>(workbuf_ptr_raw), &sk_free);
923 
924     uint64_t pixbuf_len = imgcfg.pixcfg.pixbuf_len();
925     void*    pixbuf_ptr_raw = pixbuf_len <= SIZE_MAX ? sk_malloc_canfail(pixbuf_len) : nullptr;
926     if (!pixbuf_ptr_raw) {
927         *result = SkCodec::kInternalError;
928         return nullptr;
929     }
930     std::unique_ptr<uint8_t, decltype(&sk_free)> pixbuf_ptr(
931         reinterpret_cast<uint8_t*>(pixbuf_ptr_raw), &sk_free);
932     wuffs_base__pixel_buffer pixbuf = wuffs_base__null_pixel_buffer();
933 
934     const char* status = pixbuf.set_from_slice(
935         &imgcfg.pixcfg, wuffs_base__make_slice_u8(pixbuf_ptr.get(), SkToSizeT(pixbuf_len)));
936     if (status != nullptr) {
937         SkCodecPrintf("set_from_slice: %s", status);
938         *result = SkCodec::kInternalError;
939         return nullptr;
940     }
941 
942     SkEncodedInfo::Color color =
943         (imgcfg.pixcfg.pixel_format() == WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL)
944             ? SkEncodedInfo::kBGRA_Color
945             : SkEncodedInfo::kRGBA_Color;
946 
947     // In Skia's API, the alpha we calculate here and return is only for the
948     // first frame.
949     SkEncodedInfo::Alpha alpha = imgcfg.first_frame_is_opaque() ? SkEncodedInfo::kOpaque_Alpha
950                                                                 : SkEncodedInfo::kBinary_Alpha;
951 
952     SkEncodedInfo encodedInfo = SkEncodedInfo::Make(width, height, color, alpha, 8);
953 
954     *result = SkCodec::kSuccess;
955     return std::unique_ptr<SkCodec>(new SkWuffsCodec(
956         std::move(encodedInfo), std::move(stream), std::move(decoder), std::move(pixbuf_ptr),
957         std::move(workbuf_ptr), workbuf_len, imgcfg, pixbuf, iobuf));
958 }
959