| /* |
| * Copyright 2015 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "SkCodec.h" |
| #include "SkCodecAnimation.h" |
| #include "SkColorSpace.h" |
| #include "SkColorTable.h" |
| #include "SkImageInfo.h" |
| #include "SkSwizzler.h" |
| |
| #include "SkGifImageReader.h" |
| |
| /* |
| * |
| * This class implements the decoding for gif images |
| * |
| */ |
| class SkGifCodec : public SkCodec { |
| public: |
| static bool IsGif(const void*, size_t); |
| |
| /* |
| * Assumes IsGif was called and returned true |
| * Creates a gif decoder |
| * Reads enough of the stream to determine the image format |
| */ |
| static SkCodec* NewFromStream(SkStream*); |
| |
| // Callback for SkGifImageReader when a row is available. |
| bool haveDecodedRow(size_t frameIndex, const unsigned char* rowBegin, |
| size_t rowNumber, unsigned repeatCount, bool writeTransparentPixels); |
| protected: |
| /* |
| * Performs the full gif decode |
| */ |
| Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, |
| SkPMColor*, int*, int*) override; |
| |
| SkEncodedImageFormat onGetEncodedFormat() const override { |
| return SkEncodedImageFormat::kGIF; |
| } |
| |
| bool onRewind() override; |
| |
| uint64_t onGetFillValue(const SkImageInfo&) const override; |
| |
| std::vector<FrameInfo> onGetFrameInfo() override; |
| int onGetRepetitionCount() override; |
| |
| Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t, |
| const SkCodec::Options&, SkPMColor*, int*) override; |
| |
| Result onIncrementalDecode(int*) override; |
| |
| private: |
| |
| /* |
| * Initializes the color table that we will use for decoding. |
| * |
| * @param dstInfo Contains the requested dst color type. |
| * @param frameIndex Frame whose color table to use. |
| */ |
| void initializeColorTable(const SkImageInfo& dstInfo, size_t frameIndex); |
| |
| /* |
| * Does necessary setup, including setting up the color table and swizzler, |
| * and reports color info to the client. |
| */ |
| Result prepareToDecode(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr, |
| int* inputColorCount, const Options& opts); |
| |
| /* |
| * Initializes the swizzler. |
| * |
| * @param dstInfo Output image information. Dimensions may have been |
| * adjusted if the image frame size does not match the size |
| * indicated in the header. |
| * @param frameIndex Which frame we are decoding. This determines the frameRect |
| * to use. |
| */ |
| void initializeSwizzler(const SkImageInfo& dstInfo, size_t frameIndex); |
| |
| SkSampler* getSampler(bool createIfNecessary) override { |
| SkASSERT(fSwizzler); |
| return fSwizzler.get(); |
| } |
| |
| /* |
| * Recursive function to decode a frame. |
| * |
| * @param firstAttempt Whether this is the first call to decodeFrame since |
| * starting. e.g. true in onGetPixels, and true in the |
| * first call to onIncrementalDecode after calling |
| * onStartIncrementalDecode. |
| * When true, this method may have to initialize the |
| * frame, for example by filling or decoding the prior |
| * frame. |
| * @param opts Options for decoding. May be different from |
| * this->options() for decoding prior frames. Specifies |
| * the frame to decode and whether the prior frame has |
| * already been decoded to fDst. If not, and the frame |
| * is not independent, this method will recursively |
| * decode the frame it depends on. |
| * @param rowsDecoded Out-parameter to report the total number of rows |
| * that have been decoded (or at least written to, if |
| * it had to fill), including rows decoded by prior |
| * calls to onIncrementalDecode. |
| * @return kSuccess if the frame is complete, kIncompleteInput |
| * otherwise. |
| */ |
| Result decodeFrame(bool firstAttempt, const Options& opts, int* rowsDecoded); |
| |
| /* |
| * Swizzles and color xforms (if necessary) into dst. |
| */ |
| void applyXformRow(const SkImageInfo& dstInfo, void* dst, const uint8_t* src) const; |
| |
| /* |
| * Creates an instance of the decoder |
| * Called only by NewFromStream |
| * Takes ownership of the SkGifImageReader |
| */ |
| SkGifCodec(const SkEncodedInfo&, const SkImageInfo&, SkGifImageReader*); |
| |
| std::unique_ptr<SkGifImageReader> fReader; |
| std::unique_ptr<uint8_t[]> fTmpBuffer; |
| std::unique_ptr<SkSwizzler> fSwizzler; |
| sk_sp<SkColorTable> fCurrColorTable; |
| // We may create a dummy table if there is not a Map in the input data. In |
| // that case, we set this value to false, and we can skip a lot of decoding |
| // work (which would not be meaningful anyway). We create a "fake"/"dummy" |
| // one in that case, so the client and the swizzler have something to draw. |
| bool fCurrColorTableIsReal; |
| // Whether the background was filled. |
| bool fFilledBackground; |
| // True on the first call to onIncrementalDecode. This value is passed to |
| // decodeFrame. |
| bool fFirstCallToIncrementalDecode; |
| |
| void* fDst; |
| size_t fDstRowBytes; |
| |
| // Updated inside haveDecodedRow when rows are decoded, unless we filled |
| // the background, in which case it is set once and left alone. |
| int fRowsDecoded; |
| std::unique_ptr<uint32_t[]> fXformBuffer; |
| bool fXformOnDecode; |
| |
| typedef SkCodec INHERITED; |
| }; |