blob: b5eca10dfb3fd0587c84854a89513e67b7992ec8 [file] [log] [blame]
scroggo19b91532016-10-24 09:03:26 -07001/* -*- 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
scroggo3d3a65c2016-10-24 12:28:30 -070038#ifndef SkGifImageReader_h
39#define SkGifImageReader_h
scroggo19b91532016-10-24 09:03:26 -070040
41// Define ourselves as the clientPtr. Mozilla just hacked their C++ callback class into this old C decoder,
42// so we will too.
43class SkGifCodec;
44
45#include "SkCodec.h"
46#include "SkCodecPriv.h"
47#include "SkCodecAnimation.h"
48#include "SkColorTable.h"
49#include "SkData.h"
Leon Scroggins III557fbbe2017-05-23 09:37:21 -040050#include "SkFrameHolder.h"
scroggo19b91532016-10-24 09:03:26 -070051#include "SkImageInfo.h"
52#include "SkStreamBuffer.h"
53#include "../private/SkTArray.h"
54#include <memory>
scroggo19b91532016-10-24 09:03:26 -070055
scroggof9acbe22016-10-25 12:43:21 -070056typedef SkTArray<unsigned char, true> SkGIFRow;
scroggo19b91532016-10-24 09:03:26 -070057
58
scroggof9acbe22016-10-25 12:43:21 -070059#define SK_MAX_DICTIONARY_ENTRY_BITS 12
60#define SK_MAX_DICTIONARY_ENTRIES 4096 // 2^SK_MAX_DICTIONARY_ENTRY_BITS
61#define SK_MAX_COLORS 256
62#define SK_BYTES_PER_COLORMAP_ENTRY 3
scroggo19b91532016-10-24 09:03:26 -070063
64// List of possible parsing states.
scroggof9acbe22016-10-25 12:43:21 -070065enum SkGIFState {
66 SkGIFType,
67 SkGIFGlobalHeader,
68 SkGIFGlobalColormap,
69 SkGIFImageStart,
70 SkGIFImageHeader,
71 SkGIFImageColormap,
72 SkGIFImageBody,
73 SkGIFLZWStart,
74 SkGIFLZW,
75 SkGIFSubBlock,
76 SkGIFExtension,
77 SkGIFControlExtension,
78 SkGIFConsumeBlock,
79 SkGIFSkipBlock,
80 SkGIFDone,
81 SkGIFCommentExtension,
82 SkGIFApplicationExtension,
83 SkGIFNetscapeExtensionBlock,
84 SkGIFConsumeNetscapeExtension,
85 SkGIFConsumeComment
scroggo19b91532016-10-24 09:03:26 -070086};
87
Leon Scroggins III557fbbe2017-05-23 09:37:21 -040088class SkGIFFrameContext;
scroggo53f63b62016-10-27 08:29:13 -070089class SkGIFColorMap;
scroggo19b91532016-10-24 09:03:26 -070090
91// LZW decoder state machine.
scroggof9acbe22016-10-25 12:43:21 -070092class SkGIFLZWContext final : public SkNoncopyable {
scroggo19b91532016-10-24 09:03:26 -070093public:
scroggof9acbe22016-10-25 12:43:21 -070094 SkGIFLZWContext(SkGifCodec* client, const SkGIFFrameContext* frameContext)
scroggo19b91532016-10-24 09:03:26 -070095 : codesize(0)
96 , codemask(0)
97 , clearCode(0)
98 , avail(0)
99 , oldcode(0)
100 , firstchar(0)
101 , bits(0)
102 , datum(0)
103 , ipass(0)
104 , irow(0)
105 , rowsRemaining(0)
Ben Wagnera93a14a2017-08-28 10:34:05 -0400106 , rowIter(nullptr)
scroggo19b91532016-10-24 09:03:26 -0700107 , m_client(client)
108 , m_frameContext(frameContext)
109 { }
110
Leon Scroggins III45565b62016-12-05 14:56:30 -0500111 bool prepareToDecode();
Leon Scroggins III223ec292017-08-22 14:13:15 -0400112 void outputRow(const unsigned char* rowBegin);
scroggo19b91532016-10-24 09:03:26 -0700113 bool doLZW(const unsigned char* block, size_t bytesInBlock);
Jim Van Verth3cfdf6c2016-10-26 09:45:23 -0400114 bool hasRemainingRows() { return SkToBool(rowsRemaining); }
scroggo19b91532016-10-24 09:03:26 -0700115
116private:
117 // LZW decoding states and output states.
118 int codesize;
119 int codemask;
120 int clearCode; // Codeword used to trigger dictionary reset.
121 int avail; // Index of next available slot in dictionary.
122 int oldcode;
123 unsigned char firstchar;
124 int bits; // Number of unread bits in "datum".
125 int datum; // 32-bit input buffer.
126 int ipass; // Interlace pass; Ranges 1-4 if interlaced.
127 size_t irow; // Current output row, starting at zero.
128 size_t rowsRemaining; // Rows remaining to be output.
129
scroggof9acbe22016-10-25 12:43:21 -0700130 unsigned short prefix[SK_MAX_DICTIONARY_ENTRIES];
131 unsigned char suffix[SK_MAX_DICTIONARY_ENTRIES];
132 unsigned short suffixLength[SK_MAX_DICTIONARY_ENTRIES];
133 SkGIFRow rowBuffer; // Single scanline temporary buffer.
scroggo19b91532016-10-24 09:03:26 -0700134 unsigned char* rowIter;
135
136 SkGifCodec* const m_client;
scroggof9acbe22016-10-25 12:43:21 -0700137 const SkGIFFrameContext* m_frameContext;
scroggo19b91532016-10-24 09:03:26 -0700138};
139
Leon Scroggins III932efed2016-12-16 11:39:51 -0500140struct SkGIFLZWBlock {
141 public:
142 SkGIFLZWBlock(size_t position, size_t size)
143 : blockPosition(position), blockSize(size) {}
144
Chris Blumed5c5ed52016-12-20 18:59:39 -0800145 size_t blockPosition;
146 size_t blockSize;
Leon Scroggins III932efed2016-12-16 11:39:51 -0500147};
148
scroggof9acbe22016-10-25 12:43:21 -0700149class SkGIFColorMap final {
scroggo19b91532016-10-24 09:03:26 -0700150public:
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400151 static constexpr int kNotFound = -1;
Leon Scroggins IIIb0b625b2016-12-22 16:40:24 -0500152
scroggof9acbe22016-10-25 12:43:21 -0700153 SkGIFColorMap()
scroggo19b91532016-10-24 09:03:26 -0700154 : m_isDefined(false)
Leon Scroggins III932efed2016-12-16 11:39:51 -0500155 , m_position(0)
scroggo19b91532016-10-24 09:03:26 -0700156 , m_colors(0)
Leon Scroggins IIIb0b625b2016-12-22 16:40:24 -0500157 , m_transPixel(kNotFound)
scroggo19b91532016-10-24 09:03:26 -0700158 , m_packColorProc(nullptr)
159 {
160 }
161
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400162 void setNumColors(int colors) {
Leon Scroggins III932efed2016-12-16 11:39:51 -0500163 SkASSERT(!m_colors);
164 SkASSERT(!m_position);
165
scroggo19b91532016-10-24 09:03:26 -0700166 m_colors = colors;
167 }
168
Leon Scroggins III932efed2016-12-16 11:39:51 -0500169 void setTablePosition(size_t position) {
170 SkASSERT(!m_isDefined);
171
172 m_position = position;
173 m_isDefined = true;
174 }
175
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400176 int numColors() const { return m_colors; }
scroggo19b91532016-10-24 09:03:26 -0700177
scroggo19b91532016-10-24 09:03:26 -0700178 bool isDefined() const { return m_isDefined; }
179
180 // Build RGBA table using the data stream.
Leon Scroggins III932efed2016-12-16 11:39:51 -0500181 sk_sp<SkColorTable> buildTable(SkStreamBuffer*, SkColorType dstColorType,
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400182 int transparentPixel) const;
scroggo19b91532016-10-24 09:03:26 -0700183
184private:
185 bool m_isDefined;
Leon Scroggins III932efed2016-12-16 11:39:51 -0500186 size_t m_position;
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400187 int m_colors;
Leon Scroggins IIIb0b625b2016-12-22 16:40:24 -0500188 // Cached values. If these match on a new request, we can reuse m_table.
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400189 mutable int m_transPixel;
scroggo19b91532016-10-24 09:03:26 -0700190 mutable PackColorProc m_packColorProc;
191 mutable sk_sp<SkColorTable> m_table;
192};
193
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400194class SkGifImageReader;
195
scroggo19b91532016-10-24 09:03:26 -0700196// LocalFrame output state machine.
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400197class SkGIFFrameContext : public SkFrame {
scroggo19b91532016-10-24 09:03:26 -0700198public:
Chris Blume6c08b7b2017-09-28 10:23:26 -0700199 SkGIFFrameContext(int id)
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400200 : INHERITED(id)
Leon Scroggins IIIb0b625b2016-12-22 16:40:24 -0500201 , m_transparentPixel(SkGIFColorMap::kNotFound)
scroggo19b91532016-10-24 09:03:26 -0700202 , m_dataSize(0)
203 , m_progressiveDisplay(false)
204 , m_interlaced(false)
205 , m_delayTime(0)
206 , m_currentLzwBlock(0)
207 , m_isComplete(false)
208 , m_isHeaderDefined(false)
209 , m_isDataSizeDefined(false)
210 {
211 }
212
Kevin Lubick700a79c2017-05-24 08:34:16 -0400213 ~SkGIFFrameContext() override
scroggo19b91532016-10-24 09:03:26 -0700214 {
215 }
216
Leon Scroggins III932efed2016-12-16 11:39:51 -0500217 void addLzwBlock(size_t position, size_t size)
scroggo19b91532016-10-24 09:03:26 -0700218 {
Leon Scroggins IIIe7503912017-08-30 10:09:42 -0400219 m_lzwBlocks.emplace_back(position, size);
scroggo19b91532016-10-24 09:03:26 -0700220 }
221
Leon Scroggins III932efed2016-12-16 11:39:51 -0500222 bool decode(SkStreamBuffer*, SkGifCodec* client, bool* frameDecoded);
scroggo19b91532016-10-24 09:03:26 -0700223
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400224 int transparentPixel() const { return m_transparentPixel; }
225 void setTransparentPixel(int pixel) { m_transparentPixel = pixel; }
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500226
scroggo19b91532016-10-24 09:03:26 -0700227 unsigned delayTime() const { return m_delayTime; }
228 void setDelayTime(unsigned delay) { m_delayTime = delay; }
229 bool isComplete() const { return m_isComplete; }
230 void setComplete() { m_isComplete = true; }
231 bool isHeaderDefined() const { return m_isHeaderDefined; }
232 void setHeaderDefined() { m_isHeaderDefined = true; }
233 bool isDataSizeDefined() const { return m_isDataSizeDefined; }
234 int dataSize() const { return m_dataSize; }
235 void setDataSize(int size)
236 {
237 m_dataSize = size;
238 m_isDataSizeDefined = true;
239 }
240 bool progressiveDisplay() const { return m_progressiveDisplay; }
241 void setProgressiveDisplay(bool progressiveDisplay) { m_progressiveDisplay = progressiveDisplay; }
242 bool interlaced() const { return m_interlaced; }
243 void setInterlaced(bool interlaced) { m_interlaced = interlaced; }
244
245 void clearDecodeState() { m_lzwContext.reset(); }
scroggof9acbe22016-10-25 12:43:21 -0700246 const SkGIFColorMap& localColorMap() const { return m_localColorMap; }
247 SkGIFColorMap& localColorMap() { return m_localColorMap; }
scroggo19b91532016-10-24 09:03:26 -0700248
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400249protected:
250 bool onReportsAlpha() const override;
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500251
scroggo19b91532016-10-24 09:03:26 -0700252private:
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400253 int m_transparentPixel; // Index of transparent pixel. Value is kNotFound if there is no transparent pixel.
scroggo19b91532016-10-24 09:03:26 -0700254 int m_dataSize;
255
256 bool m_progressiveDisplay; // If true, do Haeberli interlace hack.
257 bool m_interlaced; // True, if scanlines arrive interlaced order.
258
259 unsigned m_delayTime; // Display time, in milliseconds, for this image in a multi-image GIF.
260
scroggof9acbe22016-10-25 12:43:21 -0700261 std::unique_ptr<SkGIFLZWContext> m_lzwContext;
Leon Scroggins III932efed2016-12-16 11:39:51 -0500262 // LZW blocks for this frame.
Leon Scroggins IIIe7503912017-08-30 10:09:42 -0400263 SkTArray<SkGIFLZWBlock> m_lzwBlocks;
Leon Scroggins III932efed2016-12-16 11:39:51 -0500264
scroggof9acbe22016-10-25 12:43:21 -0700265 SkGIFColorMap m_localColorMap;
scroggo19b91532016-10-24 09:03:26 -0700266
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400267 int m_currentLzwBlock;
scroggo19b91532016-10-24 09:03:26 -0700268 bool m_isComplete;
269 bool m_isHeaderDefined;
270 bool m_isDataSizeDefined;
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400271
272 typedef SkFrame INHERITED;
scroggo19b91532016-10-24 09:03:26 -0700273};
274
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400275class SkGifImageReader final : public SkFrameHolder {
scroggo19b91532016-10-24 09:03:26 -0700276public:
277 // This takes ownership of stream.
Mike Reedede7bac2017-07-23 15:30:02 -0400278 SkGifImageReader(std::unique_ptr<SkStream> stream)
scroggo19b91532016-10-24 09:03:26 -0700279 : m_client(nullptr)
scroggof9acbe22016-10-25 12:43:21 -0700280 , m_state(SkGIFType)
scroggo19b91532016-10-24 09:03:26 -0700281 , m_bytesToConsume(6) // Number of bytes for GIF type, either "GIF87a" or "GIF89a".
282 , m_version(0)
scroggo19b91532016-10-24 09:03:26 -0700283 , m_loopCount(cLoopCountNotSeen)
Mike Reedede7bac2017-07-23 15:30:02 -0400284 , m_streamBuffer(std::move(stream))
scroggo19b91532016-10-24 09:03:26 -0700285 , m_parseCompleted(false)
286 , m_firstFrameHasAlpha(false)
scroggo19b91532016-10-24 09:03:26 -0700287 {
288 }
289
Kevin Lubick700a79c2017-05-24 08:34:16 -0400290 ~SkGifImageReader() override
scroggo19b91532016-10-24 09:03:26 -0700291 {
292 }
293
294 void setClient(SkGifCodec* client) { m_client = client; }
295
scroggo19b91532016-10-24 09:03:26 -0700296 // Option to pass to parse(). All enums are negative, because a non-negative value is used to
297 // indicate that the Reader should parse up to and including the frame indicated.
scroggof9acbe22016-10-25 12:43:21 -0700298 enum SkGIFParseQuery {
scroggo19b91532016-10-24 09:03:26 -0700299 // Parse enough to determine the size. Note that this parses the first frame's header,
300 // since we may decide to expand based on the frame's dimensions.
scroggof9acbe22016-10-25 12:43:21 -0700301 SkGIFSizeQuery = -1,
scroggo19b91532016-10-24 09:03:26 -0700302 // Parse to the end, so we know about all frames.
scroggof9acbe22016-10-25 12:43:21 -0700303 SkGIFFrameCountQuery = -2,
scroggoe71b1a12016-11-01 08:28:28 -0700304 // Parse until we see the loop count.
305 SkGIFLoopCountQuery = -3,
scroggo19b91532016-10-24 09:03:26 -0700306 };
307
308 // Parse incoming GIF data stream into internal data structures.
309 // Non-negative values are used to indicate to parse through that frame.
Leon Scroggins III588fb042017-07-14 16:32:31 -0400310 SkCodec::Result parse(SkGIFParseQuery);
scroggo19b91532016-10-24 09:03:26 -0700311
312 // Decode the frame indicated by frameIndex.
313 // frameComplete will be set to true if the frame is completely decoded.
314 // The method returns false if there is an error.
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400315 bool decode(int frameIndex, bool* frameComplete);
scroggo19b91532016-10-24 09:03:26 -0700316
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400317 int imagesCount() const
scroggo19b91532016-10-24 09:03:26 -0700318 {
Leon Scroggins IIIe7503912017-08-30 10:09:42 -0400319 const int frames = m_frames.count();
Leon Scroggins IIIe726e7c2017-07-18 16:22:52 -0400320 if (!frames) {
321 return 0;
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500322 }
scroggo19b91532016-10-24 09:03:26 -0700323
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500324 // This avoids counting an empty frame when the file is truncated (or
325 // simply not yet complete) after receiving SkGIFControlExtension (and
326 // possibly SkGIFImageHeader) but before reading the color table. This
327 // ensures that we do not count a frame before we know its required
328 // frame.
Leon Scroggins IIIe7503912017-08-30 10:09:42 -0400329 return m_frames.back()->reachedStartOfData() ? frames : frames - 1;
scroggo19b91532016-10-24 09:03:26 -0700330 }
scroggoe71b1a12016-11-01 08:28:28 -0700331 int loopCount() const {
332 if (cLoopCountNotSeen == m_loopCount) {
333 return 0;
334 }
335 return m_loopCount;
336 }
scroggo19b91532016-10-24 09:03:26 -0700337
scroggof9acbe22016-10-25 12:43:21 -0700338 const SkGIFColorMap& globalColorMap() const
scroggo19b91532016-10-24 09:03:26 -0700339 {
340 return m_globalColorMap;
341 }
342
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400343 const SkGIFFrameContext* frameContext(int index) const
scroggo19b91532016-10-24 09:03:26 -0700344 {
Leon Scroggins IIIe7503912017-08-30 10:09:42 -0400345 return index >= 0 && index < m_frames.count()
Ben Wagnera93a14a2017-08-28 10:34:05 -0400346 ? m_frames[index].get() : nullptr;
scroggo19b91532016-10-24 09:03:26 -0700347 }
348
349 void clearDecodeState() {
Leon Scroggins IIIe7503912017-08-30 10:09:42 -0400350 for (int index = 0; index < m_frames.count(); index++) {
scroggo19b91532016-10-24 09:03:26 -0700351 m_frames[index]->clearDecodeState();
352 }
353 }
354
355 // Return the color table for frame index (which may be the global color table).
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400356 sk_sp<SkColorTable> getColorTable(SkColorType dstColorType, int index);
scroggo19b91532016-10-24 09:03:26 -0700357
358 bool firstFrameHasAlpha() const { return m_firstFrameHasAlpha; }
359
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400360protected:
361 const SkFrame* onGetFrame(int i) const override {
362 return static_cast<const SkFrame*>(this->frameContext(i));
363 }
364
scroggo19b91532016-10-24 09:03:26 -0700365private:
366 // Requires that one byte has been buffered into m_streamBuffer.
367 unsigned char getOneByte() const {
368 return reinterpret_cast<const unsigned char*>(m_streamBuffer.get())[0];
369 }
370
371 void addFrameIfNecessary();
372 bool currentFrameIsFirstFrame() const
373 {
Leon Scroggins IIIe7503912017-08-30 10:09:42 -0400374 return m_frames.empty() || (m_frames.count() == 1 && !m_frames[0]->isComplete());
scroggo19b91532016-10-24 09:03:26 -0700375 }
376
377 // Unowned pointer
378 SkGifCodec* m_client;
379
380 // Parsing state machine.
scroggof9acbe22016-10-25 12:43:21 -0700381 SkGIFState m_state; // Current decoder master state.
scroggo19b91532016-10-24 09:03:26 -0700382 size_t m_bytesToConsume; // Number of bytes to consume for next stage of parsing.
383
384 // Global (multi-image) state.
385 int m_version; // Either 89 for GIF89 or 87 for GIF87.
scroggof9acbe22016-10-25 12:43:21 -0700386 SkGIFColorMap m_globalColorMap;
scroggoe71b1a12016-11-01 08:28:28 -0700387
388 static constexpr int cLoopCountNotSeen = -2;
scroggo19b91532016-10-24 09:03:26 -0700389 int m_loopCount; // Netscape specific extension block to control the number of animation loops a GIF renders.
390
Leon Scroggins IIIe7503912017-08-30 10:09:42 -0400391 SkTArray<std::unique_ptr<SkGIFFrameContext>> m_frames;
scroggo19b91532016-10-24 09:03:26 -0700392
393 SkStreamBuffer m_streamBuffer;
394 bool m_parseCompleted;
395
Leon Scroggins571b30f2017-07-11 17:35:31 +0000396 // This value can be computed before we create a SkGIFFrameContext, so we
397 // store it here instead of on m_frames[0].
scroggo19b91532016-10-24 09:03:26 -0700398 bool m_firstFrameHasAlpha;
scroggo19b91532016-10-24 09:03:26 -0700399};
400
401#endif