1// Copyright 2015 Google Inc.
2// Use of this source code is governed by the BSD-3-Clause license that can be
3// found in the LICENSE.md file.
4#ifndef SkLibGifCodec_DEFINED
5#define SkLibGifCodec_DEFINED
6
7#include "SkGifImageReader.h"
8
9#include "include/codec/SkCodec.h"
10#include "include/codec/SkCodecAnimation.h"
11#include "include/core/SkColorSpace.h"
12#include "include/core/SkImageInfo.h"
13#include "src/codec/SkColorTable.h"
14#include "src/codec/SkSwizzler.h"
15
16/*
17 *
18 * This class implements the decoding for gif images
19 *
20 */
21class SkLibGifCodec : public SkCodec {
22public:
23 static bool IsGif(const void*, size_t);
24
25 /*
26 * Assumes IsGif was called and returned true
27 * Reads enough of the stream to determine the image format
28 */
29 static std::unique_ptr<SkCodec> MakeFromStream(std::unique_ptr<SkStream>, Result*);
30
31 // Callback for SkGifImageReader when a row is available.
32 void haveDecodedRow(int frameIndex, const unsigned char* rowBegin,
33 int rowNumber, int repeatCount, bool writeTransparentPixels);
34 /*
35 * Creates an instance of the decoder
36 * Called only by NewFromStream
37 * Takes ownership of the SkGifImageReader
38 */
39 SkLibGifCodec(SkEncodedInfo&&, SkGifImageReader*);
40
41protected:
42 /*
43 * Performs the full gif decode
44 */
45 Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&,
46 int*) override;
47
48 SkEncodedImageFormat onGetEncodedFormat() const override {
49 return SkEncodedImageFormat::kGIF;
50 }
51
52 bool onRewind() override;
53
54 int onGetFrameCount() override;
55 bool onGetFrameInfo(int, FrameInfo*) const override;
56 int onGetRepetitionCount() override;
57
58 Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t,
59 const SkCodec::Options&) override;
60
61 Result onIncrementalDecode(int*) override;
62
63 const SkFrameHolder* getFrameHolder() const override {
64 return fReader.get();
65 }
66
67private:
68
69 /*
70 * Initializes the color table that we will use for decoding.
71 *
72 * @param dstInfo Contains the requested dst color type.
73 * @param frameIndex Frame whose color table to use.
74 */
75 void initializeColorTable(const SkImageInfo& dstInfo, int frameIndex);
76
77 /*
78 * Does necessary setup, including setting up the color table and swizzler.
79 */
80 Result prepareToDecode(const SkImageInfo& dstInfo, const Options& opts);
81
82 /*
83 * Initializes the swizzler.
84 *
85 * @param dstInfo Output image information. Dimensions may have been
86 * adjusted if the image frame size does not match the size
87 * indicated in the header.
88 * @param frameIndex Which frame we are decoding. This determines the frameRect
89 * to use.
90 */
91 void initializeSwizzler(const SkImageInfo& dstInfo, int frameIndex);
92
93 SkSampler* getSampler(bool createIfNecessary) override {
94 SkASSERT(fSwizzler);
95 return fSwizzler.get();
96 }
97
98 /*
99 * Recursive function to decode a frame.
100 *
101 * @param firstAttempt Whether this is the first call to decodeFrame since
102 * starting. e.g. true in onGetPixels, and true in the
103 * first call to onIncrementalDecode after calling
104 * onStartIncrementalDecode.
105 * When true, this method may have to initialize the
106 * frame, for example by filling or decoding the prior
107 * frame.
108 * @param opts Options for decoding. May be different from
109 * this->options() for decoding prior frames. Specifies
110 * the frame to decode and whether the prior frame has
111 * already been decoded to fDst. If not, and the frame
112 * is not independent, this method will recursively
113 * decode the frame it depends on.
114 * @param rowsDecoded Out-parameter to report the total number of rows
115 * that have been decoded (or at least written to, if
116 * it had to fill), including rows decoded by prior
117 * calls to onIncrementalDecode.
118 * @return kSuccess if the frame is complete, kIncompleteInput
119 * otherwise.
120 */
121 Result decodeFrame(bool firstAttempt, const Options& opts, int* rowsDecoded);
122
123 /*
124 * Swizzles and color xforms (if necessary) into dst.
125 */
126 void applyXformRow(const SkImageInfo& dstInfo, void* dst, const uint8_t* src) const;
127
128 std::unique_ptr<SkGifImageReader> fReader;
129 std::unique_ptr<uint8_t[]> fTmpBuffer;
130 std::unique_ptr<SkSwizzler> fSwizzler;
131 sk_sp<SkColorTable> fCurrColorTable;
132 // We may create a dummy table if there is not a Map in the input data. In
133 // that case, we set this value to false, and we can skip a lot of decoding
134 // work (which would not be meaningful anyway). We create a "fake"/"dummy"
135 // one in that case, so the client and the swizzler have something to draw.
136 bool fCurrColorTableIsReal;
137 // Whether the background was filled.
138 bool fFilledBackground;
139 // True on the first call to onIncrementalDecode. This value is passed to
140 // decodeFrame.
141 bool fFirstCallToIncrementalDecode;
142
143 void* fDst;
144 size_t fDstRowBytes;
145
146 // Updated inside haveDecodedRow when rows are decoded, unless we filled
147 // the background, in which case it is set once and left alone.
148 int fRowsDecoded;
149 std::unique_ptr<uint32_t[]> fXformBuffer;
150
151 typedef SkCodec INHERITED;
152};
153#endif // SkLibGifCodec_DEFINED
154