DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
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
/* -*- 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"

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 gfx::IntRect& 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 tranforms.
  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>
  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 gfx::IntRect& 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;

  SurfacePipe mPipe;  /// The SurfacePipe used to write to the output surface.
};

}  // namespace image
}  // namespace mozilla

#endif  // mozilla_image_decoders_nsGIFDecoder2_h