summaryrefslogtreecommitdiffstats
path: root/image/decoders/nsGIFDecoder2.h
blob: 5a6c501778ec0eb69a0137a06b9e29455459e0b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_image_decoders_nsGIFDecoder2_h
#define mozilla_image_decoders_nsGIFDecoder2_h

#include "Decoder.h"
#include "GIF2.h"
#include "StreamingLexer.h"
#include "SurfacePipe.h"
#include "mozilla/gfx/Swizzle.h"

namespace mozilla {
namespace image {
class RasterImage;

//////////////////////////////////////////////////////////////////////
// nsGIFDecoder2 Definition

class nsGIFDecoder2 : public Decoder {
 public:
  ~nsGIFDecoder2();

  DecoderType GetType() const override { return DecoderType::GIF; }

 protected:
  LexerResult DoDecode(SourceBufferIterator& aIterator,
                       IResumable* aOnResume) override;
  nsresult FinishInternal() override;

  Maybe<Telemetry::HistogramID> SpeedHistogram() const override;

 private:
  friend class DecoderFactory;

  // Decoders should only be instantiated via DecoderFactory.
  explicit nsGIFDecoder2(RasterImage* aImage);

  /// Called when we begin decoding the image.
  void BeginGIF();

  /**
   * Called when we begin decoding a frame.
   *
   * @param aFrameRect The region of the image that contains data. The region
   *                   outside this rect is transparent.
   * @param aDepth The palette depth of this frame.
   * @param aIsInterlaced If true, this frame is an interlaced frame.
   */
  nsresult BeginImageFrame(const OrientedIntRect& aFrameRect, uint16_t aDepth,
                           bool aIsInterlaced);

  /// Called when we finish decoding a frame.
  void EndImageFrame();

  /// Called when we finish decoding the entire image.
  void FlushImageData();

  /// Convert color map to BGRA, applying any necessary CMS transforms.
  void ConvertColormap(uint32_t* aColormap, uint32_t aColors);

  /// Transforms a palette index into a pixel.
  template <typename PixelSize>
  PixelSize ColormapIndexToPixel(uint8_t aIndex);

  /// A generator function that performs LZW decompression and yields pixels.
  template <typename PixelSize>
  std::tuple<int32_t, Maybe<WriteState>> YieldPixels(const uint8_t* aData,
                                                     size_t aLength,
                                                     size_t* aBytesReadOut,
                                                     PixelSize* aPixelBlock,
                                                     int32_t aBlockSize);

  /// Checks if we have transparency, either because the header indicates that
  /// there's alpha, or because the frame rect doesn't cover the entire image.
  bool CheckForTransparency(const OrientedIntRect& aFrameRect);

  // @return the clear code used for LZW decompression.
  int ClearCode() const {
    MOZ_ASSERT(mGIFStruct.datasize <= MAX_LZW_BITS);
    return 1 << mGIFStruct.datasize;
  }

  enum class State {
    FAILURE,
    SUCCESS,
    GIF_HEADER,
    SCREEN_DESCRIPTOR,
    GLOBAL_COLOR_TABLE,
    FINISHED_GLOBAL_COLOR_TABLE,
    BLOCK_HEADER,
    EXTENSION_HEADER,
    GRAPHIC_CONTROL_EXTENSION,
    APPLICATION_IDENTIFIER,
    NETSCAPE_EXTENSION_SUB_BLOCK,
    NETSCAPE_EXTENSION_DATA,
    IMAGE_DESCRIPTOR,
    FINISH_IMAGE_DESCRIPTOR,
    LOCAL_COLOR_TABLE,
    FINISHED_LOCAL_COLOR_TABLE,
    IMAGE_DATA_BLOCK,
    IMAGE_DATA_SUB_BLOCK,
    LZW_DATA,
    SKIP_LZW_DATA,
    FINISHED_LZW_DATA,
    SKIP_SUB_BLOCKS,
    SKIP_DATA_THEN_SKIP_SUB_BLOCKS,
    FINISHED_SKIPPING_DATA
  };

  LexerTransition<State> ReadGIFHeader(const char* aData);
  LexerTransition<State> ReadScreenDescriptor(const char* aData);
  LexerTransition<State> ReadGlobalColorTable(const char* aData,
                                              size_t aLength);
  LexerTransition<State> FinishedGlobalColorTable();
  LexerTransition<State> ReadBlockHeader(const char* aData);
  LexerTransition<State> ReadExtensionHeader(const char* aData);
  LexerTransition<State> ReadGraphicControlExtension(const char* aData);
  LexerTransition<State> ReadApplicationIdentifier(const char* aData);
  LexerTransition<State> ReadNetscapeExtensionSubBlock(const char* aData);
  LexerTransition<State> ReadNetscapeExtensionData(const char* aData);
  LexerTransition<State> ReadImageDescriptor(const char* aData);
  LexerTransition<State> FinishImageDescriptor(const char* aData);
  LexerTransition<State> ReadLocalColorTable(const char* aData, size_t aLength);
  LexerTransition<State> FinishedLocalColorTable();
  LexerTransition<State> ReadImageDataBlock(const char* aData);
  LexerTransition<State> ReadImageDataSubBlock(const char* aData);
  LexerTransition<State> ReadLZWData(const char* aData, size_t aLength);
  LexerTransition<State> SkipSubBlocks(const char* aData);

  // The StreamingLexer used to manage input. The initial size of the buffer is
  // chosen as a little larger than the maximum size of any fixed-length data we
  // have to read for a state. We read variable-length data in unbuffered mode
  // so the buffer shouldn't have to be resized during decoding.
  StreamingLexer<State, 16> mLexer;

  uint32_t mOldColor;  // The old value of the transparent pixel

  // The frame number of the currently-decoding frame when we're in the middle
  // of decoding it, and -1 otherwise.
  int32_t mCurrentFrameIndex;

  // When we're reading in the global or local color table, this records our
  // current position - i.e., the offset into which the next byte should be
  // written.
  size_t mColorTablePos;
  uint32_t* mColormap;  // Current colormap to be used in Cairo format
  uint32_t mColormapSize;

  uint8_t mColorMask;  // Apply this to the pixel to keep within colormap
  bool mGIFOpen;
  bool mSawTransparency;

  gif_struct mGIFStruct;

  gfx::SwizzleRowFn mSwizzleFn;  /// Method to unpack color tables from RGB.
  SurfacePipe mPipe;  /// The SurfacePipe used to write to the output surface.
};

}  // namespace image
}  // namespace mozilla

#endif  // mozilla_image_decoders_nsGIFDecoder2_h