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