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 |