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