c2e33e17238c4ca8bbf01870c661af5a77c190df
[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
46 #define MAX_LZW_BITS          12
47 #define MAX_BITS            4097 /* 2^MAX_LZW_BITS+1 */
48 #define MAX_COLORS           256
49 #define GIF_COLORS             3
50
51 const int cLoopCountNotSeen = -2;
52
53 // List of possible parsing states.
54 enum GIFState {
55     GIFType,
56     GIFGlobalHeader,
57     GIFGlobalColormap,
58     GIFImageStart,            
59     GIFImageHeader,
60     GIFImageColormap,
61     GIFImageBody,
62     GIFLZWStart,
63     GIFLZW,
64     GIFSubBlock,
65     GIFExtension,
66     GIFControlExtension,
67     GIFConsumeBlock,
68     GIFSkipBlock,
69     GIFDone,
70     GIFCommentExtension,
71     GIFApplicationExtension,
72     GIFNetscapeExtensionBlock,
73     GIFConsumeNetscapeExtension,
74     GIFConsumeComment
75 };
76
77 struct GIFFrameContext {
78     WTF_MAKE_FAST_ALLOCATED;
79 public:
80     // LZW decoder state machine.
81     unsigned char *stackp; // Current stack pointer.
82     int datasize;
83     int codesize;
84     int codemask;
85     int clearCode; // Codeword used to trigger dictionary reset.
86     int avail; // Index of next available slot in dictionary.
87     int oldcode;
88     unsigned char firstchar;
89     int bits; // Number of unread bits in "datum".
90     int datum; // 32-bit input buffer.
91
92     // Output state machine.
93     int ipass; // Interlace pass; Ranges 1-4 if interlaced.
94     unsigned rowsRemaining; // Rows remaining to be output.
95     unsigned irow; // Current output row, starting at zero.
96     unsigned char *rowbuf; // Single scanline temporary buffer.
97     unsigned char *rowend; // Pointer to end of rowbuf.
98     unsigned char *rowp; // Current output pointer.
99
100     // Parameters for image frame currently being decoded.
101     unsigned xOffset;
102     unsigned yOffset; // With respect to "screen" origin.
103     unsigned width;
104     unsigned height;
105     int tpixel; // Index of transparent pixel.
106     WebCore::ImageFrame::FrameDisposalMethod disposalMethod; // Restore to background, leave in place, etc.
107     size_t localColormapPosition; // Per-image colormap.
108     int localColormapSize; // Size of local colormap array.
109     
110     bool isLocalColormapDefined : 1;
111     bool progressiveDisplay : 1; // If true, do Haeberli interlace hack.
112     bool interlaced : 1; // True, if scanlines arrive interlaced order.
113     bool isTransparent : 1; // TRUE, if tpixel is valid.
114
115     unsigned delayTime; // Display time, in milliseconds, for this image in a multi-image GIF.
116
117     unsigned short* prefix; // LZW decoding tables.
118     unsigned char* suffix; // LZW decoding tables.
119     unsigned char* stack; // Base of LZW decoder stack.
120
121     GIFFrameContext()
122         : stackp(0)
123         , datasize(0)
124         , codesize(0)
125         , codemask(0)
126         , clearCode(0)
127         , avail(0)
128         , oldcode(0)
129         , firstchar(0)
130         , bits(0)
131         , datum(0)
132         , ipass(0)
133         , rowsRemaining(0)
134         , irow(0)
135         , rowbuf(0)
136         , rowend(0)
137         , rowp(0)
138         , xOffset(0)
139         , yOffset(0)
140         , width(0)
141         , height(0)
142         , tpixel(0)
143         , disposalMethod(WebCore::ImageFrame::DisposeNotSpecified)
144         , localColormapPosition(0)
145         , localColormapSize(0)
146         , isLocalColormapDefined(false)
147         , progressiveDisplay(false)
148         , interlaced(false)
149         , isTransparent(false)
150         , delayTime(0)
151         , prefix(0)
152         , suffix(0)
153         , stack(0)
154     {
155     }
156     
157     ~GIFFrameContext()
158     {
159         delete [] rowbuf;
160         delete [] prefix;
161         delete [] suffix;
162         delete [] stack;
163     }
164 };
165
166 class GIFImageReader {
167     WTF_MAKE_FAST_ALLOCATED;
168 public:
169     GIFImageReader(WebCore::GIFImageDecoder* client = 0)
170         : m_client(client)
171         , m_state(GIFType)
172         , m_bytesToConsume(6) // Number of bytes for GIF type, either "GIF87a" or "GIF89a".
173         , m_bytesRead(0)
174         , m_screenBgcolor(0)
175         , m_version(0)
176         , m_screenWidth(0)
177         , m_screenHeight(0)
178         , m_isGlobalColormapDefined(false)
179         , m_globalColormapPosition(0)
180         , m_globalColormapSize(0)
181         , m_imagesDecoded(0)
182         , m_imagesCount(0)
183         , m_loopCount(cLoopCountNotSeen)
184         , m_frameContext(0)
185     {
186     }
187
188     ~GIFImageReader()
189     {
190         delete m_frameContext;
191         m_frameContext = 0;
192     }
193
194     void setData(PassRefPtr<WebCore::SharedBuffer> data) { m_data = data; }
195     bool decode(WebCore::GIFImageDecoder::GIFQuery, unsigned haltAtFrame);
196
197     int imagesCount() const { return m_imagesCount; }
198     int loopCount() const { return m_loopCount; }
199
200     const unsigned char* globalColormap() const
201     {
202         return m_isGlobalColormapDefined ? data(m_globalColormapPosition) : 0;
203     }
204     int globalColormapSize() const
205     {
206         return m_isGlobalColormapDefined ? m_globalColormapSize : 0;
207     }
208
209     const unsigned char* localColormap(const GIFFrameContext* frame) const
210     {
211         return frame->isLocalColormapDefined ? data(frame->localColormapPosition) : 0;
212     }
213     int localColormapSize(const GIFFrameContext* frame) const
214     {
215         return frame->isLocalColormapDefined ? frame->localColormapSize : 0;
216     }
217
218     const GIFFrameContext* frameContext() const { return m_frameContext; }
219
220 private:
221     bool decodeInternal(size_t dataPosition, size_t len, WebCore::GIFImageDecoder::GIFQuery, unsigned haltAtFrame);
222     bool outputRow();
223     bool doLZW(const unsigned char *, size_t);
224     void setRemainingBytes(size_t);
225
226     const unsigned char* data(size_t dataPosition) const
227     {
228         return reinterpret_cast<const unsigned char*>(m_data->data()) + dataPosition;
229     }
230
231     WebCore::GIFImageDecoder* m_client;
232
233     // Parsing state machine.
234     GIFState m_state; // Current decoder master state.
235     size_t m_bytesToConsume; // Number of bytes to consume for next stage of parsing.
236     size_t m_bytesRead; // Number of bytes processed.
237     
238     // Global (multi-image) state.
239     int m_screenBgcolor; // Logical screen background color.
240     int m_version; // Either 89 for GIF89 or 87 for GIF87.
241     unsigned m_screenWidth; // Logical screen width & height.
242     unsigned m_screenHeight;
243     bool m_isGlobalColormapDefined;
244     size_t m_globalColormapPosition; // (3* MAX_COLORS in size) Default colormap if local not supplied, 3 bytes for each color.
245     int m_globalColormapSize; // Size of global colormap array.
246     unsigned m_imagesDecoded; // Counts completed frames for animated GIFs.
247     int m_imagesCount; // Counted all frames seen so far (including incomplete frames).
248     int m_loopCount; // Netscape specific extension block to control the number of animation loops a GIF renders.
249     
250     GIFFrameContext* m_frameContext;
251
252     RefPtr<WebCore::SharedBuffer> m_data;
253 };
254
255 #endif