1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_image_decoders_nsGIFDecoder2_h
8 #define mozilla_image_decoders_nsGIFDecoder2_h
9 
10 #include "Decoder.h"
11 #include "GIF2.h"
12 #include "StreamingLexer.h"
13 #include "SurfacePipe.h"
14 
15 namespace mozilla {
16 namespace image {
17 class RasterImage;
18 
19 //////////////////////////////////////////////////////////////////////
20 // nsGIFDecoder2 Definition
21 
22 class nsGIFDecoder2 : public Decoder
23 {
24 public:
25   ~nsGIFDecoder2();
26 
27 protected:
28   LexerResult DoDecode(SourceBufferIterator& aIterator,
29                        IResumable* aOnResume) override;
30   nsresult FinishInternal() override;
31 
32   Maybe<Telemetry::ID> SpeedHistogram() const override;
33 
34 private:
35   friend class DecoderFactory;
36 
37   // Decoders should only be instantiated via DecoderFactory.
38   explicit nsGIFDecoder2(RasterImage* aImage);
39 
40   /// Called when we begin decoding the image.
41   void      BeginGIF();
42 
43   /**
44    * Called when we begin decoding a frame.
45    *
46    * @param aFrameRect The region of the image that contains data. The region
47    *                   outside this rect is transparent.
48    * @param aDepth The palette depth of this frame.
49    * @param aIsInterlaced If true, this frame is an interlaced frame.
50    */
51   nsresult  BeginImageFrame(const gfx::IntRect& aFrameRect,
52                             uint16_t aDepth,
53                             bool aIsInterlaced);
54 
55   /// Called when we finish decoding a frame.
56   void      EndImageFrame();
57 
58   /// Called when we finish decoding the entire image.
59   void      FlushImageData();
60 
61   /// Transforms a palette index into a pixel.
62   template <typename PixelSize> PixelSize
63   ColormapIndexToPixel(uint8_t aIndex);
64 
65   /// A generator function that performs LZW decompression and yields pixels.
66   template <typename PixelSize> NextPixel<PixelSize>
67   YieldPixel(const uint8_t* aData, size_t aLength, size_t* aBytesReadOut);
68 
69   /// Checks if we have transparency, either because the header indicates that
70   /// there's alpha, or because the frame rect doesn't cover the entire image.
71   bool CheckForTransparency(const gfx::IntRect& aFrameRect);
72 
73   // @return the clear code used for LZW decompression.
ClearCode()74   int ClearCode() const { return 1 << mGIFStruct.datasize; }
75 
76   enum class State
77   {
78     FAILURE,
79     SUCCESS,
80     GIF_HEADER,
81     SCREEN_DESCRIPTOR,
82     GLOBAL_COLOR_TABLE,
83     FINISHED_GLOBAL_COLOR_TABLE,
84     BLOCK_HEADER,
85     EXTENSION_HEADER,
86     GRAPHIC_CONTROL_EXTENSION,
87     APPLICATION_IDENTIFIER,
88     NETSCAPE_EXTENSION_SUB_BLOCK,
89     NETSCAPE_EXTENSION_DATA,
90     IMAGE_DESCRIPTOR,
91     FINISH_IMAGE_DESCRIPTOR,
92     LOCAL_COLOR_TABLE,
93     FINISHED_LOCAL_COLOR_TABLE,
94     IMAGE_DATA_BLOCK,
95     IMAGE_DATA_SUB_BLOCK,
96     LZW_DATA,
97     SKIP_LZW_DATA,
98     FINISHED_LZW_DATA,
99     SKIP_SUB_BLOCKS,
100     SKIP_DATA_THEN_SKIP_SUB_BLOCKS,
101     FINISHED_SKIPPING_DATA
102   };
103 
104   LexerTransition<State> ReadGIFHeader(const char* aData);
105   LexerTransition<State> ReadScreenDescriptor(const char* aData);
106   LexerTransition<State> ReadGlobalColorTable(const char* aData, size_t aLength);
107   LexerTransition<State> FinishedGlobalColorTable();
108   LexerTransition<State> ReadBlockHeader(const char* aData);
109   LexerTransition<State> ReadExtensionHeader(const char* aData);
110   LexerTransition<State> ReadGraphicControlExtension(const char* aData);
111   LexerTransition<State> ReadApplicationIdentifier(const char* aData);
112   LexerTransition<State> ReadNetscapeExtensionSubBlock(const char* aData);
113   LexerTransition<State> ReadNetscapeExtensionData(const char* aData);
114   LexerTransition<State> ReadImageDescriptor(const char* aData);
115   LexerTransition<State> FinishImageDescriptor(const char* aData);
116   LexerTransition<State> ReadLocalColorTable(const char* aData, size_t aLength);
117   LexerTransition<State> FinishedLocalColorTable();
118   LexerTransition<State> ReadImageDataBlock(const char* aData);
119   LexerTransition<State> ReadImageDataSubBlock(const char* aData);
120   LexerTransition<State> ReadLZWData(const char* aData, size_t aLength);
121   LexerTransition<State> SkipSubBlocks(const char* aData);
122 
123   // The StreamingLexer used to manage input. The initial size of the buffer is
124   // chosen as a little larger than the maximum size of any fixed-length data we
125   // have to read for a state. We read variable-length data in unbuffered mode
126   // so the buffer shouldn't have to be resized during decoding.
127   StreamingLexer<State, 16> mLexer;
128 
129   uint32_t mOldColor;        // The old value of the transparent pixel
130 
131   // The frame number of the currently-decoding frame when we're in the middle
132   // of decoding it, and -1 otherwise.
133   int32_t mCurrentFrameIndex;
134 
135   // When we're reading in the global or local color table, this records our
136   // current position - i.e., the offset into which the next byte should be
137   // written.
138   size_t mColorTablePos;
139 
140   uint8_t mColorMask;        // Apply this to the pixel to keep within colormap
141   bool mGIFOpen;
142   bool mSawTransparency;
143 
144   gif_struct mGIFStruct;
145 
146   SurfacePipe mPipe;  /// The SurfacePipe used to write to the output surface.
147 };
148 
149 } // namespace image
150 } // namespace mozilla
151 
152 #endif // mozilla_image_decoders_nsGIFDecoder2_h
153