More cleanup in GIFImageReader
[WebKit-https.git] / Source / WebCore / platform / image-decoders / gif / GIFImageReader.h
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is Mozilla Communicator client code.
16  *
17  * The Initial Developer of the Original Code is
18  * Netscape Communications Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 1998
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either the GNU General Public License Version 2 or later (the "GPL"), or
26  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the MPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the MPL, the GPL or the LGPL.
35  *
36  * ***** END LICENSE BLOCK ***** */
37
38 #ifndef GIFImageReader_h
39 #define GIFImageReader_h
40
41 // Define ourselves as the clientPtr.  Mozilla just hacked their C++ callback class into this old C decoder,
42 // so we will too.
43 #include "GIFImageDecoder.h"
44 #include "SharedBuffer.h"
45 #include <wtf/Vector.h>
46
47 #define MAX_LZW_BITS          12
48 #define MAX_BYTES           4097 /* 2^MAX_LZW_BITS+1 */
49 #define MAX_COLORS           256
50 #define GIF_COLORS             3
51
52 const int cLoopCountNotSeen = -2;
53
54 // List of possible parsing states.
55 enum GIFState {
56     GIFType,
57     GIFGlobalHeader,
58     GIFGlobalColormap,
59     GIFImageStart,            
60     GIFImageHeader,
61     GIFImageColormap,
62     GIFImageBody,
63     GIFLZWStart,
64     GIFLZW,
65     GIFSubBlock,
66     GIFExtension,
67     GIFControlExtension,
68     GIFConsumeBlock,
69     GIFSkipBlock,
70     GIFDone,
71     GIFCommentExtension,
72     GIFApplicationExtension,
73     GIFNetscapeExtensionBlock,
74     GIFConsumeNetscapeExtension,
75     GIFConsumeComment
76 };
77
78 // Frame output state machine.
79 struct GIFFrameContext {
80     WTF_MAKE_FAST_ALLOCATED;
81 public:
82     int datasize;
83     int ipass; // Interlace pass; Ranges 1-4 if interlaced.
84     size_t rowsRemaining; // Rows remaining to be output.
85     size_t irow; // Current output row, starting at zero.
86
87     // Parameters for image frame currently being decoded.
88     unsigned xOffset;
89     unsigned yOffset; // With respect to "screen" origin.
90     unsigned width;
91     unsigned height;
92     int tpixel; // Index of transparent pixel.
93     WebCore::ImageFrame::FrameDisposalMethod disposalMethod; // Restore to background, leave in place, etc.
94     size_t localColormapPosition; // Per-image colormap.
95     int localColormapSize; // Size of local colormap array.
96     
97     bool isLocalColormapDefined : 1;
98     bool progressiveDisplay : 1; // If true, do Haeberli interlace hack.
99     bool interlaced : 1; // True, if scanlines arrive interlaced order.
100     bool isTransparent : 1; // TRUE, if tpixel is valid.
101
102     unsigned delayTime; // Display time, in milliseconds, for this image in a multi-image GIF.
103
104     GIFFrameContext()
105         : datasize(0)
106         , ipass(0)
107         , rowsRemaining(0)
108         , irow(0)
109         , xOffset(0)
110         , yOffset(0)
111         , width(0)
112         , height(0)
113         , tpixel(0)
114         , disposalMethod(WebCore::ImageFrame::DisposeNotSpecified)
115         , localColormapPosition(0)
116         , localColormapSize(0)
117         , isLocalColormapDefined(false)
118         , progressiveDisplay(false)
119         , interlaced(false)
120         , isTransparent(false)
121         , delayTime(0)
122     {
123     }
124     
125     ~GIFFrameContext()
126     {
127     }
128 };
129
130 // LZW decoder state machine.
131 // FIXME: Make this a class and hide private members.
132 struct GIFLZWContext {
133     WTF_MAKE_FAST_ALLOCATED;
134 public:
135     GIFLZWContext()
136         : stackp(0)
137         , codesize(0)
138         , codemask(0)
139         , clearCode(0)
140         , avail(0)
141         , oldcode(0)
142         , firstchar(0)
143         , bits(0)
144         , datum(0)
145         , rowPosition(0)
146     { }
147
148     bool prepareToDecode(unsigned rowWidth, int datasize);
149
150     size_t stackp; // Current stack pointer.
151     int codesize;
152     int codemask;
153     int clearCode; // Codeword used to trigger dictionary reset.
154     int avail; // Index of next available slot in dictionary.
155     int oldcode;
156     unsigned char firstchar;
157     int bits; // Number of unread bits in "datum".
158     int datum; // 32-bit input buffer.
159     size_t rowPosition;
160
161     Vector<unsigned short> prefix;
162     Vector<unsigned char> suffix;
163     Vector<unsigned char> stack;
164     Vector<unsigned char> rowBuffer; // Single scanline temporary buffer.
165 };
166
167 class GIFImageReader {
168     WTF_MAKE_FAST_ALLOCATED;
169 public:
170     GIFImageReader(WebCore::GIFImageDecoder* client = 0)
171         : m_client(client)
172         , m_state(GIFType)
173         , m_bytesToConsume(6) // Number of bytes for GIF type, either "GIF87a" or "GIF89a".
174         , m_bytesRead(0)
175         , m_screenBgcolor(0)
176         , m_version(0)
177         , m_screenWidth(0)
178         , m_screenHeight(0)
179         , m_isGlobalColormapDefined(false)
180         , m_globalColormapPosition(0)
181         , m_globalColormapSize(0)
182         , m_imagesDecoded(0)
183         , m_imagesCount(0)
184         , m_loopCount(cLoopCountNotSeen)
185         , m_frameContext(0)
186     {
187     }
188
189     ~GIFImageReader()
190     {
191         delete m_frameContext;
192         m_frameContext = 0;
193     }
194
195     void setData(PassRefPtr<WebCore::SharedBuffer> data) { m_data = data; }
196     bool decode(WebCore::GIFImageDecoder::GIFQuery, unsigned haltAtFrame);
197
198     int imagesCount() const { return m_imagesCount; }
199     int loopCount() const { return m_loopCount; }
200
201     const unsigned char* globalColormap() const
202     {
203         return m_isGlobalColormapDefined ? data(m_globalColormapPosition) : 0;
204     }
205     int globalColormapSize() const
206     {
207         return m_isGlobalColormapDefined ? m_globalColormapSize : 0;
208     }
209
210     const unsigned char* localColormap(const GIFFrameContext* frame) const
211     {
212         return frame->isLocalColormapDefined ? data(frame->localColormapPosition) : 0;
213     }
214     int localColormapSize(const GIFFrameContext* frame) const
215     {
216         return frame->isLocalColormapDefined ? frame->localColormapSize : 0;
217     }
218
219     const GIFFrameContext* frameContext() const { return m_frameContext; }
220
221 private:
222     bool decodeInternal(size_t dataPosition, size_t len, WebCore::GIFImageDecoder::GIFQuery, unsigned haltAtFrame);
223     bool outputRow();
224     bool doLZW(const unsigned char *, size_t);
225     void setRemainingBytes(size_t);
226
227     const unsigned char* data(size_t dataPosition) const
228     {
229         return reinterpret_cast<const unsigned char*>(m_data->data()) + dataPosition;
230     }
231
232     WebCore::GIFImageDecoder* m_client;
233
234     // Parsing state machine.
235     GIFState m_state; // Current decoder master state.
236     size_t m_bytesToConsume; // Number of bytes to consume for next stage of parsing.
237     size_t m_bytesRead; // Number of bytes processed.
238     
239     // Global (multi-image) state.
240     int m_screenBgcolor; // Logical screen background color.
241     int m_version; // Either 89 for GIF89 or 87 for GIF87.
242     unsigned m_screenWidth; // Logical screen width & height.
243     unsigned m_screenHeight;
244     bool m_isGlobalColormapDefined;
245     size_t m_globalColormapPosition; // (3* MAX_COLORS in size) Default colormap if local not supplied, 3 bytes for each color.
246     int m_globalColormapSize; // Size of global colormap array.
247     unsigned m_imagesDecoded; // Counts completed frames for animated GIFs.
248     int m_imagesCount; // Counted all frames seen so far (including incomplete frames).
249     int m_loopCount; // Netscape specific extension block to control the number of animation loops a GIF renders.
250     
251     GIFFrameContext* m_frameContext;
252
253     GIFLZWContext m_lzwContext;
254
255     RefPtr<WebCore::SharedBuffer> m_data;
256 };
257
258 #endif