msarett | 8c8f22a | 2015-04-01 06:58:48 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2015 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #include "SkCodec.h" |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 9 | #include "SkColorTable.h" |
msarett | 8c8f22a | 2015-04-01 06:58:48 -0700 | [diff] [blame] | 10 | #include "SkImageInfo.h" |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 11 | #include "SkSwizzler.h" |
msarett | 8c8f22a | 2015-04-01 06:58:48 -0700 | [diff] [blame] | 12 | |
| 13 | #include "gif_lib.h" |
| 14 | |
| 15 | /* |
| 16 | * |
| 17 | * This class implements the decoding for gif images |
| 18 | * |
| 19 | */ |
| 20 | class SkGifCodec : public SkCodec { |
| 21 | public: |
| 22 | |
| 23 | /* |
| 24 | * Checks the start of the stream to see if the image is a gif |
| 25 | */ |
| 26 | static bool IsGif(SkStream*); |
| 27 | |
| 28 | /* |
| 29 | * Assumes IsGif was called and returned true |
| 30 | * Creates a gif decoder |
| 31 | * Reads enough of the stream to determine the image format |
| 32 | */ |
| 33 | static SkCodec* NewFromStream(SkStream*); |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 34 | |
msarett | 8c8f22a | 2015-04-01 06:58:48 -0700 | [diff] [blame] | 35 | protected: |
| 36 | |
| 37 | /* |
msarett | 438b2ad | 2015-04-09 12:43:10 -0700 | [diff] [blame] | 38 | * Read enough of the stream to initialize the SkGifCodec. |
| 39 | * Returns a bool representing success or failure. |
| 40 | * |
| 41 | * @param codecOut |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 42 | * If it returned true, and codecOut was not nullptr, |
msarett | 438b2ad | 2015-04-09 12:43:10 -0700 | [diff] [blame] | 43 | * codecOut will be set to a new SkGifCodec. |
| 44 | * |
| 45 | * @param gifOut |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 46 | * If it returned true, and codecOut was nullptr, |
| 47 | * gifOut must be non-nullptr and gifOut will be set to a new |
msarett | 438b2ad | 2015-04-09 12:43:10 -0700 | [diff] [blame] | 48 | * GifFileType pointer. |
| 49 | * |
| 50 | * @param stream |
| 51 | * Deleted on failure. |
| 52 | * codecOut will take ownership of it in the case where we created a codec. |
| 53 | * Ownership is unchanged when we returned a gifOut. |
| 54 | * |
| 55 | */ |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 56 | static bool ReadHeader(SkStream* stream, SkCodec** codecOut, |
| 57 | GifFileType** gifOut); |
msarett | 438b2ad | 2015-04-09 12:43:10 -0700 | [diff] [blame] | 58 | |
| 59 | /* |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 60 | * Performs the full gif decode |
msarett | 8c8f22a | 2015-04-01 06:58:48 -0700 | [diff] [blame] | 61 | */ |
| 62 | Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, |
msarett | e6dd004 | 2015-10-09 11:07:34 -0700 | [diff] [blame] | 63 | SkPMColor*, int*, int*) override; |
msarett | 8c8f22a | 2015-04-01 06:58:48 -0700 | [diff] [blame] | 64 | |
| 65 | SkEncodedFormat onGetEncodedFormat() const override { |
| 66 | return kGIF_SkEncodedFormat; |
| 67 | } |
| 68 | |
scroggo | b427db1 | 2015-08-12 07:24:13 -0700 | [diff] [blame] | 69 | bool onRewind() override; |
| 70 | |
msarett | e6dd004 | 2015-10-09 11:07:34 -0700 | [diff] [blame] | 71 | uint32_t onGetFillValue(SkColorType colorType, SkAlphaType alphaType) const override; |
| 72 | |
mtklein | e975928 | 2015-10-15 08:55:33 -0700 | [diff] [blame] | 73 | int onOutputScanline(int inputScanline) const override; |
msarett | e6dd004 | 2015-10-09 11:07:34 -0700 | [diff] [blame] | 74 | |
msarett | 8c8f22a | 2015-04-01 06:58:48 -0700 | [diff] [blame] | 75 | private: |
| 76 | |
| 77 | /* |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 78 | * A gif can contain multiple image frames. We will only decode the first |
| 79 | * frame. This function reads up to the first image frame, processing |
| 80 | * transparency and/or animation information that comes before the image |
| 81 | * data. |
| 82 | * |
| 83 | * @param gif Pointer to the library type that manages the gif decode |
| 84 | * @param transIndex This call will set the transparent index based on the |
| 85 | * extension data. |
| 86 | */ |
scroggo | 46c5747 | 2015-09-30 08:57:13 -0700 | [diff] [blame] | 87 | static Result ReadUpToFirstImage(GifFileType* gif, uint32_t* transIndex); |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 88 | |
| 89 | /* |
| 90 | * A gif may contain many image frames, all of different sizes. |
msarett | 4aa02d8 | 2015-10-06 07:46:02 -0700 | [diff] [blame] | 91 | * This function checks if the gif dimensions are valid, based on the frame |
| 92 | * dimensions, and corrects the gif dimensions if necessary. |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 93 | * |
msarett | 4aa02d8 | 2015-10-06 07:46:02 -0700 | [diff] [blame] | 94 | * @param gif Pointer to the library type that manages the gif decode |
| 95 | * @param size Size of the image that we will decode. |
| 96 | * Will be set by this function if the return value is true. |
| 97 | * @param frameRect Contains the dimenions and offset of the first image frame. |
| 98 | * Will be set by this function if the return value is true. |
| 99 | * |
| 100 | * @return true on success, false otherwise |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 101 | */ |
msarett | 4aa02d8 | 2015-10-06 07:46:02 -0700 | [diff] [blame] | 102 | static bool GetDimensions(GifFileType* gif, SkISize* size, SkIRect* frameRect); |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 103 | |
| 104 | /* |
| 105 | * Initializes the color table that we will use for decoding. |
| 106 | * |
| 107 | * @param dstInfo Contains the requested dst color type. |
| 108 | * @param inputColorPtr Copies the encoded color table to the client's |
| 109 | * input color table if the client requests kIndex8. |
| 110 | * @param inputColorCount If the client requests kIndex8, sets |
| 111 | * inputColorCount to 256. Since gifs always |
| 112 | * contain 8-bit indices, we need a 256 entry color |
| 113 | * table to ensure that indexing is always in |
| 114 | * bounds. |
| 115 | */ |
| 116 | void initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* colorPtr, |
| 117 | int* inputColorCount); |
| 118 | |
| 119 | /* |
scroggo | 3a7701c | 2015-09-30 09:15:14 -0700 | [diff] [blame] | 120 | * Checks for invalid inputs and calls setFrameDimensions(), and |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 121 | * initializeColorTable() in the proper sequence. |
| 122 | */ |
scroggo | 46c5747 | 2015-09-30 08:57:13 -0700 | [diff] [blame] | 123 | Result prepareToDecode(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr, |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 124 | int* inputColorCount, const Options& opts); |
| 125 | |
| 126 | /* |
| 127 | * Initializes the swizzler. |
| 128 | * |
| 129 | * @param dstInfo Output image information. Dimensions may have been |
| 130 | * adjusted if the image frame size does not match the size |
| 131 | * indicated in the header. |
msarett | fdb4757 | 2015-10-13 12:50:14 -0700 | [diff] [blame] | 132 | * @param options Informs the swizzler if destination memory is zero initialized. |
| 133 | * Contains subset information. |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 134 | */ |
msarett | fdb4757 | 2015-10-13 12:50:14 -0700 | [diff] [blame] | 135 | Result initializeSwizzler(const SkImageInfo& dstInfo, |
| 136 | const Options& options); |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 137 | |
msarett | e6dd004 | 2015-10-09 11:07:34 -0700 | [diff] [blame] | 138 | SkSampler* getSampler(bool createIfNecessary) override { |
| 139 | SkASSERT(fSwizzler); |
| 140 | return fSwizzler; |
| 141 | } |
scroggo | e7fc14b | 2015-10-02 13:14:46 -0700 | [diff] [blame] | 142 | |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 143 | /* |
msarett | e6dd004 | 2015-10-09 11:07:34 -0700 | [diff] [blame] | 144 | * @return true if the read is successful and false if the read fails. |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 145 | */ |
msarett | e6dd004 | 2015-10-09 11:07:34 -0700 | [diff] [blame] | 146 | bool readRow(); |
scroggo | 46c5747 | 2015-09-30 08:57:13 -0700 | [diff] [blame] | 147 | |
| 148 | Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opts, |
| 149 | SkPMColor inputColorPtr[], int* inputColorCount) override; |
| 150 | |
msarett | e6dd004 | 2015-10-09 11:07:34 -0700 | [diff] [blame] | 151 | int onGetScanlines(void* dst, int count, size_t rowBytes) override; |
scroggo | 46c5747 | 2015-09-30 08:57:13 -0700 | [diff] [blame] | 152 | |
msarett | 72261c0 | 2015-11-19 15:29:26 -0800 | [diff] [blame] | 153 | bool onSkipScanlines(int count) override; |
| 154 | |
| 155 | /* |
| 156 | * For a scanline decode of "count" lines, this function indicates how |
| 157 | * many of the "count" lines should be skipped until we reach the top of |
| 158 | * the image frame and how many of the "count" lines are actually inside |
| 159 | * the image frame. |
| 160 | * |
| 161 | * @param count The number of scanlines requested. |
| 162 | * @param rowsBeforeFrame Output variable. The number of lines before |
| 163 | * we reach the top of the image frame. |
| 164 | * @param rowsInFrame Output variable. The number of lines to decode |
| 165 | * inside the image frame. |
| 166 | */ |
| 167 | void handleScanlineFrame(int count, int* rowsBeforeFrame, int* rowsInFrame); |
| 168 | |
scroggo | 46c5747 | 2015-09-30 08:57:13 -0700 | [diff] [blame] | 169 | SkScanlineOrder onGetScanlineOrder() const override; |
| 170 | |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 171 | /* |
msarett | 8c8f22a | 2015-04-01 06:58:48 -0700 | [diff] [blame] | 172 | * This function cleans up the gif object after the decode completes |
| 173 | * It is used in a SkAutoTCallIProc template |
| 174 | */ |
msarett | 438b2ad | 2015-04-09 12:43:10 -0700 | [diff] [blame] | 175 | static void CloseGif(GifFileType* gif); |
msarett | 8c8f22a | 2015-04-01 06:58:48 -0700 | [diff] [blame] | 176 | |
| 177 | /* |
| 178 | * Frees any extension data used in the decode |
| 179 | * Used in a SkAutoTCallVProc |
| 180 | */ |
| 181 | static void FreeExtension(SavedImage* image); |
| 182 | |
| 183 | /* |
| 184 | * Creates an instance of the decoder |
| 185 | * Called only by NewFromStream |
| 186 | * |
| 187 | * @param srcInfo contains the source width and height |
| 188 | * @param stream the stream of image data |
| 189 | * @param gif pointer to library type that manages gif decode |
| 190 | * takes ownership |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 191 | * @param transIndex The transparent index. An invalid value |
| 192 | * indicates that there is no transparent index. |
msarett | 8c8f22a | 2015-04-01 06:58:48 -0700 | [diff] [blame] | 193 | */ |
msarett | 4aa02d8 | 2015-10-06 07:46:02 -0700 | [diff] [blame] | 194 | SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, GifFileType* gif, uint32_t transIndex, |
| 195 | const SkIRect& frameRect, bool frameIsSubset); |
msarett | 8c8f22a | 2015-04-01 06:58:48 -0700 | [diff] [blame] | 196 | |
msarett | 438b2ad | 2015-04-09 12:43:10 -0700 | [diff] [blame] | 197 | SkAutoTCallVProc<GifFileType, CloseGif> fGif; // owned |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 198 | SkAutoTDeleteArray<uint8_t> fSrcBuffer; |
msarett | 4aa02d8 | 2015-10-06 07:46:02 -0700 | [diff] [blame] | 199 | const SkIRect fFrameRect; |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 200 | const uint32_t fTransIndex; |
| 201 | uint32_t fFillIndex; |
msarett | 4aa02d8 | 2015-10-06 07:46:02 -0700 | [diff] [blame] | 202 | const bool fFrameIsSubset; |
msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 203 | SkAutoTDelete<SkSwizzler> fSwizzler; |
| 204 | SkAutoTUnref<SkColorTable> fColorTable; |
| 205 | |
msarett | 8c8f22a | 2015-04-01 06:58:48 -0700 | [diff] [blame] | 206 | typedef SkCodec INHERITED; |
| 207 | }; |