OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 | |
9 #include "SkColor.h" | 8 #include "SkColor.h" |
10 #include "SkColorPriv.h" | 9 #include "SkColorPriv.h" |
11 #include "SkColorTable.h" | 10 #include "SkColorTable.h" |
12 #include "SkImageDecoder.h" | 11 #include "SkImageDecoder.h" |
12 #include "SkRTConf.h" | |
13 #include "SkScaledBitmapSampler.h" | 13 #include "SkScaledBitmapSampler.h" |
14 #include "SkStream.h" | 14 #include "SkStream.h" |
15 #include "SkTemplates.h" | 15 #include "SkTemplates.h" |
16 | 16 |
17 #include "gif_lib.h" | 17 #include "gif_lib.h" |
18 | 18 |
19 class SkGIFImageDecoder : public SkImageDecoder { | 19 class SkGIFImageDecoder : public SkImageDecoder { |
20 public: | 20 public: |
21 virtual Format getFormat() const SK_OVERRIDE { | 21 virtual Format getFormat() const SK_OVERRIDE { |
22 return kGIF_Format; | 22 return kGIF_Format; |
23 } | 23 } |
24 | 24 |
25 protected: | 25 protected: |
26 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE ; | 26 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE ; |
27 | 27 |
28 private: | 28 private: |
29 typedef SkImageDecoder INHERITED; | 29 typedef SkImageDecoder INHERITED; |
30 }; | 30 }; |
31 | 31 |
32 static const uint8_t gStartingIterlaceYValue[] = { | 32 static const uint8_t gStartingIterlaceYValue[] = { |
33 0, 4, 2, 1 | 33 0, 4, 2, 1 |
34 }; | 34 }; |
35 static const uint8_t gDeltaIterlaceYValue[] = { | 35 static const uint8_t gDeltaIterlaceYValue[] = { |
36 8, 8, 4, 2 | 36 8, 8, 4, 2 |
37 }; | 37 }; |
38 | 38 |
39 SK_CONF_DECLARE(bool, c_suppressGIFImageDecoderWarnings, | |
40 "images.gif.suppressDecoderWarnings", true, | |
41 "Suppress GIF warnings and errors when calling image decode " | |
42 "functions."); | |
43 | |
44 | |
39 /* Implement the GIF interlace algorithm in an iterator. | 45 /* Implement the GIF interlace algorithm in an iterator. |
40 1) grab every 8th line beginning at 0 | 46 1) grab every 8th line beginning at 0 |
41 2) grab every 8th line beginning at 4 | 47 2) grab every 8th line beginning at 4 |
42 3) grab every 4th line beginning at 2 | 48 3) grab every 4th line beginning at 2 |
43 4) grab every 2nd line beginning at 1 | 49 4) grab every 2nd line beginning at 1 |
44 */ | 50 */ |
45 class GifInterlaceIter { | 51 class GifInterlaceIter { |
46 public: | 52 public: |
47 GifInterlaceIter(int height) : fHeight(height) { | 53 GifInterlaceIter(int height) : fHeight(height) { |
48 fStartYPtr = gStartingIterlaceYValue; | 54 fStartYPtr = gStartingIterlaceYValue; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
140 } | 146 } |
141 break; | 147 break; |
142 } | 148 } |
143 } | 149 } |
144 } | 150 } |
145 return transpIndex; | 151 return transpIndex; |
146 } | 152 } |
147 | 153 |
148 static bool error_return(GifFileType* gif, const SkBitmap& bm, | 154 static bool error_return(GifFileType* gif, const SkBitmap& bm, |
149 const char msg[]) { | 155 const char msg[]) { |
150 #if 0 | 156 if (!c_suppressGIFImageDecoderWarnings) { |
151 SkDebugf("libgif error <%s> bitmap [%d %d] pixels %p colortable %p\n", | 157 SkDebugf("libgif error [%s] bitmap [%d %d] pixels %p colortable %p\n", |
152 msg, bm.width(), bm.height(), bm.getPixels(), bm.getColorTable()); | 158 msg, bm.width(), bm.height(), bm.getPixels(), bm.getColorTable( )); |
153 #endif | 159 } |
154 return false; | 160 return false; |
155 } | 161 } |
162 static void gif_warning(GifFileType* gif, const SkBitmap& bm, | |
scroggo
2013/10/09 20:12:03
gif is never used.
(Same in error_return)
hal.canary
2013/10/10 16:22:11
Good catch.
| |
163 const char msg[]) { | |
164 if (!c_suppressGIFImageDecoderWarnings) { | |
165 SkDebugf("libgif warning [%s] bitmap [%d %d] pixels %p colortable %p\n", | |
166 msg, bm.width(), bm.height(), bm.getPixels(), | |
167 bm.getColorTable()); | |
168 } | |
169 } | |
156 | 170 |
157 /** | 171 /** |
172 * Used several times in SkGIFImageDecoder::onDecode() to determine | |
173 * the index value to use when the image is truncated or doesn't fill | |
174 * the bitmap. */ | |
175 static int get_fill_index(int transpIndex, int colorCount, GifFileType & gif) { | |
scroggo
2013/10/09 20:12:03
Can't gif be const?
hal.canary
2013/10/10 16:22:11
good catch.
| |
176 int fill = 0; | |
177 if (transpIndex >= 0) { | |
178 fill = transpIndex; | |
179 } else { | |
180 fill = gif.SBackGroundColor; | |
181 } | |
182 // check for valid fill index/color | |
183 if (static_cast<unsigned>(fill) >= | |
184 static_cast<unsigned>(colorCount)) { | |
185 return 0; | |
186 } | |
187 return fill; | |
188 } | |
189 | |
190 | |
191 /** | |
158 * Skip rows in the source gif image. | 192 * Skip rows in the source gif image. |
159 * @param gif Source image. | 193 * @param gif Source image. |
160 * @param dst Scratch output needed by gif library call. Must be >= width bytes . | 194 * @param dst Scratch output needed by gif library call. Must be >= width bytes . |
161 * @param width Bytes per row in the source image. | 195 * @param width Bytes per row in the source image. |
162 * @param rowsToSkip Number of rows to skip. | 196 * @param rowsToSkip Number of rows to skip. |
163 * @return True on success, false on GIF_ERROR. | 197 * @return True on success, false on GIF_ERROR. |
164 */ | 198 */ |
165 static bool skip_src_rows(GifFileType* gif, uint8_t* dst, int width, int rowsToS kip) { | 199 static bool skip_src_rows(GifFileType* gif, uint8_t* dst, int width, int rowsToS kip) { |
166 for (int i = 0; i < rowsToSkip; i++) { | 200 for (int i = 0; i < rowsToSkip; i++) { |
167 if (DGifGetLine(gif, dst, width) == GIF_ERROR) { | 201 if (DGifGetLine(gif, dst, width) == GIF_ERROR) { |
(...skipping 19 matching lines...) Expand all Loading... | |
187 temp_save.ExtensionBlocks=NULL; | 221 temp_save.ExtensionBlocks=NULL; |
188 temp_save.ExtensionBlockCount=0; | 222 temp_save.ExtensionBlockCount=0; |
189 SkAutoTCallVProc<SavedImage, CheckFreeExtension> acp2(&temp_save); | 223 SkAutoTCallVProc<SavedImage, CheckFreeExtension> acp2(&temp_save); |
190 | 224 |
191 int width, height; | 225 int width, height; |
192 GifRecordType recType; | 226 GifRecordType recType; |
193 GifByteType *extData; | 227 GifByteType *extData; |
194 #if GIFLIB_MAJOR >= 5 | 228 #if GIFLIB_MAJOR >= 5 |
195 int extFunction; | 229 int extFunction; |
196 #endif | 230 #endif |
197 int transpIndex = -1; // -1 means we don't have it (yet) | 231 int transpIndex = -1; // -1 means we don't have it (yet) |
scroggo
2013/10/09 20:12:03
Would it make sense to define a fill color here, a
hal.canary
2013/10/10 16:22:11
I was thinking about the waste of extra logic that
| |
198 | 232 |
199 do { | 233 do { |
200 if (DGifGetRecordType(gif, &recType) == GIF_ERROR) { | 234 if (DGifGetRecordType(gif, &recType) == GIF_ERROR) { |
201 return error_return(gif, *bm, "DGifGetRecordType"); | 235 return error_return(gif, *bm, "DGifGetRecordType"); |
202 } | 236 } |
203 | 237 |
204 switch (recType) { | 238 switch (recType) { |
205 case IMAGE_DESC_RECORD_TYPE: { | 239 case IMAGE_DESC_RECORD_TYPE: { |
206 if (DGifGetImageDesc(gif) == GIF_ERROR) { | 240 if (DGifGetImageDesc(gif) == GIF_ERROR) { |
207 return error_return(gif, *bm, "IMAGE_DESC_RECORD_TYPE"); | 241 return error_return(gif, *bm, "IMAGE_DESC_RECORD_TYPE"); |
208 } | 242 } |
209 | 243 |
210 if (gif->ImageCount < 1) { // sanity check | 244 if (gif->ImageCount < 1) { // sanity check |
211 return error_return(gif, *bm, "ImageCount < 1"); | 245 return error_return(gif, *bm, "ImageCount < 1"); |
212 } | 246 } |
213 | 247 |
214 width = gif->SWidth; | 248 width = gif->SWidth; |
215 height = gif->SHeight; | 249 height = gif->SHeight; |
216 if (width <= 0 || height <= 0) { | 250 // if (width <= 0 || height <= 0) { |
scroggo
2013/10/09 20:12:03
Any reason not to remove this commented out code?
hal.canary
2013/10/10 16:22:11
Good catch
| |
251 // return error_return(gif, *bm, "invalid dimensions"); | |
252 // } | |
253 SavedImage* image = &gif->SavedImages[gif->ImageCount-1]; | |
254 const GifImageDesc& desc = image->ImageDesc; | |
255 | |
256 int imageLeft = desc.Left; | |
257 int imageTop = desc.Top; | |
258 const int innerWidth = desc.Width; | |
259 const int innerHeight = desc.Height; | |
260 if (innerWidth <= 0 || innerHeight <= 0) { | |
217 return error_return(gif, *bm, "invalid dimensions"); | 261 return error_return(gif, *bm, "invalid dimensions"); |
218 } | 262 } |
219 | 263 |
264 // check for valid descriptor | |
265 if (innerWidth > width) { | |
266 gif_warning(gif, *bm, "image too wide, expanding output to size" ); | |
267 width = innerWidth; | |
268 imageLeft = 0; | |
269 } else if (imageLeft + innerWidth > width) { | |
270 gif_warning(gif, *bm, "shifting image left to fit"); | |
271 imageLeft = width - innerWidth; | |
272 } else if (imageLeft < 0) { | |
273 gif_warning(gif, *bm, "shifting image right to fit"); | |
274 imageLeft = 0; | |
275 } | |
276 | |
277 | |
278 if (innerHeight > height) { | |
279 gif_warning(gif, *bm, "image too tall, expanding output to size "); | |
280 height = innerHeight; | |
281 imageTop = 0; | |
282 } else if (imageTop + innerHeight > height) { | |
283 gif_warning(gif, *bm, "shifting image up to fit"); | |
284 imageTop = height - innerHeight; | |
285 } else if (imageTop < 0) { | |
286 gif_warning(gif, *bm, "shifting image down to fit"); | |
287 imageTop = 0; | |
288 } | |
289 | |
220 // FIXME: We could give the caller a choice of images or configs. | 290 // FIXME: We could give the caller a choice of images or configs. |
221 if (!this->chooseFromOneChoice(SkBitmap::kIndex8_Config, width, heig ht)) { | 291 if (!this->chooseFromOneChoice(SkBitmap::kIndex8_Config, width, heig ht)) { |
222 return error_return(gif, *bm, "chooseFromOneChoice"); | 292 return error_return(gif, *bm, "chooseFromOneChoice"); |
223 } | 293 } |
224 | 294 |
225 SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); | 295 SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); |
226 | 296 |
227 bm->setConfig(SkBitmap::kIndex8_Config, sampler.scaledWidth(), | 297 bm->setConfig(SkBitmap::kIndex8_Config, sampler.scaledWidth(), |
228 sampler.scaledHeight()); | 298 sampler.scaledHeight()); |
229 | 299 |
230 if (SkImageDecoder::kDecodeBounds_Mode == mode) { | 300 if (SkImageDecoder::kDecodeBounds_Mode == mode) { |
231 return true; | 301 return true; |
232 } | 302 } |
233 | 303 |
234 SavedImage* image = &gif->SavedImages[gif->ImageCount-1]; | |
235 const GifImageDesc& desc = image->ImageDesc; | |
236 | |
237 // check for valid descriptor | |
238 if ( (desc.Top | desc.Left) < 0 || | |
239 desc.Left + desc.Width > width || | |
240 desc.Top + desc.Height > height) { | |
241 return error_return(gif, *bm, "TopLeft"); | |
242 } | |
243 | 304 |
244 // now we decode the colortable | 305 // now we decode the colortable |
245 int colorCount = 0; | 306 int colorCount = 0; |
246 { | 307 { |
308 SkAutoTMalloc<SkPMColor> colorStorage; // declare here for scop e. | |
scroggo
2013/10/09 20:12:03
Mike's patch (https://codereview.chromium.org/2657
hal.canary
2013/10/10 16:22:11
That's a good idea. 1kb on the stack is a lot che
| |
247 const ColorMapObject* cmap = find_colormap(gif); | 309 const ColorMapObject* cmap = find_colormap(gif); |
248 if (NULL == cmap) { | 310 if (cmap != NULL) { |
249 return error_return(gif, *bm, "null cmap"); | 311 colorCount = cmap->ColorCount; |
312 colorStorage.reset(colorCount); | |
313 for (int index = 0; index < colorCount; index++) { | |
314 colorStorage[index] = SkPackARGB32(0xFF, | |
315 cmap->Colors[index].R ed, | |
316 cmap->Colors[index].G reen, | |
317 cmap->Colors[index].B lue); | |
318 } | |
319 } else { | |
320 // find_colormap() returned NULL. Some GIFs don't | |
321 // have a color table, so we force one. | |
322 gif_warning(gif, *bm, "missing colormap"); | |
323 colorCount = 256; | |
324 colorStorage.reset(colorCount); | |
325 for (int i = 0; i < colorCount; ++i) { | |
326 colorStorage[i] = SK_ColorWHITE; | |
scroggo
2013/10/09 20:12:03
Why did you pick white? I thought you said this ha
hal.canary
2013/10/10 16:22:11
In every example I saw, the only index used was th
| |
327 } | |
250 } | 328 } |
251 | |
252 colorCount = cmap->ColorCount; | |
253 SkAutoTMalloc<SkPMColor> colorStorage(colorCount); | |
254 SkPMColor* colorPtr = colorStorage.get(); | |
255 for (int index = 0; index < colorCount; index++) { | |
256 colorPtr[index] = SkPackARGB32(0xFF, | |
257 cmap->Colors[index].Red, | |
258 cmap->Colors[index].Green, | |
259 cmap->Colors[index].Blue); | |
260 } | |
261 | |
262 transpIndex = find_transpIndex(temp_save, colorCount); | 329 transpIndex = find_transpIndex(temp_save, colorCount); |
263 bool reallyHasAlpha = transpIndex >= 0; | 330 bool reallyHasAlpha = transpIndex >= 0; |
264 if (reallyHasAlpha) { | 331 if (reallyHasAlpha) { |
265 colorPtr[transpIndex] = SK_ColorTRANSPARENT; // ram in a tra nsparent SkPMColor | 332 // ram in a transparent SkPMColor |
333 colorStorage[transpIndex] = SK_ColorTRANSPARENT; | |
266 } | 334 } |
267 | 335 SkAutoTUnref<SkColorTable> ctable(SkNEW_ARGS(SkColorTable, |
268 SkAutoTUnref<SkColorTable> ctable(SkNEW_ARGS(SkColorTable, (colo rPtr, colorCount))); | 336 (colorStorage.get() , colorCount))); |
269 ctable->setIsOpaque(!reallyHasAlpha); | 337 ctable->setIsOpaque(!reallyHasAlpha); |
270 if (!this->allocPixelRef(bm, ctable)) { | 338 if (!this->allocPixelRef(bm, ctable)) { |
271 return error_return(gif, *bm, "allocPixelRef"); | 339 return error_return(gif, *bm, "allocPixelRef"); |
272 } | 340 } |
273 } | 341 } |
274 | 342 |
275 const int innerWidth = desc.Width; | |
276 const int innerHeight = desc.Height; | |
277 | |
278 // abort if either inner dimension is <= 0 | 343 // abort if either inner dimension is <= 0 |
279 if (innerWidth <= 0 || innerHeight <= 0) { | 344 if (innerWidth <= 0 || innerHeight <= 0) { |
280 return error_return(gif, *bm, "non-pos inner width/height"); | 345 return error_return(gif, *bm, "non-pos inner width/height"); |
281 } | 346 } |
282 | 347 |
283 SkAutoLockPixels alp(*bm); | 348 SkAutoLockPixels alp(*bm); |
284 | 349 |
285 SkAutoMalloc storage(innerWidth); | 350 SkAutoMalloc storage(innerWidth); |
286 uint8_t* scanline = (uint8_t*) storage.get(); | 351 uint8_t* scanline = (uint8_t*) storage.get(); |
287 | 352 |
288 // GIF has an option to store the scanlines of an image, plus a larg er background, | 353 // GIF has an option to store the scanlines of an image, plus a larg er background, |
289 // filled by a fill color. In this case, we will use a subset of the larger bitmap | 354 // filled by a fill color. In this case, we will use a subset of the larger bitmap |
290 // for sampling. | 355 // for sampling. |
291 SkBitmap subset; | 356 SkBitmap subset; |
292 SkBitmap* workingBitmap; | 357 SkBitmap* workingBitmap; |
293 // are we only a subset of the total bounds? | 358 // are we only a subset of the total bounds? |
294 if ((desc.Top | desc.Left) > 0 || | 359 if ((imageTop | imageLeft) > 0 || |
295 innerWidth < width || innerHeight < height) { | 360 innerWidth < width || innerHeight < height) { |
296 int fill; | 361 int fill = get_fill_index(transpIndex, colorCount, *gif); |
297 if (transpIndex >= 0) { | |
298 fill = transpIndex; | |
299 } else { | |
300 fill = gif->SBackGroundColor; | |
301 } | |
302 // check for valid fill index/color | |
303 if (static_cast<unsigned>(fill) >= | |
304 static_cast<unsigned>(colorCount)) { | |
305 fill = 0; | |
306 } | |
307 // Fill the background. | 362 // Fill the background. |
308 memset(bm->getPixels(), fill, bm->getSize()); | 363 memset(bm->getPixels(), fill, bm->getSize()); |
309 | 364 |
310 // Create a subset of the bitmap. | 365 // Create a subset of the bitmap. |
311 SkIRect subsetRect(SkIRect::MakeXYWH(desc.Left / sampler.srcDX() , | 366 SkIRect subsetRect(SkIRect::MakeXYWH(imageLeft / sampler.srcDX() , |
312 desc.Top / sampler.srcDY(), | 367 imageTop / sampler.srcDY(), |
313 innerWidth / sampler.srcDX( ), | 368 innerWidth / sampler.srcDX( ), |
314 innerHeight / sampler.srcDY ())); | 369 innerHeight / sampler.srcDY ())); |
315 if (!bm->extractSubset(&subset, subsetRect)) { | 370 if (!bm->extractSubset(&subset, subsetRect)) { |
316 return error_return(gif, *bm, "Extract failed."); | 371 return error_return(gif, *bm, "Extract failed."); |
317 } | 372 } |
318 // Update the sampler. We'll now be only sampling into the subse t. | 373 // Update the sampler. We'll now be only sampling into the subse t. |
319 sampler = SkScaledBitmapSampler(innerWidth, innerHeight, this->g etSampleSize()); | 374 sampler = SkScaledBitmapSampler(innerWidth, innerHeight, this->g etSampleSize()); |
320 workingBitmap = ⊂ | 375 workingBitmap = ⊂ |
321 } else { | 376 } else { |
322 workingBitmap = bm; | 377 workingBitmap = bm; |
323 } | 378 } |
324 | 379 |
325 // bm is already locked, but if we had to take a subset, it must be locked also, | 380 // bm is already locked, but if we had to take a subset, it must be locked also, |
326 // so that getPixels() will point to its pixels. | 381 // so that getPixels() will point to its pixels. |
327 SkAutoLockPixels alpWorking(*workingBitmap); | 382 SkAutoLockPixels alpWorking(*workingBitmap); |
328 | 383 |
329 if (!sampler.begin(workingBitmap, SkScaledBitmapSampler::kIndex, *th is)) { | 384 if (!sampler.begin(workingBitmap, SkScaledBitmapSampler::kIndex, *th is)) { |
330 return error_return(gif, *bm, "Sampler failed to begin."); | 385 return error_return(gif, *bm, "Sampler failed to begin."); |
331 } | 386 } |
332 | 387 |
333 // now decode each scanline | 388 // now decode each scanline |
334 if (gif->Image.Interlace) { | 389 if (gif->Image.Interlace) { |
335 // Iterate over the height of the source data. The sampler will | 390 // Iterate over the height of the source data. The sampler will |
336 // take care of skipping unneeded rows. | 391 // take care of skipping unneeded rows. |
337 GifInterlaceIter iter(innerHeight); | 392 GifInterlaceIter iter(innerHeight); |
338 for (int y = 0; y < innerHeight; y++){ | 393 for (int y = 0; y < innerHeight; y++) { |
339 if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) { | 394 if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) { |
340 return error_return(gif, *bm, "interlace DGifGetLine"); | 395 gif_warning(gif, *bm, "interlace DGifGetLine"); |
396 int fill = get_fill_index(transpIndex, colorCount, *gif) ; | |
scroggo
2013/10/09 20:12:03
Maybe this suggestion introduces complexity withou
hal.canary
2013/10/10 16:22:11
But we aren't guaranteed to have done that.
| |
397 for (; y < innerHeight; y++) { | |
398 memset(scanline, fill, innerWidth); | |
scroggo
2013/10/09 20:12:03
This can be done once outside the loop. (sampleInt
hal.canary
2013/10/10 16:22:11
good catch.
| |
399 sampler.sampleInterlaced(scanline, iter.currY()); | |
400 iter.next(); | |
401 } | |
402 return true; | |
scroggo
2013/10/09 20:12:03
Should we say 'goto DONE;' to fit with the surroun
hal.canary
2013/10/10 16:22:11
Since there is no cleanup code, let's just get rid
| |
341 } | 403 } |
342 sampler.sampleInterlaced(scanline, iter.currY()); | 404 sampler.sampleInterlaced(scanline, iter.currY()); |
343 iter.next(); | 405 iter.next(); |
344 } | 406 } |
345 } else { | 407 } else { |
346 // easy, non-interlace case | 408 // easy, non-interlace case |
409 bool getLineErrorState = false; | |
410 int fill = 0; | |
347 const int outHeight = workingBitmap->height(); | 411 const int outHeight = workingBitmap->height(); |
348 skip_src_rows(gif, scanline, innerWidth, sampler.srcY0()); | 412 skip_src_rows(gif, scanline, innerWidth, sampler.srcY0()); |
349 for (int y = 0; y < outHeight; y++) { | 413 for (int y = 0; y < outHeight; y++) { |
350 if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) { | 414 if (!getLineErrorState) { |
scroggo
2013/10/09 20:12:03
This is a little complicated to follow. Why not fo
hal.canary
2013/10/10 16:22:11
I'll change it.
| |
351 return error_return(gif, *bm, "DGifGetLine"); | 415 if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) { |
416 getLineErrorState = true; | |
417 gif_warning(gif, *bm, "DGifGetLine"); | |
418 fill = get_fill_index(transpIndex, colorCount, *gif) ; | |
419 memset(scanline, fill, innerWidth); | |
420 } | |
421 } else { | |
422 memset(scanline, fill, innerWidth); | |
scroggo
2013/10/09 20:12:03
This step is unnecessary for each line past the fi
hal.canary
2013/10/10 16:22:11
I'll change it.
| |
352 } | 423 } |
353 // scanline now contains the raw data. Sample it. | 424 // scanline now contains the raw data. Sample it. |
354 sampler.next(scanline); | 425 sampler.next(scanline); |
355 if (y < outHeight - 1) { | 426 if (y < outHeight - 1) { |
356 skip_src_rows(gif, scanline, innerWidth, sampler.srcDY() - 1); | 427 skip_src_rows(gif, scanline, innerWidth, sampler.srcDY() - 1); |
scroggo
2013/10/09 20:12:03
If getLineErrorState is true, both this and the ne
hal.canary
2013/10/10 16:22:11
I'll change it.
| |
357 } | 428 } |
358 } | 429 } |
359 // skip the rest of the rows (if any) | 430 // skip the rest of the rows (if any) |
360 int read = (outHeight - 1) * sampler.srcDY() + sampler.srcY0() + 1; | 431 int read = (outHeight - 1) * sampler.srcDY() + sampler.srcY0() + 1; |
361 SkASSERT(read <= innerHeight); | 432 SkASSERT(read <= innerHeight); |
362 skip_src_rows(gif, scanline, innerWidth, innerHeight - read); | 433 skip_src_rows(gif, scanline, innerWidth, innerHeight - read); |
363 } | 434 } |
364 goto DONE; | 435 goto DONE; |
365 } break; | 436 } break; |
366 | 437 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
435 static SkImageDecoder_DecodeReg gReg(sk_libgif_dfactory); | 506 static SkImageDecoder_DecodeReg gReg(sk_libgif_dfactory); |
436 | 507 |
437 static SkImageDecoder::Format get_format_gif(SkStreamRewindable* stream) { | 508 static SkImageDecoder::Format get_format_gif(SkStreamRewindable* stream) { |
438 if (is_gif(stream)) { | 509 if (is_gif(stream)) { |
439 return SkImageDecoder::kGIF_Format; | 510 return SkImageDecoder::kGIF_Format; |
440 } | 511 } |
441 return SkImageDecoder::kUnknown_Format; | 512 return SkImageDecoder::kUnknown_Format; |
442 } | 513 } |
443 | 514 |
444 static SkImageDecoder_FormatReg gFormatReg(get_format_gif); | 515 static SkImageDecoder_FormatReg gFormatReg(get_format_gif); |
OLD | NEW |