Chromium Code Reviews| 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 |