blob: ebb805e5c59cbb5e9fc091f98235b16bf76ba951 [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>
55#include <vector>
56
scroggof9acbe22016-10-25 12:43:21 -070057typedef SkTArray<unsigned char, true> SkGIFRow;
scroggo19b91532016-10-24 09:03:26 -070058
59
scroggof9acbe22016-10-25 12:43:21 -070060#define SK_MAX_DICTIONARY_ENTRY_BITS 12
61#define SK_MAX_DICTIONARY_ENTRIES 4096 // 2^SK_MAX_DICTIONARY_ENTRY_BITS
62#define SK_MAX_COLORS 256
63#define SK_BYTES_PER_COLORMAP_ENTRY 3
scroggo19b91532016-10-24 09:03:26 -070064
65// List of possible parsing states.
scroggof9acbe22016-10-25 12:43:21 -070066enum SkGIFState {
67 SkGIFType,
68 SkGIFGlobalHeader,
69 SkGIFGlobalColormap,
70 SkGIFImageStart,
71 SkGIFImageHeader,
72 SkGIFImageColormap,
73 SkGIFImageBody,
74 SkGIFLZWStart,
75 SkGIFLZW,
76 SkGIFSubBlock,
77 SkGIFExtension,
78 SkGIFControlExtension,
79 SkGIFConsumeBlock,
80 SkGIFSkipBlock,
81 SkGIFDone,
82 SkGIFCommentExtension,
83 SkGIFApplicationExtension,
84 SkGIFNetscapeExtensionBlock,
85 SkGIFConsumeNetscapeExtension,
86 SkGIFConsumeComment
scroggo19b91532016-10-24 09:03:26 -070087};
88
Leon Scroggins III557fbbe2017-05-23 09:37:21 -040089class SkGIFFrameContext;
scroggo53f63b62016-10-27 08:29:13 -070090class SkGIFColorMap;
scroggo19b91532016-10-24 09:03:26 -070091
92// LZW decoder state machine.
scroggof9acbe22016-10-25 12:43:21 -070093class SkGIFLZWContext final : public SkNoncopyable {
scroggo19b91532016-10-24 09:03:26 -070094public:
scroggof9acbe22016-10-25 12:43:21 -070095 SkGIFLZWContext(SkGifCodec* client, const SkGIFFrameContext* frameContext)
scroggo19b91532016-10-24 09:03:26 -070096 : codesize(0)
97 , codemask(0)
98 , clearCode(0)
99 , avail(0)
100 , oldcode(0)
101 , firstchar(0)
102 , bits(0)
103 , datum(0)
104 , ipass(0)
105 , irow(0)
106 , rowsRemaining(0)
Ben Wagnera93a14a2017-08-28 10:34:05 -0400107 , rowIter(nullptr)
scroggo19b91532016-10-24 09:03:26 -0700108 , m_client(client)
109 , m_frameContext(frameContext)
110 { }
111
Leon Scroggins III45565b62016-12-05 14:56:30 -0500112 bool prepareToDecode();
Leon Scroggins III223ec292017-08-22 14:13:15 -0400113 void outputRow(const unsigned char* rowBegin);
scroggo19b91532016-10-24 09:03:26 -0700114 bool doLZW(const unsigned char* block, size_t bytesInBlock);
Jim Van Verth3cfdf6c2016-10-26 09:45:23 -0400115 bool hasRemainingRows() { return SkToBool(rowsRemaining); }
scroggo19b91532016-10-24 09:03:26 -0700116
117private:
118 // LZW decoding states and output states.
119 int codesize;
120 int codemask;
121 int clearCode; // Codeword used to trigger dictionary reset.
122 int avail; // Index of next available slot in dictionary.
123 int oldcode;
124 unsigned char firstchar;
125 int bits; // Number of unread bits in "datum".
126 int datum; // 32-bit input buffer.
127 int ipass; // Interlace pass; Ranges 1-4 if interlaced.
128 size_t irow; // Current output row, starting at zero.
129 size_t rowsRemaining; // Rows remaining to be output.
130
scroggof9acbe22016-10-25 12:43:21 -0700131 unsigned short prefix[SK_MAX_DICTIONARY_ENTRIES];
132 unsigned char suffix[SK_MAX_DICTIONARY_ENTRIES];
133 unsigned short suffixLength[SK_MAX_DICTIONARY_ENTRIES];
134 SkGIFRow rowBuffer; // Single scanline temporary buffer.
scroggo19b91532016-10-24 09:03:26 -0700135 unsigned char* rowIter;
136
137 SkGifCodec* const m_client;
scroggof9acbe22016-10-25 12:43:21 -0700138 const SkGIFFrameContext* m_frameContext;
scroggo19b91532016-10-24 09:03:26 -0700139};
140
Leon Scroggins III932efed2016-12-16 11:39:51 -0500141struct SkGIFLZWBlock {
142 public:
143 SkGIFLZWBlock(size_t position, size_t size)
144 : blockPosition(position), blockSize(size) {}
145
Chris Blumed5c5ed52016-12-20 18:59:39 -0800146 size_t blockPosition;
147 size_t blockSize;
Leon Scroggins III932efed2016-12-16 11:39:51 -0500148};
149
scroggof9acbe22016-10-25 12:43:21 -0700150class SkGIFColorMap final {
scroggo19b91532016-10-24 09:03:26 -0700151public:
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400152 static constexpr int kNotFound = -1;
Leon Scroggins IIIb0b625b2016-12-22 16:40:24 -0500153
scroggof9acbe22016-10-25 12:43:21 -0700154 SkGIFColorMap()
scroggo19b91532016-10-24 09:03:26 -0700155 : m_isDefined(false)
Leon Scroggins III932efed2016-12-16 11:39:51 -0500156 , m_position(0)
scroggo19b91532016-10-24 09:03:26 -0700157 , m_colors(0)
Leon Scroggins IIIb0b625b2016-12-22 16:40:24 -0500158 , m_transPixel(kNotFound)
scroggo19b91532016-10-24 09:03:26 -0700159 , m_packColorProc(nullptr)
160 {
161 }
162
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400163 void setNumColors(int colors) {
Leon Scroggins III932efed2016-12-16 11:39:51 -0500164 SkASSERT(!m_colors);
165 SkASSERT(!m_position);
166
scroggo19b91532016-10-24 09:03:26 -0700167 m_colors = colors;
168 }
169
Leon Scroggins III932efed2016-12-16 11:39:51 -0500170 void setTablePosition(size_t position) {
171 SkASSERT(!m_isDefined);
172
173 m_position = position;
174 m_isDefined = true;
175 }
176
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400177 int numColors() const { return m_colors; }
scroggo19b91532016-10-24 09:03:26 -0700178
scroggo19b91532016-10-24 09:03:26 -0700179 bool isDefined() const { return m_isDefined; }
180
181 // Build RGBA table using the data stream.
Leon Scroggins III932efed2016-12-16 11:39:51 -0500182 sk_sp<SkColorTable> buildTable(SkStreamBuffer*, SkColorType dstColorType,
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400183 int transparentPixel) const;
scroggo19b91532016-10-24 09:03:26 -0700184
185private:
186 bool m_isDefined;
Leon Scroggins III932efed2016-12-16 11:39:51 -0500187 size_t m_position;
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400188 int m_colors;
Leon Scroggins IIIb0b625b2016-12-22 16:40:24 -0500189 // Cached values. If these match on a new request, we can reuse m_table.
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400190 mutable int m_transPixel;
scroggo19b91532016-10-24 09:03:26 -0700191 mutable PackColorProc m_packColorProc;
192 mutable sk_sp<SkColorTable> m_table;
193};
194
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400195class SkGifImageReader;
196
scroggo19b91532016-10-24 09:03:26 -0700197// LocalFrame output state machine.
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400198class SkGIFFrameContext : public SkFrame {
scroggo19b91532016-10-24 09:03:26 -0700199public:
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400200 SkGIFFrameContext(SkGifImageReader* reader, int id)
201 : INHERITED(id)
202 , m_owner(reader)
Leon Scroggins IIIb0b625b2016-12-22 16:40:24 -0500203 , m_transparentPixel(SkGIFColorMap::kNotFound)
scroggo19b91532016-10-24 09:03:26 -0700204 , m_dataSize(0)
205 , m_progressiveDisplay(false)
206 , m_interlaced(false)
207 , m_delayTime(0)
208 , m_currentLzwBlock(0)
209 , m_isComplete(false)
210 , m_isHeaderDefined(false)
211 , m_isDataSizeDefined(false)
212 {
213 }
214
Kevin Lubick700a79c2017-05-24 08:34:16 -0400215 ~SkGIFFrameContext() override
scroggo19b91532016-10-24 09:03:26 -0700216 {
217 }
218
Leon Scroggins III932efed2016-12-16 11:39:51 -0500219 void addLzwBlock(size_t position, size_t size)
scroggo19b91532016-10-24 09:03:26 -0700220 {
Leon Scroggins III932efed2016-12-16 11:39:51 -0500221 m_lzwBlocks.push_back(SkGIFLZWBlock(position, size));
scroggo19b91532016-10-24 09:03:26 -0700222 }
223
Leon Scroggins III932efed2016-12-16 11:39:51 -0500224 bool decode(SkStreamBuffer*, SkGifCodec* client, bool* frameDecoded);
scroggo19b91532016-10-24 09:03:26 -0700225
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400226 int transparentPixel() const { return m_transparentPixel; }
227 void setTransparentPixel(int pixel) { m_transparentPixel = pixel; }
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500228
scroggo19b91532016-10-24 09:03:26 -0700229 unsigned delayTime() const { return m_delayTime; }
230 void setDelayTime(unsigned delay) { m_delayTime = delay; }
231 bool isComplete() const { return m_isComplete; }
232 void setComplete() { m_isComplete = true; }
233 bool isHeaderDefined() const { return m_isHeaderDefined; }
234 void setHeaderDefined() { m_isHeaderDefined = true; }
235 bool isDataSizeDefined() const { return m_isDataSizeDefined; }
236 int dataSize() const { return m_dataSize; }
237 void setDataSize(int size)
238 {
239 m_dataSize = size;
240 m_isDataSizeDefined = true;
241 }
242 bool progressiveDisplay() const { return m_progressiveDisplay; }
243 void setProgressiveDisplay(bool progressiveDisplay) { m_progressiveDisplay = progressiveDisplay; }
244 bool interlaced() const { return m_interlaced; }
245 void setInterlaced(bool interlaced) { m_interlaced = interlaced; }
246
247 void clearDecodeState() { m_lzwContext.reset(); }
scroggof9acbe22016-10-25 12:43:21 -0700248 const SkGIFColorMap& localColorMap() const { return m_localColorMap; }
249 SkGIFColorMap& localColorMap() { return m_localColorMap; }
scroggo19b91532016-10-24 09:03:26 -0700250
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400251protected:
252 bool onReportsAlpha() const override;
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500253
scroggo19b91532016-10-24 09:03:26 -0700254private:
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400255 // Unowned pointer to the object that owns this frame.
256 const SkGifImageReader* m_owner;
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500257
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400258 int m_transparentPixel; // Index of transparent pixel. Value is kNotFound if there is no transparent pixel.
scroggo19b91532016-10-24 09:03:26 -0700259 int m_dataSize;
260
261 bool m_progressiveDisplay; // If true, do Haeberli interlace hack.
262 bool m_interlaced; // True, if scanlines arrive interlaced order.
263
264 unsigned m_delayTime; // Display time, in milliseconds, for this image in a multi-image GIF.
265
scroggof9acbe22016-10-25 12:43:21 -0700266 std::unique_ptr<SkGIFLZWContext> m_lzwContext;
Leon Scroggins III932efed2016-12-16 11:39:51 -0500267 // LZW blocks for this frame.
268 std::vector<SkGIFLZWBlock> m_lzwBlocks;
269
scroggof9acbe22016-10-25 12:43:21 -0700270 SkGIFColorMap m_localColorMap;
scroggo19b91532016-10-24 09:03:26 -0700271
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400272 int m_currentLzwBlock;
scroggo19b91532016-10-24 09:03:26 -0700273 bool m_isComplete;
274 bool m_isHeaderDefined;
275 bool m_isDataSizeDefined;
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400276
277 typedef SkFrame INHERITED;
scroggo19b91532016-10-24 09:03:26 -0700278};
279
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400280class SkGifImageReader final : public SkFrameHolder {
scroggo19b91532016-10-24 09:03:26 -0700281public:
282 // This takes ownership of stream.
Mike Reedede7bac2017-07-23 15:30:02 -0400283 SkGifImageReader(std::unique_ptr<SkStream> stream)
scroggo19b91532016-10-24 09:03:26 -0700284 : m_client(nullptr)
scroggof9acbe22016-10-25 12:43:21 -0700285 , m_state(SkGIFType)
scroggo19b91532016-10-24 09:03:26 -0700286 , m_bytesToConsume(6) // Number of bytes for GIF type, either "GIF87a" or "GIF89a".
287 , m_version(0)
scroggo19b91532016-10-24 09:03:26 -0700288 , m_loopCount(cLoopCountNotSeen)
Mike Reedede7bac2017-07-23 15:30:02 -0400289 , m_streamBuffer(std::move(stream))
scroggo19b91532016-10-24 09:03:26 -0700290 , m_parseCompleted(false)
291 , m_firstFrameHasAlpha(false)
scroggo19b91532016-10-24 09:03:26 -0700292 {
293 }
294
Kevin Lubick700a79c2017-05-24 08:34:16 -0400295 ~SkGifImageReader() override
scroggo19b91532016-10-24 09:03:26 -0700296 {
297 }
298
299 void setClient(SkGifCodec* client) { m_client = client; }
300
scroggo19b91532016-10-24 09:03:26 -0700301 // Option to pass to parse(). All enums are negative, because a non-negative value is used to
302 // indicate that the Reader should parse up to and including the frame indicated.
scroggof9acbe22016-10-25 12:43:21 -0700303 enum SkGIFParseQuery {
scroggo19b91532016-10-24 09:03:26 -0700304 // Parse enough to determine the size. Note that this parses the first frame's header,
305 // since we may decide to expand based on the frame's dimensions.
scroggof9acbe22016-10-25 12:43:21 -0700306 SkGIFSizeQuery = -1,
scroggo19b91532016-10-24 09:03:26 -0700307 // Parse to the end, so we know about all frames.
scroggof9acbe22016-10-25 12:43:21 -0700308 SkGIFFrameCountQuery = -2,
scroggoe71b1a12016-11-01 08:28:28 -0700309 // Parse until we see the loop count.
310 SkGIFLoopCountQuery = -3,
scroggo19b91532016-10-24 09:03:26 -0700311 };
312
313 // Parse incoming GIF data stream into internal data structures.
314 // Non-negative values are used to indicate to parse through that frame.
Leon Scroggins III588fb042017-07-14 16:32:31 -0400315 SkCodec::Result parse(SkGIFParseQuery);
scroggo19b91532016-10-24 09:03:26 -0700316
317 // Decode the frame indicated by frameIndex.
318 // frameComplete will be set to true if the frame is completely decoded.
319 // The method returns false if there is an error.
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400320 bool decode(int frameIndex, bool* frameComplete);
scroggo19b91532016-10-24 09:03:26 -0700321
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400322 int imagesCount() const
scroggo19b91532016-10-24 09:03:26 -0700323 {
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500324 const size_t frames = m_frames.size();
Leon Scroggins IIIe726e7c2017-07-18 16:22:52 -0400325 if (!frames) {
326 return 0;
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500327 }
scroggo19b91532016-10-24 09:03:26 -0700328
Leon Scroggins IIIe4ba1052017-01-30 13:55:14 -0500329 // This avoids counting an empty frame when the file is truncated (or
330 // simply not yet complete) after receiving SkGIFControlExtension (and
331 // possibly SkGIFImageHeader) but before reading the color table. This
332 // ensures that we do not count a frame before we know its required
333 // frame.
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400334 return static_cast<int>(m_frames.back()->reachedStartOfData() ? frames : frames - 1);
scroggo19b91532016-10-24 09:03:26 -0700335 }
scroggoe71b1a12016-11-01 08:28:28 -0700336 int loopCount() const {
337 if (cLoopCountNotSeen == m_loopCount) {
338 return 0;
339 }
340 return m_loopCount;
341 }
scroggo19b91532016-10-24 09:03:26 -0700342
scroggof9acbe22016-10-25 12:43:21 -0700343 const SkGIFColorMap& globalColorMap() const
scroggo19b91532016-10-24 09:03:26 -0700344 {
345 return m_globalColorMap;
346 }
347
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400348 const SkGIFFrameContext* frameContext(int index) const
scroggo19b91532016-10-24 09:03:26 -0700349 {
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400350 return index >= 0 && index < static_cast<int>(m_frames.size())
Ben Wagnera93a14a2017-08-28 10:34:05 -0400351 ? m_frames[index].get() : nullptr;
scroggo19b91532016-10-24 09:03:26 -0700352 }
353
354 void clearDecodeState() {
355 for (size_t index = 0; index < m_frames.size(); index++) {
356 m_frames[index]->clearDecodeState();
357 }
358 }
359
360 // Return the color table for frame index (which may be the global color table).
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400361 sk_sp<SkColorTable> getColorTable(SkColorType dstColorType, int index);
scroggo19b91532016-10-24 09:03:26 -0700362
363 bool firstFrameHasAlpha() const { return m_firstFrameHasAlpha; }
364
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400365 // Helper function that returns whether an SkGIFFrameContext has transparency.
366 // This method is sometimes called before creating one/parsing its color map,
367 // so it cannot rely on SkGIFFrameContext::transparentPixel or ::localColorMap().
368 bool hasTransparency(int transPix, bool hasLocalColorMap, int localMapColors) const;
369
370protected:
371 const SkFrame* onGetFrame(int i) const override {
372 return static_cast<const SkFrame*>(this->frameContext(i));
373 }
374
scroggo19b91532016-10-24 09:03:26 -0700375private:
376 // Requires that one byte has been buffered into m_streamBuffer.
377 unsigned char getOneByte() const {
378 return reinterpret_cast<const unsigned char*>(m_streamBuffer.get())[0];
379 }
380
381 void addFrameIfNecessary();
382 bool currentFrameIsFirstFrame() const
383 {
384 return m_frames.empty() || (m_frames.size() == 1u && !m_frames[0]->isComplete());
385 }
386
387 // Unowned pointer
388 SkGifCodec* m_client;
389
390 // Parsing state machine.
scroggof9acbe22016-10-25 12:43:21 -0700391 SkGIFState m_state; // Current decoder master state.
scroggo19b91532016-10-24 09:03:26 -0700392 size_t m_bytesToConsume; // Number of bytes to consume for next stage of parsing.
393
394 // Global (multi-image) state.
395 int m_version; // Either 89 for GIF89 or 87 for GIF87.
scroggof9acbe22016-10-25 12:43:21 -0700396 SkGIFColorMap m_globalColorMap;
scroggoe71b1a12016-11-01 08:28:28 -0700397
398 static constexpr int cLoopCountNotSeen = -2;
scroggo19b91532016-10-24 09:03:26 -0700399 int m_loopCount; // Netscape specific extension block to control the number of animation loops a GIF renders.
400
scroggof9acbe22016-10-25 12:43:21 -0700401 std::vector<std::unique_ptr<SkGIFFrameContext>> m_frames;
scroggo19b91532016-10-24 09:03:26 -0700402
403 SkStreamBuffer m_streamBuffer;
404 bool m_parseCompleted;
405
Leon Scroggins571b30f2017-07-11 17:35:31 +0000406 // This value can be computed before we create a SkGIFFrameContext, so we
407 // store it here instead of on m_frames[0].
scroggo19b91532016-10-24 09:03:26 -0700408 bool m_firstFrameHasAlpha;
scroggo19b91532016-10-24 09:03:26 -0700409};
410
411#endif