/* -*- 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 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 PixelSize ColormapIndexToPixel(uint8_t aIndex); /// A generator function that performs LZW decompression and yields pixels. template std::tuple> 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 ReadGIFHeader(const char* aData); LexerTransition ReadScreenDescriptor(const char* aData); LexerTransition ReadGlobalColorTable(const char* aData, size_t aLength); LexerTransition FinishedGlobalColorTable(); LexerTransition ReadBlockHeader(const char* aData); LexerTransition ReadExtensionHeader(const char* aData); LexerTransition ReadGraphicControlExtension(const char* aData); LexerTransition ReadApplicationIdentifier(const char* aData); LexerTransition ReadNetscapeExtensionSubBlock(const char* aData); LexerTransition ReadNetscapeExtensionData(const char* aData); LexerTransition ReadImageDescriptor(const char* aData); LexerTransition FinishImageDescriptor(const char* aData); LexerTransition ReadLocalColorTable(const char* aData, size_t aLength); LexerTransition FinishedLocalColorTable(); LexerTransition ReadImageDataBlock(const char* aData); LexerTransition ReadImageDataSubBlock(const char* aData); LexerTransition ReadLZWData(const char* aData, size_t aLength); LexerTransition 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 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