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 "platform/SharedBuffer.h"
44#include "platform/image-decoders/gif/GIFImageDecoder.h"
45#include "wtf/Noncopyable.h"
46#include "wtf/OwnPtr.h"
47#include "wtf/PassOwnPtr.h"
48#include "wtf/Vector.h"
49
50#define MAX_DICTIONARY_ENTRY_BITS 12
51#define MAX_DICTIONARY_ENTRIES    4096 // 2^MAX_DICTIONARY_ENTRY_BITS
52#define MAX_COLORS                256
53#define BYTES_PER_COLORMAP_ENTRY  3
54
55const int cLoopCountNotSeen = -2;
56
57// List of possible parsing states.
58enum GIFState {
59    GIFType,
60    GIFGlobalHeader,
61    GIFGlobalColormap,
62    GIFImageStart,
63    GIFImageHeader,
64    GIFImageColormap,
65    GIFImageBody,
66    GIFLZWStart,
67    GIFLZW,
68    GIFSubBlock,
69    GIFExtension,
70    GIFControlExtension,
71    GIFConsumeBlock,
72    GIFSkipBlock,
73    GIFDone,
74    GIFCommentExtension,
75    GIFApplicationExtension,
76    GIFNetscapeExtensionBlock,
77    GIFConsumeNetscapeExtension,
78    GIFConsumeComment
79};
80
81struct GIFFrameContext;
82
83// LZW decoder state machine.
84class GIFLZWContext {
85    WTF_MAKE_FAST_ALLOCATED;
86public:
87    GIFLZWContext(blink::GIFImageDecoder* client, const GIFFrameContext* frameContext)
88        : codesize(0)
89        , codemask(0)
90        , clearCode(0)
91        , avail(0)
92        , oldcode(0)
93        , firstchar(0)
94        , bits(0)
95        , datum(0)
96        , ipass(0)
97        , irow(0)
98        , rowsRemaining(0)
99        , rowIter(0)
100        , m_client(client)
101        , m_frameContext(frameContext)
102    { }
103
104    bool prepareToDecode();
105    bool outputRow(GIFRow::const_iterator rowBegin);
106    bool doLZW(const unsigned char* block, size_t bytesInBlock);
107    bool hasRemainingRows() { return rowsRemaining; }
108
109private:
110    // LZW decoding states and output states.
111    int codesize;
112    int codemask;
113    int clearCode; // Codeword used to trigger dictionary reset.
114    int avail; // Index of next available slot in dictionary.
115    int oldcode;
116    unsigned char firstchar;
117    int bits; // Number of unread bits in "datum".
118    int datum; // 32-bit input buffer.
119    int ipass; // Interlace pass; Ranges 1-4 if interlaced.
120    size_t irow; // Current output row, starting at zero.
121    size_t rowsRemaining; // Rows remaining to be output.
122
123    unsigned short prefix[MAX_DICTIONARY_ENTRIES];
124    unsigned char suffix[MAX_DICTIONARY_ENTRIES];
125    unsigned short suffixLength[MAX_DICTIONARY_ENTRIES];
126    GIFRow rowBuffer; // Single scanline temporary buffer.
127    GIFRow::iterator rowIter;
128
129    // Initialized during construction and read-only.
130    blink::GIFImageDecoder* m_client;
131    const GIFFrameContext* m_frameContext;
132};
133
134// Data structure for one LZW block.
135struct GIFLZWBlock {
136    WTF_MAKE_FAST_ALLOCATED;
137public:
138    GIFLZWBlock(size_t position, size_t size)
139        : blockPosition(position)
140        , blockSize(size)
141    {
142    }
143
144    size_t blockPosition;
145    size_t blockSize;
146};
147
148class GIFColorMap {
149    WTF_MAKE_FAST_ALLOCATED;
150public:
151    typedef Vector<blink::ImageFrame::PixelData> Table;
152
153    GIFColorMap()
154        : m_isDefined(false)
155        , m_position(0)
156        , m_colors(0)
157    {
158    }
159
160    // Set position and number of colors for the RGB table in the data stream.
161    void setTablePositionAndSize(size_t position, size_t colors)
162    {
163        m_position = position;
164        m_colors = colors;
165    }
166    void setDefined() { m_isDefined = true; }
167    bool isDefined() const { return m_isDefined; }
168
169    // Build RGBA table using the data stream.
170    void buildTable(const unsigned char* data, size_t length);
171    const Table& table() const { return m_table; }
172
173private:
174    bool m_isDefined;
175    size_t m_position;
176    size_t m_colors;
177    Table m_table;
178};
179
180// LocalFrame output state machine.
181struct GIFFrameContext {
182    WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(GIFFrameContext);
183public:
184    GIFFrameContext(int id)
185        : m_frameId(id)
186        , m_xOffset(0)
187        , m_yOffset(0)
188        , m_width(0)
189        , m_height(0)
190        , m_transparentPixel(kNotFound)
191        , m_disposalMethod(blink::ImageFrame::DisposeNotSpecified)
192        , m_dataSize(0)
193        , m_progressiveDisplay(false)
194        , m_interlaced(false)
195        , m_delayTime(0)
196        , m_currentLzwBlock(0)
197        , m_isComplete(false)
198        , m_isHeaderDefined(false)
199        , m_isDataSizeDefined(false)
200    {
201    }
202
203    ~GIFFrameContext()
204    {
205    }
206
207    void addLzwBlock(size_t position, size_t size)
208    {
209        m_lzwBlocks.append(GIFLZWBlock(position, size));
210    }
211
212    bool decode(const unsigned char* data, size_t length, blink::GIFImageDecoder* client, bool* frameDecoded);
213
214    int frameId() const { return m_frameId; }
215    void setRect(unsigned x, unsigned y, unsigned width, unsigned height)
216    {
217        m_xOffset = x;
218        m_yOffset = y;
219        m_width = width;
220        m_height = height;
221    }
222    blink::IntRect frameRect() const { return blink::IntRect(m_xOffset, m_yOffset, m_width, m_height); }
223    unsigned xOffset() const { return m_xOffset; }
224    unsigned yOffset() const { return m_yOffset; }
225    unsigned width() const { return m_width; }
226    unsigned height() const { return m_height; }
227    size_t transparentPixel() const { return m_transparentPixel; }
228    void setTransparentPixel(size_t pixel) { m_transparentPixel = pixel; }
229    blink::ImageFrame::DisposalMethod disposalMethod() const { return m_disposalMethod; }
230    void setDisposalMethod(blink::ImageFrame::DisposalMethod disposalMethod) { m_disposalMethod = disposalMethod; }
231    unsigned delayTime() const { return m_delayTime; }
232    void setDelayTime(unsigned delay) { m_delayTime = delay; }
233    bool isComplete() const { return m_isComplete; }
234    void setComplete() { m_isComplete = true; }
235    bool isHeaderDefined() const { return m_isHeaderDefined; }
236    void setHeaderDefined() { m_isHeaderDefined = true; }
237    bool isDataSizeDefined() const { return m_isDataSizeDefined; }
238    int dataSize() const { return m_dataSize; }
239    void setDataSize(int size)
240    {
241        m_dataSize = size;
242        m_isDataSizeDefined = true;
243    }
244    bool progressiveDisplay() const { return m_progressiveDisplay; }
245    void setProgressiveDisplay(bool progressiveDisplay) { m_progressiveDisplay = progressiveDisplay; }
246    bool interlaced() const { return m_interlaced; }
247    void setInterlaced(bool interlaced) { m_interlaced = interlaced; }
248
249    void clearDecodeState() { m_lzwContext.clear(); }
250    const GIFColorMap& localColorMap() const { return m_localColorMap; }
251    GIFColorMap& localColorMap() { return m_localColorMap; }
252
253private:
254    int m_frameId;
255    unsigned m_xOffset;
256    unsigned m_yOffset; // With respect to "screen" origin.
257    unsigned m_width;
258    unsigned m_height;
259    size_t m_transparentPixel; // Index of transparent pixel. Value is kNotFound if there is no transparent pixel.
260    blink::ImageFrame::DisposalMethod m_disposalMethod; // Restore to background, leave in place, etc.
261    int m_dataSize;
262
263    bool m_progressiveDisplay; // If true, do Haeberli interlace hack.
264    bool m_interlaced; // True, if scanlines arrive interlaced order.
265
266    unsigned m_delayTime; // Display time, in milliseconds, for this image in a multi-image GIF.
267
268    OwnPtr<GIFLZWContext> m_lzwContext;
269    Vector<GIFLZWBlock> m_lzwBlocks; // LZW blocks for this frame.
270    GIFColorMap m_localColorMap;
271
272    size_t m_currentLzwBlock;
273    bool m_isComplete;
274    bool m_isHeaderDefined;
275    bool m_isDataSizeDefined;
276};
277
278class PLATFORM_EXPORT GIFImageReader {
279    WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(GIFImageReader);
280public:
281    GIFImageReader(blink::GIFImageDecoder* client = 0)
282        : m_client(client)
283        , m_state(GIFType)
284        , m_bytesToConsume(6) // Number of bytes for GIF type, either "GIF87a" or "GIF89a".
285        , m_bytesRead(0)
286        , m_version(0)
287        , m_screenWidth(0)
288        , m_screenHeight(0)
289        , m_loopCount(cLoopCountNotSeen)
290        , m_parseCompleted(false)
291    {
292    }
293
294    ~GIFImageReader()
295    {
296    }
297
298    void setData(PassRefPtr<blink::SharedBuffer> data) { m_data = data; }
299    bool parse(blink::GIFImageDecoder::GIFParseQuery);
300    bool decode(size_t frameIndex);
301
302    size_t imagesCount() const
303    {
304        if (m_frames.isEmpty())
305            return 0;
306
307        // This avoids counting an empty frame when the file is truncated right after
308        // GIFControlExtension but before GIFImageHeader.
309        // FIXME: This extra complexity is not necessary and we should just report m_frames.size().
310        return m_frames.last()->isHeaderDefined() ? m_frames.size() : m_frames.size() - 1;
311    }
312    int loopCount() const { return m_loopCount; }
313
314    const GIFColorMap& globalColorMap() const
315    {
316        return m_globalColorMap;
317    }
318
319    const GIFFrameContext* frameContext(size_t index) const
320    {
321        return index < m_frames.size() ? m_frames[index].get() : 0;
322    }
323
324    bool parseCompleted() const { return m_parseCompleted; }
325
326    void clearDecodeState(size_t index) { m_frames[index]->clearDecodeState(); }
327
328private:
329    bool parseData(size_t dataPosition, size_t len, blink::GIFImageDecoder::GIFParseQuery);
330    void setRemainingBytes(size_t);
331
332    const unsigned char* data(size_t dataPosition) const
333    {
334        return reinterpret_cast<const unsigned char*>(m_data->data()) + dataPosition;
335    }
336
337    void addFrameIfNecessary();
338    bool currentFrameIsFirstFrame() const
339    {
340        return m_frames.isEmpty() || (m_frames.size() == 1u && !m_frames[0]->isComplete());
341    }
342
343    blink::GIFImageDecoder* m_client;
344
345    // Parsing state machine.
346    GIFState m_state; // Current decoder master state.
347    size_t m_bytesToConsume; // Number of bytes to consume for next stage of parsing.
348    size_t m_bytesRead; // Number of bytes processed.
349
350    // Global (multi-image) state.
351    int m_version; // Either 89 for GIF89 or 87 for GIF87.
352    unsigned m_screenWidth; // Logical screen width & height.
353    unsigned m_screenHeight;
354    GIFColorMap m_globalColorMap;
355    int m_loopCount; // Netscape specific extension block to control the number of animation loops a GIF renders.
356
357    Vector<OwnPtr<GIFFrameContext> > m_frames;
358
359    RefPtr<blink::SharedBuffer> m_data;
360    bool m_parseCompleted;
361};
362
363#endif
364