blob: 1dbd8646df390ff63805dee9f69da47312a29298 [file] [log] [blame]
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -04001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/codec/SkWuffsCodec.h"
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#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/SkRasterClip.h"
19#include "src/core/SkUtils.h"
Nigel Taoa6766482019-01-07 13:41:53 +110020
Ben Wagner666a9f92019-05-02 17:45:00 -040021#include <limits.h>
22
Nigel Taoa6766482019-01-07 13:41:53 +110023// Wuffs ships as a "single file C library" or "header file library" as per
24// https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
25//
26// As we have not #define'd WUFFS_IMPLEMENTATION, the #include here is
27// including a header file, even though that file name ends in ".c".
Nigel Taoe66a0b22019-03-09 15:03:14 +110028#if defined(WUFFS_IMPLEMENTATION)
29#error "SkWuffsCodec should not #define WUFFS_IMPLEMENTATION"
30#endif
Nigel Taoa6766482019-01-07 13:41:53 +110031#include "wuffs-v0.2.c"
Nigel Tao477f2212019-10-09 10:07:11 +110032#if WUFFS_VERSION_BUILD_METADATA_COMMIT_COUNT < 1942
Nigel Taoa6766482019-01-07 13:41:53 +110033#error "Wuffs version is too old. Upgrade to the latest version."
34#endif
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -040035
36#define SK_WUFFS_CODEC_BUFFER_SIZE 4096
37
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -040038static bool fill_buffer(wuffs_base__io_buffer* b, SkStream* s) {
39 b->compact();
40 size_t num_read = s->read(b->data.ptr + b->meta.wi, b->data.len - b->meta.wi);
41 b->meta.wi += num_read;
42 b->meta.closed = s->isAtEnd();
43 return num_read > 0;
44}
45
46static bool seek_buffer(wuffs_base__io_buffer* b, SkStream* s, uint64_t pos) {
47 // Try to re-position the io_buffer's meta.ri read-index first, which is
48 // cheaper than seeking in the backing SkStream.
49 if ((pos >= b->meta.pos) && (pos - b->meta.pos <= b->meta.wi)) {
50 b->meta.ri = pos - b->meta.pos;
51 return true;
52 }
53 // Seek in the backing SkStream.
54 if ((pos > SIZE_MAX) || (!s->seek(pos))) {
55 return false;
56 }
57 b->meta.wi = 0;
58 b->meta.ri = 0;
59 b->meta.pos = pos;
60 b->meta.closed = false;
61 return true;
62}
63
64static SkEncodedInfo::Alpha wuffs_blend_to_skia_alpha(wuffs_base__animation_blend w) {
65 return (w == WUFFS_BASE__ANIMATION_BLEND__OPAQUE) ? SkEncodedInfo::kOpaque_Alpha
66 : SkEncodedInfo::kUnpremul_Alpha;
67}
68
69static SkCodecAnimation::Blend wuffs_blend_to_skia_blend(wuffs_base__animation_blend w) {
70 return (w == WUFFS_BASE__ANIMATION_BLEND__SRC) ? SkCodecAnimation::Blend::kBG
71 : SkCodecAnimation::Blend::kPriorFrame;
72}
73
74static SkCodecAnimation::DisposalMethod wuffs_disposal_to_skia_disposal(
75 wuffs_base__animation_disposal w) {
76 switch (w) {
77 case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_BACKGROUND:
78 return SkCodecAnimation::DisposalMethod::kRestoreBGColor;
79 case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS:
80 return SkCodecAnimation::DisposalMethod::kRestorePrevious;
81 default:
82 return SkCodecAnimation::DisposalMethod::kKeep;
83 }
84}
85
Nigel Tao2777cd32019-10-29 11:10:25 +110086static SkCodec::Result reset_and_decode_image_config(wuffs_gif__decoder* decoder,
87 wuffs_base__image_config* imgcfg,
88 wuffs_base__io_buffer* b,
89 SkStream* s);
90
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -040091// -------------------------------- Class definitions
92
93class SkWuffsCodec;
94
95class SkWuffsFrame final : public SkFrame {
96public:
97 SkWuffsFrame(wuffs_base__frame_config* fc);
98
99 SkCodec::FrameInfo frameInfo(bool fullyReceived) const;
100 uint64_t ioPosition() const;
101
102 // SkFrame overrides.
103 SkEncodedInfo::Alpha onReportedAlpha() const override;
104
105private:
106 uint64_t fIOPosition;
107 SkEncodedInfo::Alpha fReportedAlpha;
108
109 typedef SkFrame INHERITED;
110};
111
112// SkWuffsFrameHolder is a trivial indirector that forwards its calls onto a
113// SkWuffsCodec. It is a separate class as SkWuffsCodec would otherwise
114// inherit from both SkCodec and SkFrameHolder, and Skia style discourages
115// multiple inheritance (e.g. with its "typedef Foo INHERITED" convention).
116class SkWuffsFrameHolder final : public SkFrameHolder {
117public:
118 SkWuffsFrameHolder() : INHERITED() {}
119
120 void init(SkWuffsCodec* codec, int width, int height);
121
122 // SkFrameHolder overrides.
123 const SkFrame* onGetFrame(int i) const override;
124
125private:
126 const SkWuffsCodec* fCodec;
127
128 typedef SkFrameHolder INHERITED;
129};
130
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400131class SkWuffsCodec final : public SkScalingCodec {
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400132public:
133 SkWuffsCodec(SkEncodedInfo&& encodedInfo,
134 std::unique_ptr<SkStream> stream,
135 std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> dec,
136 std::unique_ptr<uint8_t, decltype(&sk_free)> pixbuf_ptr,
137 std::unique_ptr<uint8_t, decltype(&sk_free)> workbuf_ptr,
138 size_t workbuf_len,
139 wuffs_base__image_config imgcfg,
140 wuffs_base__pixel_buffer pixbuf,
141 wuffs_base__io_buffer iobuf);
142
143 const SkWuffsFrame* frame(int i) const;
144
145private:
Nigel Tao2777cd32019-10-29 11:10:25 +1100146 // It is valid, in terms of the SkCodec API, to call SkCodec::getFrameCount
147 // while in an incremental decode (after onStartIncrementalDecode returns
148 // and before the rest of the image is decoded). Some Skia users expect
149 // getFrameCount to increase, and the SkStream to advance, when given more
150 // data.
151 //
152 // On the other hand, while in an incremental decode, the underlying Wuffs
153 // object is suspended in a coroutine. To keep its internal proof-of-safety
154 // invariants consistent, there's only two things you can safely do with a
155 // suspended Wuffs object: resume the coroutine, or reset all state (memset
156 // to zero and start again).
157 //
158 // The Wuffs API provides a limited, optional form of seeking, to the start
159 // of an animation frame's data, but does not provide arbitrary save and
160 // load of its internal state whilst in the middle of an animation frame.
161 //
162 // SkWuffsCodec therefore uses two Wuffs decoders: a primary decoder
163 // (kIncrDecode) to support startIncrementalDecode / incrementalDecode, and
164 // a secondary decoder (kFrameCount) to support getFrameCount. The two
165 // decoders' states can change independently.
166 //
167 // As of Wuffs version 0.2, both of these decoders have the same type. A
168 // future Wuffs version might let us use a different type for kFrameCount,
169 // one that is much lighter weight (in terms of memory requirements), as it
170 // doesn't have to handle decompressing pixel data.
171 enum WhichDecoder {
172 kIncrDecode,
173 kFrameCount,
174 kNumDecoders,
175 };
176
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400177 // SkCodec overrides.
178 SkEncodedImageFormat onGetEncodedFormat() const override;
179 Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, int*) override;
180 const SkFrameHolder* getFrameHolder() const override;
181 Result onStartIncrementalDecode(const SkImageInfo& dstInfo,
182 void* dst,
183 size_t rowBytes,
184 const SkCodec::Options& options) override;
185 Result onIncrementalDecode(int* rowsDecoded) override;
186 int onGetFrameCount() override;
187 bool onGetFrameInfo(int, FrameInfo*) const override;
188 int onGetRepetitionCount() override;
189
Nigel Tao2777cd32019-10-29 11:10:25 +1100190 Result seekFrame(WhichDecoder which, int frameIndex);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400191
Nigel Tao2777cd32019-10-29 11:10:25 +1100192 void onGetFrameCountInternal();
193 Result onIncrementalDecodeInternal(int* rowsDecoded);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400194
Nigel Tao2777cd32019-10-29 11:10:25 +1100195 Result resetDecoder(WhichDecoder which);
196 const char* decodeFrameConfig(WhichDecoder which);
197 const char* decodeFrame(WhichDecoder which);
198 void updateNumFullyReceivedFrames(WhichDecoder which);
199
200 SkWuffsFrameHolder fFrameHolder;
201 std::unique_ptr<SkStream> fStream;
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 std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> fDecoders[WhichDecoder::kNumDecoders];
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400207
208 const uint64_t fFirstFrameIOPosition;
Nigel Tao2777cd32019-10-29 11:10:25 +1100209 wuffs_base__frame_config fFrameConfigs[WhichDecoder::kNumDecoders];
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400210 wuffs_base__pixel_buffer fPixelBuffer;
211 wuffs_base__io_buffer fIOBuffer;
212
213 // Incremental decoding state.
Nigel Tao0185b952018-11-08 10:47:24 +1100214 uint8_t* fIncrDecDst;
Nigel Tao2777cd32019-10-29 11:10:25 +1100215 uint64_t fIncrDecReaderIOPosition;
Nigel Tao0185b952018-11-08 10:47:24 +1100216 size_t fIncrDecRowBytes;
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400217 bool fFirstCallToIncrementalDecode;
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400218
219 uint64_t fNumFullyReceivedFrames;
220 std::vector<SkWuffsFrame> fFrames;
221 bool fFramesComplete;
222
Nigel Tao2777cd32019-10-29 11:10:25 +1100223 // If calling an fDecoders[which] method returns an incomplete status, then
224 // fDecoders[which] is suspended in a coroutine (i.e. waiting on I/O or
225 // halted on a non-recoverable error). To keep its internal proof-of-safety
226 // invariants consistent, there's only two things you can safely do with a
227 // suspended Wuffs object: resume the coroutine, or reset all state (memset
228 // to zero and start again).
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400229 //
Nigel Tao2777cd32019-10-29 11:10:25 +1100230 // If fDecoderIsSuspended[which], and we aren't sure that we're going to
231 // resume the coroutine, then we will need to call this->resetDecoder
232 // before calling other fDecoders[which] methods.
233 bool fDecoderIsSuspended[WhichDecoder::kNumDecoders];
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400234
235 uint8_t fBuffer[SK_WUFFS_CODEC_BUFFER_SIZE];
236
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400237 typedef SkScalingCodec INHERITED;
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400238};
239
240// -------------------------------- SkWuffsFrame implementation
241
242SkWuffsFrame::SkWuffsFrame(wuffs_base__frame_config* fc)
243 : INHERITED(fc->index()),
244 fIOPosition(fc->io_position()),
245 fReportedAlpha(wuffs_blend_to_skia_alpha(fc->blend())) {
246 wuffs_base__rect_ie_u32 r = fc->bounds();
247 this->setXYWH(r.min_incl_x, r.min_incl_y, r.width(), r.height());
248 this->setDisposalMethod(wuffs_disposal_to_skia_disposal(fc->disposal()));
249 this->setDuration(fc->duration() / WUFFS_BASE__FLICKS_PER_MILLISECOND);
250 this->setBlend(wuffs_blend_to_skia_blend(fc->blend()));
251}
252
253SkCodec::FrameInfo SkWuffsFrame::frameInfo(bool fullyReceived) const {
Nigel Taoef40e332019-04-05 10:28:40 +1100254 SkCodec::FrameInfo ret;
255 ret.fRequiredFrame = getRequiredFrame();
256 ret.fDuration = getDuration();
257 ret.fFullyReceived = fullyReceived;
258 ret.fAlphaType = hasAlpha() ? kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
259 ret.fDisposalMethod = getDisposalMethod();
260 return ret;
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400261}
262
263uint64_t SkWuffsFrame::ioPosition() const {
264 return fIOPosition;
265}
266
267SkEncodedInfo::Alpha SkWuffsFrame::onReportedAlpha() const {
268 return fReportedAlpha;
269}
270
271// -------------------------------- SkWuffsFrameHolder implementation
272
273void SkWuffsFrameHolder::init(SkWuffsCodec* codec, int width, int height) {
274 fCodec = codec;
275 // Initialize SkFrameHolder's (the superclass) fields.
276 fScreenWidth = width;
277 fScreenHeight = height;
278}
279
280const SkFrame* SkWuffsFrameHolder::onGetFrame(int i) const {
281 return fCodec->frame(i);
282};
283
284// -------------------------------- SkWuffsCodec implementation
285
286SkWuffsCodec::SkWuffsCodec(SkEncodedInfo&& encodedInfo,
287 std::unique_ptr<SkStream> stream,
288 std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> dec,
289 std::unique_ptr<uint8_t, decltype(&sk_free)> pixbuf_ptr,
290 std::unique_ptr<uint8_t, decltype(&sk_free)> workbuf_ptr,
291 size_t workbuf_len,
292 wuffs_base__image_config imgcfg,
293 wuffs_base__pixel_buffer pixbuf,
294 wuffs_base__io_buffer iobuf)
295 : INHERITED(std::move(encodedInfo),
296 skcms_PixelFormat_RGBA_8888,
297 // Pass a nullptr SkStream to the SkCodec constructor. We
298 // manage the stream ourselves, as the default SkCodec behavior
299 // is too trigger-happy on rewinding the stream.
300 nullptr),
Nigel Tao0185b952018-11-08 10:47:24 +1100301 fFrameHolder(),
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400302 fStream(std::move(stream)),
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400303 fPixbufPtr(std::move(pixbuf_ptr)),
304 fWorkbufPtr(std::move(workbuf_ptr)),
305 fWorkbufLen(workbuf_len),
Nigel Tao2777cd32019-10-29 11:10:25 +1100306 fDecoders{
307 std::move(dec),
308 std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)>(nullptr, sk_free),
309 },
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400310 fFirstFrameIOPosition(imgcfg.first_frame_io_position()),
Nigel Tao2777cd32019-10-29 11:10:25 +1100311 fFrameConfigs{
312 wuffs_base__null_frame_config(),
313 wuffs_base__null_frame_config(),
314 },
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400315 fPixelBuffer(pixbuf),
Nigel Tao96c10a02019-09-25 11:08:42 +1000316 fIOBuffer(wuffs_base__empty_io_buffer()),
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400317 fIncrDecDst(nullptr),
Nigel Tao2777cd32019-10-29 11:10:25 +1100318 fIncrDecReaderIOPosition(0),
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400319 fIncrDecRowBytes(0),
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400320 fFirstCallToIncrementalDecode(false),
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400321 fNumFullyReceivedFrames(0),
322 fFramesComplete(false),
Nigel Tao2777cd32019-10-29 11:10:25 +1100323 fDecoderIsSuspended{
324 false,
325 false,
326 } {
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400327 fFrameHolder.init(this, imgcfg.pixcfg.width(), imgcfg.pixcfg.height());
328
329 // Initialize fIOBuffer's fields, copying any outstanding data from iobuf to
330 // fIOBuffer, as iobuf's backing array may not be valid for the lifetime of
331 // this SkWuffsCodec object, but fIOBuffer's backing array (fBuffer) is.
332 SkASSERT(iobuf.data.len == SK_WUFFS_CODEC_BUFFER_SIZE);
333 memmove(fBuffer, iobuf.data.ptr, iobuf.meta.wi);
Nigel Tao48aa2212019-03-09 14:59:11 +1100334 fIOBuffer.data = wuffs_base__make_slice_u8(fBuffer, SK_WUFFS_CODEC_BUFFER_SIZE);
335 fIOBuffer.meta = iobuf.meta;
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400336}
337
338const SkWuffsFrame* SkWuffsCodec::frame(int i) const {
339 if ((0 <= i) && (static_cast<size_t>(i) < fFrames.size())) {
340 return &fFrames[i];
341 }
342 return nullptr;
343}
344
345SkEncodedImageFormat SkWuffsCodec::onGetEncodedFormat() const {
346 return SkEncodedImageFormat::kGIF;
347}
348
349SkCodec::Result SkWuffsCodec::onGetPixels(const SkImageInfo& dstInfo,
350 void* dst,
351 size_t rowBytes,
352 const Options& options,
353 int* rowsDecoded) {
354 SkCodec::Result result = this->onStartIncrementalDecode(dstInfo, dst, rowBytes, options);
355 if (result != kSuccess) {
356 return result;
357 }
358 return this->onIncrementalDecode(rowsDecoded);
359}
360
361const SkFrameHolder* SkWuffsCodec::getFrameHolder() const {
362 return &fFrameHolder;
363}
364
365SkCodec::Result SkWuffsCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo,
366 void* dst,
367 size_t rowBytes,
368 const SkCodec::Options& options) {
Nigel Tao1f1cd1f2019-06-22 17:35:38 +1000369 if (!dst) {
370 return SkCodec::kInvalidParameters;
371 }
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400372 if (options.fSubset) {
373 return SkCodec::kUnimplemented;
374 }
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400375 if (options.fFrameIndex > 0 && SkColorTypeIsAlwaysOpaque(dstInfo.colorType())) {
376 return SkCodec::kInvalidConversion;
377 }
Nigel Tao2777cd32019-10-29 11:10:25 +1100378 SkCodec::Result result = this->seekFrame(WhichDecoder::kIncrDecode, options.fFrameIndex);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400379 if (result != SkCodec::kSuccess) {
380 return result;
381 }
382
Nigel Tao2777cd32019-10-29 11:10:25 +1100383 const char* status = this->decodeFrameConfig(WhichDecoder::kIncrDecode);
Nigel Taob7a1b512019-02-10 12:19:50 +1100384 if (status == wuffs_base__suspension__short_read) {
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -0500385 return SkCodec::kIncompleteInput;
Nigel Taob7a1b512019-02-10 12:19:50 +1100386 } else if (status != nullptr) {
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -0500387 SkCodecPrintf("decodeFrameConfig: %s", status);
388 return SkCodec::kErrorInInput;
389 }
Nigel Taob7a1b512019-02-10 12:19:50 +1100390
Nigel Tao490e6472019-02-14 14:50:53 +1100391 uint32_t src_bits_per_pixel =
392 wuffs_base__pixel_format__bits_per_pixel(fPixelBuffer.pixcfg.pixel_format());
393 if ((src_bits_per_pixel == 0) || (src_bits_per_pixel % 8 != 0)) {
394 return SkCodec::kInternalError;
395 }
396 size_t src_bytes_per_pixel = src_bits_per_pixel / 8;
Nigel Taob7a1b512019-02-10 12:19:50 +1100397
398 // Zero-initialize Wuffs' buffer covering the frame rect.
Nigel Tao2777cd32019-10-29 11:10:25 +1100399 wuffs_base__rect_ie_u32 frame_rect = fFrameConfigs[WhichDecoder::kIncrDecode].bounds();
Nigel Taob7a1b512019-02-10 12:19:50 +1100400 wuffs_base__table_u8 pixels = fPixelBuffer.plane(0);
401 for (uint32_t y = frame_rect.min_incl_y; y < frame_rect.max_excl_y; y++) {
Nigel Tao490e6472019-02-14 14:50:53 +1100402 sk_bzero(pixels.ptr + (y * pixels.stride) + (frame_rect.min_incl_x * src_bytes_per_pixel),
403 frame_rect.width() * src_bytes_per_pixel);
Nigel Taob7a1b512019-02-10 12:19:50 +1100404 }
405
406 fIncrDecDst = static_cast<uint8_t*>(dst);
Nigel Tao2777cd32019-10-29 11:10:25 +1100407 fIncrDecReaderIOPosition = fIOBuffer.reader_io_position();
Nigel Taob7a1b512019-02-10 12:19:50 +1100408 fIncrDecRowBytes = rowBytes;
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400409 fFirstCallToIncrementalDecode = true;
Nigel Taob7a1b512019-02-10 12:19:50 +1100410 return SkCodec::kSuccess;
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400411}
412
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400413static SkAlphaType to_alpha_type(bool opaque) {
414 return opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
Leon Scroggins III9b0ba2c2018-11-19 14:52:37 -0500415}
416
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400417SkCodec::Result SkWuffsCodec::onIncrementalDecode(int* rowsDecoded) {
418 if (!fIncrDecDst) {
419 return SkCodec::kInternalError;
420 }
421
Nigel Tao2777cd32019-10-29 11:10:25 +1100422 // If multiple SkCodec::incrementalDecode calls are made consecutively (or
423 // if SkCodec::incrementalDecode is called immediately after
424 // SkCodec::startIncrementalDecode), then this seek should be a no-op.
425 // However, it is possible to interleave SkCodec::getFrameCount calls in
426 // between SkCodec::incrementalDecode calls, and those other calls may
427 // advance the stream. This seek restores the stream to where the last
428 // SkCodec::startIncrementalDecode or SkCodec::incrementalDecode stopped.
429 if (!seek_buffer(&fIOBuffer, fStream.get(), fIncrDecReaderIOPosition)) {
430 return SkCodec::kInternalError;
431 }
432
433 SkCodec::Result result = this->onIncrementalDecodeInternal(rowsDecoded);
434 if (result == SkCodec::kSuccess) {
435 fIncrDecDst = nullptr;
436 fIncrDecReaderIOPosition = 0;
437 fIncrDecRowBytes = 0;
438 } else {
439 fIncrDecReaderIOPosition = fIOBuffer.reader_io_position();
440 }
441 return result;
442}
443
444SkCodec::Result SkWuffsCodec::onIncrementalDecodeInternal(int* rowsDecoded) {
Leon Scroggins III699d41e2019-02-07 09:25:51 -0500445 SkCodec::Result result = SkCodec::kSuccess;
Nigel Tao2777cd32019-10-29 11:10:25 +1100446 const char* status = this->decodeFrame(WhichDecoder::kIncrDecode);
447 bool independent;
448 SkAlphaType alphaType;
449 const int index = options().fFrameIndex;
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400450 if (index == 0) {
451 independent = true;
452 alphaType = to_alpha_type(getEncodedInfo().opaque());
453 } else {
454 const SkWuffsFrame* f = this->frame(index);
455 independent = f->getRequiredFrame() == SkCodec::kNoFrame;
456 alphaType = to_alpha_type(f->reportedAlpha() == SkEncodedInfo::kOpaque_Alpha);
457 }
Leon Scroggins III699d41e2019-02-07 09:25:51 -0500458 if (status != nullptr) {
459 if (status == wuffs_base__suspension__short_read) {
460 result = SkCodec::kIncompleteInput;
461 } else {
462 SkCodecPrintf("decodeFrame: %s", status);
463 result = SkCodec::kErrorInInput;
464 }
465
466 if (!independent) {
467 // For a dependent frame, we cannot blend the partial result, since
468 // that will overwrite the contribution from prior frames.
469 return result;
470 }
471 }
472
Nigel Tao490e6472019-02-14 14:50:53 +1100473 uint32_t src_bits_per_pixel =
474 wuffs_base__pixel_format__bits_per_pixel(fPixelBuffer.pixcfg.pixel_format());
475 if ((src_bits_per_pixel == 0) || (src_bits_per_pixel % 8 != 0)) {
476 return SkCodec::kInternalError;
477 }
478 size_t src_bytes_per_pixel = src_bits_per_pixel / 8;
479
Nigel Tao2777cd32019-10-29 11:10:25 +1100480 wuffs_base__rect_ie_u32 frame_rect = fFrameConfigs[WhichDecoder::kIncrDecode].bounds();
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400481 if (fFirstCallToIncrementalDecode) {
Nigel Tao490e6472019-02-14 14:50:53 +1100482 if (frame_rect.width() > (SIZE_MAX / src_bytes_per_pixel)) {
483 return SkCodec::kInternalError;
484 }
485
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400486 auto bounds = SkIRect::MakeLTRB(frame_rect.min_incl_x, frame_rect.min_incl_y,
487 frame_rect.max_excl_x, frame_rect.max_excl_y);
488
Leon Scroggins IIIcb6b8842018-12-04 13:55:13 -0500489 // If the frame rect does not fill the output, ensure that those pixels are not
Nigel Taob7a1b512019-02-10 12:19:50 +1100490 // left uninitialized.
Leon Scroggins III44076362019-02-15 13:56:44 -0500491 if (independent && (bounds != this->bounds() || result != kSuccess)) {
Nigel Tao2777cd32019-10-29 11:10:25 +1100492 SkSampler::Fill(dstInfo(), fIncrDecDst, fIncrDecRowBytes, options().fZeroInitialized);
Leon Scroggins III9b0ba2c2018-11-19 14:52:37 -0500493 }
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400494 fFirstCallToIncrementalDecode = false;
495 } else {
496 // Existing clients intend to only show frames beyond the first if they
497 // are complete (based on FrameInfo::fFullyReceived), since it might
498 // look jarring to draw a partial frame over an existing frame. If they
499 // changed their behavior and expected to continue decoding a partial
500 // frame after the first one, we'll need to update our blending code.
501 // Otherwise, if the frame were interlaced and not independent, the
502 // second pass may have an overlapping dirty_rect with the first,
503 // resulting in blending with the first pass.
504 SkASSERT(index == 0);
Nigel Tao9859ef82019-02-13 13:20:02 +1100505 }
Nigel Tao0185b952018-11-08 10:47:24 +1100506
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400507 if (rowsDecoded) {
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400508 *rowsDecoded = dstInfo().height();
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400509 }
510
Leon Scroggins IIIdad4bfc2018-12-10 12:37:10 -0500511 // If the frame's dirty rect is empty, no need to swizzle.
Nigel Tao2777cd32019-10-29 11:10:25 +1100512 wuffs_base__rect_ie_u32 dirty_rect = fDecoders[WhichDecoder::kIncrDecode]->frame_dirty_rect();
Leon Scroggins IIIdad4bfc2018-12-10 12:37:10 -0500513 if (!dirty_rect.is_empty()) {
Nigel Tao490e6472019-02-14 14:50:53 +1100514 wuffs_base__table_u8 pixels = fPixelBuffer.plane(0);
Leon Scroggins III7a3805c2018-12-07 09:21:30 -0500515
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400516 // The Wuffs model is that the dst buffer is the image, not the frame.
517 // The expectation is that you allocate the buffer once, but re-use it
518 // for the N frames, regardless of each frame's top-left co-ordinate.
519 //
520 // To get from the start (in the X-direction) of the image to the start
521 // of the dirty_rect, we adjust s by (dirty_rect.min_incl_x * src_bytes_per_pixel).
Nigel Tao2777cd32019-10-29 11:10:25 +1100522 uint8_t* s = pixels.ptr + (dirty_rect.min_incl_y * pixels.stride) +
523 (dirty_rect.min_incl_x * src_bytes_per_pixel);
Leon Scroggins III7a3805c2018-12-07 09:21:30 -0500524
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400525 // Currently, this is only used for GIF, which will never have an ICC profile. When it is
526 // used for other formats that might have one, we will need to transform from profiles that
527 // do not have corresponding SkColorSpaces.
528 SkASSERT(!getEncodedInfo().profile());
529
Nigel Tao2777cd32019-10-29 11:10:25 +1100530 auto srcInfo =
531 getInfo().makeWH(dirty_rect.width(), dirty_rect.height()).makeAlphaType(alphaType);
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400532 SkBitmap src;
533 src.installPixels(srcInfo, s, pixels.stride);
534 SkPaint paint;
535 if (independent) {
536 paint.setBlendMode(SkBlendMode::kSrc);
Leon Scroggins III7a3805c2018-12-07 09:21:30 -0500537 }
Leon Scroggins III70d8f4f2019-04-01 12:57:46 -0400538
539 SkDraw draw;
540 draw.fDst.reset(dstInfo(), fIncrDecDst, fIncrDecRowBytes);
541 SkMatrix matrix = SkMatrix::MakeRectToRect(SkRect::Make(this->dimensions()),
542 SkRect::Make(this->dstInfo().dimensions()),
543 SkMatrix::kFill_ScaleToFit);
544 draw.fMatrix = &matrix;
545 SkRasterClip rc(SkIRect::MakeSize(this->dstInfo().dimensions()));
546 draw.fRC = &rc;
547
548 SkMatrix translate = SkMatrix::MakeTrans(dirty_rect.min_incl_x, dirty_rect.min_incl_y);
549 draw.drawBitmap(src, translate, nullptr, paint);
Leon Scroggins III7a3805c2018-12-07 09:21:30 -0500550 }
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400551 return result;
552}
553
554int SkWuffsCodec::onGetFrameCount() {
Nigel Tao2777cd32019-10-29 11:10:25 +1100555 if (!fFramesComplete) {
556 this->onGetFrameCountInternal();
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400557 }
558 return fFrames.size();
559}
560
Nigel Tao2777cd32019-10-29 11:10:25 +1100561void SkWuffsCodec::onGetFrameCountInternal() {
562 if (!seek_buffer(&fIOBuffer, fStream.get(), 0)) {
563 return;
564 }
565 if (!fDecoders[WhichDecoder::kFrameCount]) {
566 void* decoder_raw = sk_malloc_canfail(sizeof__wuffs_gif__decoder());
567 if (!decoder_raw) {
568 return;
569 }
570 std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> decoder(
571 reinterpret_cast<wuffs_gif__decoder*>(decoder_raw), &sk_free);
572 fDecoders[WhichDecoder::kFrameCount] = std::move(decoder);
573 }
574 reset_and_decode_image_config(fDecoders[WhichDecoder::kFrameCount].get(), nullptr, &fIOBuffer,
575 fStream.get());
Nigel Tao2777cd32019-10-29 11:10:25 +1100576
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400577 size_t n = fFrames.size();
578 int i = n ? n - 1 : 0;
Nigel Tao2777cd32019-10-29 11:10:25 +1100579 if (this->seekFrame(WhichDecoder::kFrameCount, i) != SkCodec::kSuccess) {
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400580 return;
581 }
582
583 // Iterate through the frames, converting from Wuffs'
584 // wuffs_base__frame_config type to Skia's SkWuffsFrame type.
585 for (; i < INT_MAX; i++) {
Nigel Tao2777cd32019-10-29 11:10:25 +1100586 const char* status = this->decodeFrameConfig(WhichDecoder::kFrameCount);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400587 if (status == nullptr) {
588 // No-op.
589 } else if (status == wuffs_base__warning__end_of_data) {
590 break;
591 } else {
592 return;
593 }
594
595 if (static_cast<size_t>(i) < fFrames.size()) {
596 continue;
597 }
Nigel Tao2777cd32019-10-29 11:10:25 +1100598 fFrames.emplace_back(&fFrameConfigs[WhichDecoder::kFrameCount]);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400599 SkWuffsFrame* f = &fFrames[fFrames.size() - 1];
600 fFrameHolder.setAlphaAndRequiredFrame(f);
601 }
602
603 fFramesComplete = true;
Nigel Tao5b271462019-11-12 21:02:20 +1100604
605 // We've seen the end of the animation. There'll be no more frames, so we
606 // no longer need the kFrameCount decoder. Releasing it earlier than the
607 // SkWuffsCodec destructor might help peak memory use.
608 fDecoders[WhichDecoder::kFrameCount].reset(nullptr);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400609}
610
Nigel Taocdc92382019-10-31 08:36:53 +1100611bool SkWuffsCodec::onGetFrameInfo(int i, SkCodec::FrameInfo* frameInfo) const {
612 const SkWuffsFrame* f = this->frame(i);
613 if (!f) {
614 return false;
615 }
616 if (frameInfo) {
617 *frameInfo = f->frameInfo(static_cast<uint64_t>(i) < this->fNumFullyReceivedFrames);
618 }
619 return true;
620}
621
622int SkWuffsCodec::onGetRepetitionCount() {
623 // Convert from Wuffs's loop count to Skia's repeat count. Wuffs' uint32_t
624 // number is how many times to play the loop. Skia's int number is how many
625 // times to play the loop *after the first play*. Wuffs and Skia use 0 and
626 // kRepetitionCountInfinite respectively to mean loop forever.
627 uint32_t n = fDecoders[WhichDecoder::kIncrDecode]->num_animation_loops();
628 if (n == 0) {
629 return SkCodec::kRepetitionCountInfinite;
630 }
631 n--;
632 return n < INT_MAX ? n : INT_MAX;
633}
634
Nigel Tao2777cd32019-10-29 11:10:25 +1100635SkCodec::Result SkWuffsCodec::seekFrame(WhichDecoder which, int frameIndex) {
636 if (fDecoderIsSuspended[which]) {
637 SkCodec::Result res = this->resetDecoder(which);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400638 if (res != SkCodec::kSuccess) {
639 return res;
640 }
641 }
642
643 uint64_t pos = 0;
644 if (frameIndex < 0) {
645 return SkCodec::kInternalError;
646 } else if (frameIndex == 0) {
647 pos = fFirstFrameIOPosition;
648 } else if (static_cast<size_t>(frameIndex) < fFrames.size()) {
649 pos = fFrames[frameIndex].ioPosition();
650 } else {
651 return SkCodec::kInternalError;
652 }
653
654 if (!seek_buffer(&fIOBuffer, fStream.get(), pos)) {
655 return SkCodec::kInternalError;
656 }
Nigel Tao2777cd32019-10-29 11:10:25 +1100657 const char* status =
658 fDecoders[which]->restart_frame(frameIndex, fIOBuffer.reader_io_position());
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400659 if (status != nullptr) {
660 return SkCodec::kInternalError;
661 }
662 return SkCodec::kSuccess;
663}
664
665// An overview of the Wuffs decoding API:
666//
667// An animated image (such as GIF) has an image header and then N frames. The
668// image header gives e.g. the overall image's width and height. Each frame
669// consists of a frame header (e.g. frame rectangle bounds, display duration)
670// and a payload (the pixels).
671//
672// In Wuffs terminology, there is one image config and then N pairs of
673// (frame_config, frame). To decode everything (without knowing N in advance)
674// sequentially:
675// - call wuffs_gif__decoder::decode_image_config
676// - while (true) {
677// - call wuffs_gif__decoder::decode_frame_config
678// - if that returned wuffs_base__warning__end_of_data, break
679// - call wuffs_gif__decoder::decode_frame
680// - }
681//
682// The first argument to each decode_foo method is the destination struct to
683// store the decoded information.
684//
685// For random (instead of sequential) access to an image's frames, call
686// wuffs_gif__decoder::restart_frame to prepare to decode the i'th frame.
687// Essentially, it restores the state to be at the top of the while loop above.
688// The wuffs_base__io_buffer's reader position will also need to be set at the
689// right point in the source data stream. The position for the i'th frame is
690// calculated by the i'th decode_frame_config call. You can only call
691// restart_frame after decode_image_config is called, explicitly or implicitly
692// (see below), as decoding a single frame might require for-all-frames
693// information like the overall image dimensions and the global palette.
694//
695// All of those decode_xxx calls are optional. For example, if
696// decode_image_config is not called, then the first decode_frame_config call
697// will implicitly parse and verify the image header, before parsing the first
698// frame's header. Similarly, you can call only decode_frame N times, without
699// calling decode_image_config or decode_frame_config, if you already know
700// metadata like N and each frame's rectangle bounds by some other means (e.g.
701// this is a first party, statically known image).
702//
703// Specifically, starting with an unknown (but re-windable) GIF image, if you
704// want to just find N (i.e. count the number of frames), you can loop calling
705// only the decode_frame_config method and avoid calling the more expensive
706// decode_frame method. In terms of the underlying GIF image format, this will
707// skip over the LZW-encoded pixel data, avoiding the costly LZW decompression.
708//
709// Those decode_xxx methods are also suspendible. They will return early (with
710// a status code that is_suspendible and therefore isn't is_complete) if there
711// isn't enough source data to complete the operation: an incremental decode.
712// Calling decode_xxx again with additional source data will resume the
713// previous operation, instead of starting a new operation. Calling decode_yyy
714// whilst decode_xxx is suspended will result in an error.
715//
716// Once an error is encountered, whether from invalid source data or from a
717// programming error such as calling decode_yyy while suspended in decode_xxx,
718// all subsequent calls will be no-ops that return an error. To reset the
719// decoder into something that does productive work, memset the entire struct
720// to zero, check the Wuffs version and then, in order to be able to call
721// restart_frame, call decode_image_config. The io_buffer and its associated
722// stream will also need to be rewound.
723
724static SkCodec::Result reset_and_decode_image_config(wuffs_gif__decoder* decoder,
725 wuffs_base__image_config* imgcfg,
726 wuffs_base__io_buffer* b,
727 SkStream* s) {
Nigel Taoe39c8842019-02-27 15:57:34 +1100728 // Calling decoder->initialize will memset it to zero.
729 const char* status = decoder->initialize(sizeof__wuffs_gif__decoder(), WUFFS_VERSION, 0);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400730 if (status != nullptr) {
Nigel Taoe39c8842019-02-27 15:57:34 +1100731 SkCodecPrintf("initialize: %s", status);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400732 return SkCodec::kInternalError;
733 }
734 while (true) {
Nigel Tao6447a1a2019-09-14 12:01:00 +1000735 status = decoder->decode_image_config(imgcfg, b);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400736 if (status == nullptr) {
Nigel Tao490e6472019-02-14 14:50:53 +1100737 break;
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400738 } else if (status != wuffs_base__suspension__short_read) {
739 SkCodecPrintf("decode_image_config: %s", status);
740 return SkCodec::kErrorInInput;
741 } else if (!fill_buffer(b, s)) {
742 return SkCodec::kIncompleteInput;
743 }
744 }
Nigel Tao490e6472019-02-14 14:50:53 +1100745
746 // A GIF image's natural color model is indexed color: 1 byte per pixel,
747 // indexing a 256-element palette.
748 //
749 // For Skia, we override that to decode to 4 bytes per pixel, BGRA or RGBA.
750 wuffs_base__pixel_format pixfmt = 0;
751 switch (kN32_SkColorType) {
752 case kBGRA_8888_SkColorType:
753 pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL;
754 break;
755 case kRGBA_8888_SkColorType:
756 pixfmt = WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL;
757 break;
758 default:
759 return SkCodec::kInternalError;
760 }
Leon Scroggins III587edab2019-03-22 15:42:19 -0400761 if (imgcfg) {
762 imgcfg->pixcfg.set(pixfmt, WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, imgcfg->pixcfg.width(),
763 imgcfg->pixcfg.height());
764 }
Nigel Tao490e6472019-02-14 14:50:53 +1100765
766 return SkCodec::kSuccess;
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400767}
768
Nigel Tao2777cd32019-10-29 11:10:25 +1100769SkCodec::Result SkWuffsCodec::resetDecoder(WhichDecoder which) {
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400770 if (!fStream->rewind()) {
771 return SkCodec::kInternalError;
772 }
Nigel Tao96c10a02019-09-25 11:08:42 +1000773 fIOBuffer.meta = wuffs_base__empty_io_buffer_meta();
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400774
775 SkCodec::Result result =
Nigel Tao2777cd32019-10-29 11:10:25 +1100776 reset_and_decode_image_config(fDecoders[which].get(), nullptr, &fIOBuffer, fStream.get());
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400777 if (result == SkCodec::kIncompleteInput) {
778 return SkCodec::kInternalError;
779 } else if (result != SkCodec::kSuccess) {
780 return result;
781 }
782
Nigel Tao2777cd32019-10-29 11:10:25 +1100783 fDecoderIsSuspended[which] = false;
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400784 return SkCodec::kSuccess;
785}
786
Nigel Tao2777cd32019-10-29 11:10:25 +1100787const char* SkWuffsCodec::decodeFrameConfig(WhichDecoder which) {
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400788 while (true) {
Nigel Tao48aa2212019-03-09 14:59:11 +1100789 const char* status =
Nigel Tao2777cd32019-10-29 11:10:25 +1100790 fDecoders[which]->decode_frame_config(&fFrameConfigs[which], &fIOBuffer);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400791 if ((status == wuffs_base__suspension__short_read) &&
792 fill_buffer(&fIOBuffer, fStream.get())) {
793 continue;
794 }
Nigel Tao2777cd32019-10-29 11:10:25 +1100795 fDecoderIsSuspended[which] = !wuffs_base__status__is_complete(status);
796 this->updateNumFullyReceivedFrames(which);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400797 return status;
798 }
799}
800
Nigel Tao2777cd32019-10-29 11:10:25 +1100801const char* SkWuffsCodec::decodeFrame(WhichDecoder which) {
802 while (true) {
803 const char* status = fDecoders[which]->decode_frame(
804 &fPixelBuffer, &fIOBuffer, wuffs_base__make_slice_u8(fWorkbufPtr.get(), fWorkbufLen),
805 NULL);
806 if ((status == wuffs_base__suspension__short_read) &&
807 fill_buffer(&fIOBuffer, fStream.get())) {
808 continue;
809 }
810 fDecoderIsSuspended[which] = !wuffs_base__status__is_complete(status);
811 this->updateNumFullyReceivedFrames(which);
812 return status;
813 }
814}
815
816void SkWuffsCodec::updateNumFullyReceivedFrames(WhichDecoder which) {
Nigel Tao6af1edc2019-01-19 15:12:39 +1100817 // num_decoded_frames's return value, n, can change over time, both up and
818 // down, as we seek back and forth in the underlying stream.
819 // fNumFullyReceivedFrames is the highest n we've seen.
Nigel Tao2777cd32019-10-29 11:10:25 +1100820 uint64_t n = fDecoders[which]->num_decoded_frames();
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400821 if (fNumFullyReceivedFrames < n) {
822 fNumFullyReceivedFrames = n;
823 }
824}
825
826// -------------------------------- SkWuffsCodec.h functions
827
828bool SkWuffsCodec_IsFormat(const void* buf, size_t bytesRead) {
829 constexpr const char* gif_ptr = "GIF8";
830 constexpr size_t gif_len = 4;
831 return (bytesRead >= gif_len) && (memcmp(buf, gif_ptr, gif_len) == 0);
832}
833
834std::unique_ptr<SkCodec> SkWuffsCodec_MakeFromStream(std::unique_ptr<SkStream> stream,
835 SkCodec::Result* result) {
Nigel Tao48aa2212019-03-09 14:59:11 +1100836 uint8_t buffer[SK_WUFFS_CODEC_BUFFER_SIZE];
837 wuffs_base__io_buffer iobuf =
838 wuffs_base__make_io_buffer(wuffs_base__make_slice_u8(buffer, SK_WUFFS_CODEC_BUFFER_SIZE),
Nigel Tao96c10a02019-09-25 11:08:42 +1000839 wuffs_base__empty_io_buffer_meta());
Nigel Tao48aa2212019-03-09 14:59:11 +1100840 wuffs_base__image_config imgcfg = wuffs_base__null_image_config();
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400841
842 // Wuffs is primarily a C library, not a C++ one. Furthermore, outside of
843 // the wuffs_base__etc types, the sizeof a file format specific type like
844 // GIF's wuffs_gif__decoder can vary between Wuffs versions. If p is of
845 // type wuffs_gif__decoder*, then the supported API treats p as a pointer
846 // to an opaque type: a private implementation detail. The API is always
847 // "set_foo(p, etc)" and not "p->foo = etc".
848 //
849 // See https://en.wikipedia.org/wiki/Opaque_pointer#C
850 //
851 // Thus, we don't use C++'s new operator (which requires knowing the sizeof
852 // the struct at compile time). Instead, we use sk_malloc_canfail, with
853 // sizeof__wuffs_gif__decoder returning the appropriate value for the
854 // (statically or dynamically) linked version of the Wuffs library.
855 //
856 // As a C (not C++) library, none of the Wuffs types have constructors or
857 // destructors.
858 //
859 // In RAII style, we can still use std::unique_ptr with these pointers, but
860 // we pair the pointer with sk_free instead of C++'s delete.
861 void* decoder_raw = sk_malloc_canfail(sizeof__wuffs_gif__decoder());
862 if (!decoder_raw) {
863 *result = SkCodec::kInternalError;
864 return nullptr;
865 }
866 std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> decoder(
867 reinterpret_cast<wuffs_gif__decoder*>(decoder_raw), &sk_free);
868
869 SkCodec::Result reset_result =
870 reset_and_decode_image_config(decoder.get(), &imgcfg, &iobuf, stream.get());
871 if (reset_result != SkCodec::kSuccess) {
872 *result = reset_result;
873 return nullptr;
874 }
875
876 uint32_t width = imgcfg.pixcfg.width();
877 uint32_t height = imgcfg.pixcfg.height();
878 if ((width == 0) || (width > INT_MAX) || (height == 0) || (height > INT_MAX)) {
879 *result = SkCodec::kInvalidInput;
880 return nullptr;
881 }
882
Nigel Tao6af1edc2019-01-19 15:12:39 +1100883 uint64_t workbuf_len = decoder->workbuf_len().max_incl;
Nigel Tao22e86242019-01-26 16:04:01 +1100884 void* workbuf_ptr_raw = nullptr;
885 if (workbuf_len) {
886 workbuf_ptr_raw = workbuf_len <= SIZE_MAX ? sk_malloc_canfail(workbuf_len) : nullptr;
887 if (!workbuf_ptr_raw) {
888 *result = SkCodec::kInternalError;
889 return nullptr;
890 }
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400891 }
892 std::unique_ptr<uint8_t, decltype(&sk_free)> workbuf_ptr(
893 reinterpret_cast<uint8_t*>(workbuf_ptr_raw), &sk_free);
894
895 uint64_t pixbuf_len = imgcfg.pixcfg.pixbuf_len();
896 void* pixbuf_ptr_raw = pixbuf_len <= SIZE_MAX ? sk_malloc_canfail(pixbuf_len) : nullptr;
897 if (!pixbuf_ptr_raw) {
898 *result = SkCodec::kInternalError;
899 return nullptr;
900 }
901 std::unique_ptr<uint8_t, decltype(&sk_free)> pixbuf_ptr(
902 reinterpret_cast<uint8_t*>(pixbuf_ptr_raw), &sk_free);
Nigel Tao48aa2212019-03-09 14:59:11 +1100903 wuffs_base__pixel_buffer pixbuf = wuffs_base__null_pixel_buffer();
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400904
Nigel Tao48aa2212019-03-09 14:59:11 +1100905 const char* status = pixbuf.set_from_slice(
906 &imgcfg.pixcfg, wuffs_base__make_slice_u8(pixbuf_ptr.get(), SkToSizeT(pixbuf_len)));
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400907 if (status != nullptr) {
908 SkCodecPrintf("set_from_slice: %s", status);
909 *result = SkCodec::kInternalError;
910 return nullptr;
911 }
912
Nigel Tao490e6472019-02-14 14:50:53 +1100913 SkEncodedInfo::Color color =
914 (imgcfg.pixcfg.pixel_format() == WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL)
915 ? SkEncodedInfo::kBGRA_Color
916 : SkEncodedInfo::kRGBA_Color;
917
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400918 // In Skia's API, the alpha we calculate here and return is only for the
919 // first frame.
920 SkEncodedInfo::Alpha alpha = imgcfg.first_frame_is_opaque() ? SkEncodedInfo::kOpaque_Alpha
921 : SkEncodedInfo::kBinary_Alpha;
922
Nigel Tao490e6472019-02-14 14:50:53 +1100923 SkEncodedInfo encodedInfo = SkEncodedInfo::Make(width, height, color, alpha, 8);
Leon Scroggins IIIe93ec682018-10-26 09:25:51 -0400924
925 *result = SkCodec::kSuccess;
926 return std::unique_ptr<SkCodec>(new SkWuffsCodec(
927 std::move(encodedInfo), std::move(stream), std::move(decoder), std::move(pixbuf_ptr),
928 std::move(workbuf_ptr), workbuf_len, imgcfg, pixbuf, iobuf));
929}