SkGifCodec.h revision 39b2d5a1ac4171aba0e92cb3f9882f62e5730e3e
1/*
2 * Copyright 2015 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 "SkCodec.h"
9#include "SkColorTable.h"
10#include "SkImageInfo.h"
11#include "SkSwizzler.h"
12
13struct GifFileType;
14struct SavedImage;
15
16/*
17 *
18 * This class implements the decoding for gif images
19 *
20 */
21class SkGifCodec : public SkCodec {
22public:
23    static bool IsGif(const void*, size_t);
24
25    /*
26     * Assumes IsGif was called and returned true
27     * Creates a gif decoder
28     * Reads enough of the stream to determine the image format
29     */
30    static SkCodec* NewFromStream(SkStream*);
31
32protected:
33
34    /*
35     * Read enough of the stream to initialize the SkGifCodec.
36     * Returns a bool representing success or failure.
37     *
38     * @param codecOut
39     * If it returned true, and codecOut was not nullptr,
40     * codecOut will be set to a new SkGifCodec.
41     *
42     * @param gifOut
43     * If it returned true, and codecOut was nullptr,
44     * gifOut must be non-nullptr and gifOut will be set to a new
45     * GifFileType pointer.
46     *
47     * @param stream
48     * Deleted on failure.
49     * codecOut will take ownership of it in the case where we created a codec.
50     * Ownership is unchanged when we returned a gifOut.
51     *
52     */
53    static bool ReadHeader(SkStream* stream, SkCodec** codecOut,
54            GifFileType** gifOut);
55
56    /*
57     * Performs the full gif decode
58     */
59    Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&,
60            SkPMColor*, int*, int*) override;
61
62    SkEncodedFormat onGetEncodedFormat() const override {
63        return kGIF_SkEncodedFormat;
64    }
65
66    bool onRewind() override;
67
68    uint32_t onGetFillValue(SkColorType) const override;
69
70    int onOutputScanline(int inputScanline) const override;
71
72private:
73
74    /*
75     * A gif can contain multiple image frames.  We will only decode the first
76     * frame.  This function reads up to the first image frame, processing
77     * transparency and/or animation information that comes before the image
78     * data.
79     *
80     * @param gif        Pointer to the library type that manages the gif decode
81     * @param transIndex This call will set the transparent index based on the
82     *                   extension data.
83     */
84     static Result ReadUpToFirstImage(GifFileType* gif, uint32_t* transIndex);
85
86     /*
87      * A gif may contain many image frames, all of different sizes.
88      * This function checks if the gif dimensions are valid, based on the frame
89      * dimensions, and corrects the gif dimensions if necessary.
90      *
91      * @param gif       Pointer to the library type that manages the gif decode
92      * @param size      Size of the image that we will decode.
93      *                  Will be set by this function if the return value is true.
94      * @param frameRect Contains the dimenions and offset of the first image frame.
95      *                  Will be set by this function if the return value is true.
96      *
97      * @return true on success, false otherwise
98      */
99     static bool GetDimensions(GifFileType* gif, SkISize* size, SkIRect* frameRect);
100
101    /*
102     * Initializes the color table that we will use for decoding.
103     *
104     * @param dstInfo         Contains the requested dst color type.
105     * @param inputColorPtr   Copies the encoded color table to the client's
106     *                        input color table if the client requests kIndex8.
107     * @param inputColorCount If the client requests kIndex8, sets
108     *                        inputColorCount to 256.  Since gifs always
109     *                        contain 8-bit indices, we need a 256 entry color
110     *                        table to ensure that indexing is always in
111     *                        bounds.
112     */
113    void initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* colorPtr,
114            int* inputColorCount);
115
116   /*
117    * Checks for invalid inputs and calls setFrameDimensions(), and
118    * initializeColorTable() in the proper sequence.
119    */
120    Result prepareToDecode(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr,
121            int* inputColorCount, const Options& opts);
122
123    /*
124     * Initializes the swizzler.
125     *
126     * @param dstInfo  Output image information.  Dimensions may have been
127     *                 adjusted if the image frame size does not match the size
128     *                 indicated in the header.
129     * @param options  Informs the swizzler if destination memory is zero initialized.
130     *                 Contains subset information.
131     */
132    void initializeSwizzler(const SkImageInfo& dstInfo,
133            const Options& options);
134
135    SkSampler* getSampler(bool createIfNecessary) override {
136        SkASSERT(fSwizzler);
137        return fSwizzler;
138    }
139
140    /*
141     * @return true if the read is successful and false if the read fails.
142     */
143    bool readRow();
144
145    Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opts,
146                   SkPMColor inputColorPtr[], int* inputColorCount) override;
147
148    int onGetScanlines(void* dst, int count, size_t rowBytes) override;
149
150    bool onSkipScanlines(int count) override;
151
152    /*
153     * For a scanline decode of "count" lines, this function indicates how
154     * many of the "count" lines should be skipped until we reach the top of
155     * the image frame and how many of the "count" lines are actually inside
156     * the image frame.
157     *
158     * @param count           The number of scanlines requested.
159     * @param rowsBeforeFrame Output variable.  The number of lines before
160     *                        we reach the top of the image frame.
161     * @param rowsInFrame     Output variable.  The number of lines to decode
162     *                        inside the image frame.
163     */
164    void handleScanlineFrame(int count, int* rowsBeforeFrame, int* rowsInFrame);
165
166    SkScanlineOrder onGetScanlineOrder() const override;
167
168    /*
169     * This function cleans up the gif object after the decode completes
170     * It is used in a SkAutoTCallIProc template
171     */
172    static void CloseGif(GifFileType* gif);
173
174    /*
175     * Frees any extension data used in the decode
176     * Used in a SkAutoTCallVProc
177     */
178    static void FreeExtension(SavedImage* image);
179
180    /*
181     * Creates an instance of the decoder
182     * Called only by NewFromStream
183     *
184     * @param srcInfo contains the source width and height
185     * @param stream the stream of image data
186     * @param gif pointer to library type that manages gif decode
187     *            takes ownership
188     * @param transIndex  The transparent index.  An invalid value
189     *            indicates that there is no transparent index.
190     */
191    SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, GifFileType* gif, uint32_t transIndex,
192            const SkIRect& frameRect, bool frameIsSubset);
193
194    SkAutoTCallVProc<GifFileType, CloseGif> fGif; // owned
195    SkAutoTDeleteArray<uint8_t>             fSrcBuffer;
196    const SkIRect                           fFrameRect;
197    const uint32_t                          fTransIndex;
198    uint32_t                                fFillIndex;
199    const bool                              fFrameIsSubset;
200    SkAutoTDelete<SkSwizzler>               fSwizzler;
201    SkAutoTUnref<SkColorTable>              fColorTable;
202
203    typedef SkCodec INHERITED;
204};
205