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/OwnPtr.h> 46#include <wtf/PassOwnPtr.h> 47#include <wtf/Vector.h> 48 49#define MAX_LZW_BITS 12 50#define MAX_BYTES 4097 /* 2^MAX_LZW_BITS+1 */ 51#define MAX_COLORS 256 52#define GIF_COLORS 3 53 54const int cLoopCountNotSeen = -2; 55 56// List of possible parsing states. 57enum GIFState { 58 GIFType, 59 GIFGlobalHeader, 60 GIFGlobalColormap, 61 GIFImageStart, 62 GIFImageHeader, 63 GIFImageColormap, 64 GIFImageBody, 65 GIFLZWStart, 66 GIFLZW, 67 GIFSubBlock, 68 GIFExtension, 69 GIFControlExtension, 70 GIFConsumeBlock, 71 GIFSkipBlock, 72 GIFDone, 73 GIFCommentExtension, 74 GIFApplicationExtension, 75 GIFNetscapeExtensionBlock, 76 GIFConsumeNetscapeExtension, 77 GIFConsumeComment 78}; 79 80struct GIFFrameContext; 81 82// LZW decoder state machine. 83class GIFLZWContext { 84 WTF_MAKE_FAST_ALLOCATED; 85public: 86 GIFLZWContext(WebCore::GIFImageDecoder* client, const GIFFrameContext* frameContext) 87 : stackp(0) 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 , rowPosition(0) 99 , rowsRemaining(0) 100 , m_client(client) 101 , m_frameContext(frameContext) 102 { } 103 104 bool prepareToDecode(); 105 bool outputRow(); 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 size_t stackp; // Current stack pointer. 112 int codesize; 113 int codemask; 114 int clearCode; // Codeword used to trigger dictionary reset. 115 int avail; // Index of next available slot in dictionary. 116 int oldcode; 117 unsigned char firstchar; 118 int bits; // Number of unread bits in "datum". 119 int datum; // 32-bit input buffer. 120 int ipass; // Interlace pass; Ranges 1-4 if interlaced. 121 size_t irow; // Current output row, starting at zero. 122 size_t rowPosition; 123 size_t rowsRemaining; // Rows remaining to be output. 124 125 Vector<unsigned short> prefix; 126 Vector<unsigned char> suffix; 127 Vector<unsigned char> stack; 128 Vector<unsigned char> rowBuffer; // Single scanline temporary buffer. 129 130 // Initialized during construction and read-only. 131 WebCore::GIFImageDecoder* m_client; 132 const GIFFrameContext* m_frameContext; 133}; 134 135// Data structure for one LZW block. 136struct GIFLZWBlock { 137 WTF_MAKE_FAST_ALLOCATED; 138public: 139 GIFLZWBlock(size_t position, size_t size) 140 : blockPosition(position) 141 , blockSize(size) 142 { 143 } 144 145 size_t blockPosition; 146 size_t blockSize; 147}; 148 149// Frame output state machine. 150struct GIFFrameContext { 151 WTF_MAKE_FAST_ALLOCATED; 152public: 153 // FIXME: Move these members to private section. 154 int frameId; 155 unsigned xOffset; 156 unsigned yOffset; // With respect to "screen" origin. 157 unsigned width; 158 unsigned height; 159 int tpixel; // Index of transparent pixel. 160 WebCore::ImageFrame::FrameDisposalMethod disposalMethod; // Restore to background, leave in place, etc. 161 size_t localColormapPosition; // Per-image colormap. 162 int localColormapSize; // Size of local colormap array. 163 int datasize; 164 165 bool isLocalColormapDefined : 1; 166 bool progressiveDisplay : 1; // If true, do Haeberli interlace hack. 167 bool interlaced : 1; // True, if scanlines arrive interlaced order. 168 bool isTransparent : 1; // TRUE, if tpixel is valid. 169 170 unsigned delayTime; // Display time, in milliseconds, for this image in a multi-image GIF. 171 172 GIFFrameContext(int id) 173 : frameId(id) 174 , xOffset(0) 175 , yOffset(0) 176 , width(0) 177 , height(0) 178 , tpixel(0) 179 , disposalMethod(WebCore::ImageFrame::DisposeNotSpecified) 180 , localColormapPosition(0) 181 , localColormapSize(0) 182 , datasize(0) 183 , isLocalColormapDefined(false) 184 , progressiveDisplay(false) 185 , interlaced(false) 186 , isTransparent(false) 187 , delayTime(0) 188 , m_currentLzwBlock(0) 189 , m_isComplete(false) 190 , m_isHeaderDefined(false) 191 , m_isDataSizeDefined(false) 192 { 193 } 194 195 ~GIFFrameContext() 196 { 197 } 198 199 void addLzwBlock(size_t position, size_t size) 200 { 201 m_lzwBlocks.append(GIFLZWBlock(position, size)); 202 } 203 204 bool decode(const unsigned char* data, size_t length, WebCore::GIFImageDecoder* client, bool* frameDecoded); 205 206 bool isComplete() const { return m_isComplete; } 207 void setComplete() { m_isComplete = true; } 208 bool isHeaderDefined() const { return m_isHeaderDefined; } 209 void setHeaderDefined() { m_isHeaderDefined = true; } 210 bool isDataSizeDefined() const { return m_isDataSizeDefined; } 211 void setDataSize(int size) 212 { 213 datasize = size; 214 m_isDataSizeDefined = true; 215 } 216 217private: 218 OwnPtr<GIFLZWContext> m_lzwContext; 219 Vector<GIFLZWBlock> m_lzwBlocks; // LZW blocks for this frame. 220 size_t m_currentLzwBlock; 221 bool m_isComplete; 222 bool m_isHeaderDefined; 223 bool m_isDataSizeDefined; 224}; 225 226class GIFImageReader { 227 WTF_MAKE_FAST_ALLOCATED; 228public: 229 GIFImageReader(WebCore::GIFImageDecoder* client = 0) 230 : m_client(client) 231 , m_state(GIFType) 232 , m_bytesToConsume(6) // Number of bytes for GIF type, either "GIF87a" or "GIF89a". 233 , m_bytesRead(0) 234 , m_screenBgcolor(0) 235 , m_version(0) 236 , m_screenWidth(0) 237 , m_screenHeight(0) 238 , m_isGlobalColormapDefined(false) 239 , m_globalColormapPosition(0) 240 , m_globalColormapSize(0) 241 , m_loopCount(cLoopCountNotSeen) 242 , m_currentDecodingFrame(0) 243 , m_parseCompleted(false) 244 { 245 } 246 247 ~GIFImageReader() 248 { 249 } 250 251 void setData(PassRefPtr<WebCore::SharedBuffer> data) { m_data = data; } 252 // FIXME: haltAtFrame should be size_t. 253 bool decode(WebCore::GIFImageDecoder::GIFQuery, unsigned haltAtFrame); 254 255 size_t imagesCount() const 256 { 257 if (m_frames.isEmpty()) 258 return 0; 259 260 // This avoids counting an empty frame when the file is truncated right after 261 // GIFControlExtension but before GIFImageHeader. 262 // FIXME: This extra complexity is not necessary and we should just report m_frames.size(). 263 return m_frames.last()->isHeaderDefined() ? m_frames.size() : m_frames.size() - 1; 264 } 265 int loopCount() const { return m_loopCount; } 266 267 const unsigned char* globalColormap() const 268 { 269 return m_isGlobalColormapDefined ? data(m_globalColormapPosition) : 0; 270 } 271 int globalColormapSize() const 272 { 273 return m_isGlobalColormapDefined ? m_globalColormapSize : 0; 274 } 275 276 const unsigned char* localColormap(const GIFFrameContext* frame) const 277 { 278 return frame->isLocalColormapDefined ? data(frame->localColormapPosition) : 0; 279 } 280 int localColormapSize(const GIFFrameContext* frame) const 281 { 282 return frame->isLocalColormapDefined ? frame->localColormapSize : 0; 283 } 284 285 const GIFFrameContext* frameContext() const 286 { 287 return m_currentDecodingFrame < m_frames.size() ? m_frames[m_currentDecodingFrame].get() : 0; 288 } 289 290private: 291 bool parse(size_t dataPosition, size_t len, bool parseSizeOnly); 292 void setRemainingBytes(size_t); 293 294 const unsigned char* data(size_t dataPosition) const 295 { 296 return reinterpret_cast<const unsigned char*>(m_data->data()) + dataPosition; 297 } 298 299 void addFrameIfNecessary(); 300 bool currentFrameIsFirstFrame() const 301 { 302 return m_frames.isEmpty() || (m_frames.size() == 1u && !m_frames[0]->isComplete()); 303 } 304 305 WebCore::GIFImageDecoder* m_client; 306 307 // Parsing state machine. 308 GIFState m_state; // Current decoder master state. 309 size_t m_bytesToConsume; // Number of bytes to consume for next stage of parsing. 310 size_t m_bytesRead; // Number of bytes processed. 311 312 // Global (multi-image) state. 313 int m_screenBgcolor; // Logical screen background color. 314 int m_version; // Either 89 for GIF89 or 87 for GIF87. 315 unsigned m_screenWidth; // Logical screen width & height. 316 unsigned m_screenHeight; 317 bool m_isGlobalColormapDefined; 318 size_t m_globalColormapPosition; // (3* MAX_COLORS in size) Default colormap if local not supplied, 3 bytes for each color. 319 int m_globalColormapSize; // Size of global colormap array. 320 int m_loopCount; // Netscape specific extension block to control the number of animation loops a GIF renders. 321 322 Vector<OwnPtr<GIFFrameContext> > m_frames; 323 size_t m_currentDecodingFrame; 324 325 RefPtr<WebCore::SharedBuffer> m_data; 326 bool m_parseCompleted; 327}; 328 329#endif 330