blob: 544ba1369524a82ed0599d55b96422ecd7753ae0 [file] [log] [blame]
/*
* 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 "GIFImageReader.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 GIFImageReader 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;
SkEncodedFormat onGetEncodedFormat() const override {
return kGIF_SkEncodedFormat;
}
bool onRewind() override;
uint64_t onGetFillValue(const SkImageInfo&) const override;
std::vector<FrameInfo> onGetFrameInfo() 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.
* @param inputColorPtr Copies the encoded color table to the client's
* input color table if the client requests kIndex8.
* @param inputColorCount If the client requests kIndex8, this will be set
* to the number of colors in the array that
* inputColorPtr now points to. This will typically
* be 256. Since gifs may have up to 8-bit indices,
* using a 256-entry table means a pixel will never
* be out of range. This will be set to 1 if there
* is no color table, since that will be a
* transparent frame.
*/
void initializeColorTable(const SkImageInfo& dstInfo, size_t frameIndex,
SkPMColor* colorPtr, int* inputColorCount);
/*
* 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);
/*
* Creates an instance of the decoder
* Called only by NewFromStream
* Takes ownership of the GIFImageReader
*/
SkGifCodec(const SkEncodedInfo&, const SkImageInfo&, GIFImageReader*);
std::unique_ptr<GIFImageReader> 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;
typedef SkCodec INHERITED;
};