| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 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 #include "SkCodec_libgif.h" | 8 #include "SkCodec_libgif.h" |
| 9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| 11 #include "SkColorTable.h" | 11 #include "SkColorTable.h" |
| 12 #include "SkGifInterlaceIter.h" | |
| 13 #include "SkStream.h" | 12 #include "SkStream.h" |
| 14 #include "SkSwizzler.h" | 13 #include "SkSwizzler.h" |
| 15 #include "SkUtils.h" | 14 #include "SkUtils.h" |
| 16 | 15 |
| 17 /* | 16 /* |
| 18 * Checks the start of the stream to see if the image is a gif | 17 * Checks the start of the stream to see if the image is a gif |
| 19 */ | 18 */ |
| 20 bool SkGifCodec::IsGif(SkStream* stream) { | 19 bool SkGifCodec::IsGif(SkStream* stream) { |
| 21 char buf[GIF_STAMP_LEN]; | 20 char buf[GIF_STAMP_LEN]; |
| 22 if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) { | 21 if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 // There should only be one graphics control extension for the image
frame | 108 // There should only be one graphics control extension for the image
frame |
| 110 break; | 109 break; |
| 111 } | 110 } |
| 112 } | 111 } |
| 113 | 112 |
| 114 // Use maximum unsigned int (surely an invalid index) to indicate that a val
id | 113 // Use maximum unsigned int (surely an invalid index) to indicate that a val
id |
| 115 // index was not found. | 114 // index was not found. |
| 116 return SK_MaxU32; | 115 return SK_MaxU32; |
| 117 } | 116 } |
| 118 | 117 |
| 118 static inline uint32_t ceil_div(uint32_t a, uint32_t b) { |
| 119 return (a + b - 1) / b; |
| 120 } |
| 121 |
| 122 /* |
| 123 * Gets the output row corresponding to the encoded row for interlaced gifs |
| 124 */ |
| 125 static uint32_t get_output_row_interlaced(uint32_t encodedRow, uint32_t height)
{ |
| 126 SkASSERT(encodedRow < height); |
| 127 // First pass |
| 128 if (encodedRow * 8 < height) { |
| 129 return encodedRow * 8; |
| 130 } |
| 131 // Second pass |
| 132 if (encodedRow * 4 < height) { |
| 133 return 4 + 8 * (encodedRow - ceil_div(height, 8)); |
| 134 } |
| 135 // Third pass |
| 136 if (encodedRow * 2 < height) { |
| 137 return 2 + 4 * (encodedRow - ceil_div(height, 4)); |
| 138 } |
| 139 // Fourth pass |
| 140 return 1 + 2 * (encodedRow - ceil_div(height, 2)); |
| 141 } |
| 142 |
| 119 /* | 143 /* |
| 120 * Read enough of the stream to initialize the SkGifCodec. | 144 * Read enough of the stream to initialize the SkGifCodec. |
| 121 * Returns a bool representing success or failure. | 145 * Returns a bool representing success or failure. |
| 122 * | 146 * |
| 123 * @param codecOut | 147 * @param codecOut |
| 124 * If it returned true, and codecOut was not nullptr, | 148 * If it returned true, and codecOut was not nullptr, |
| 125 * codecOut will be set to a new SkGifCodec. | 149 * codecOut will be set to a new SkGifCodec. |
| 126 * | 150 * |
| 127 * @param gifOut | 151 * @param gifOut |
| 128 * If it returned true, and codecOut was nullptr, | 152 * If it returned true, and codecOut was nullptr, |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 swizzler.reset(SkSwizzler::CreateSwizzler( | 426 swizzler.reset(SkSwizzler::CreateSwizzler( |
| 403 SkSwizzler::kIndex, colorTable, dstInfo, | 427 SkSwizzler::kIndex, colorTable, dstInfo, |
| 404 zeroInit, this->getInfo())); | 428 zeroInit, this->getInfo())); |
| 405 } | 429 } |
| 406 | 430 |
| 407 // Stores output from dgiflib and input to the swizzler | 431 // Stores output from dgiflib and input to the swizzler |
| 408 SkAutoTDeleteArray<uint8_t> buffer(new uint8_t[innerWidth]); | 432 SkAutoTDeleteArray<uint8_t> buffer(new uint8_t[innerWidth]); |
| 409 | 433 |
| 410 // Check the interlace flag and iterate over rows of the input | 434 // Check the interlace flag and iterate over rows of the input |
| 411 if (fGif->Image.Interlace) { | 435 if (fGif->Image.Interlace) { |
| 412 // In interlace mode, the rows of input are rearranged in | |
| 413 // the output image. We use an iterator to take care of | |
| 414 // the rearranging. | |
| 415 SkGifInterlaceIter iter(innerHeight); | |
| 416 for (int32_t y = 0; y < innerHeight; y++) { | 436 for (int32_t y = 0; y < innerHeight; y++) { |
| 417 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), innerWi
dth)) { | 437 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), innerWi
dth)) { |
| 418 // Recover from error by filling remainder of image | 438 // Recover from error by filling remainder of image |
| 419 if (!skipBackground) { | 439 if (!skipBackground) { |
| 420 memset(buffer.get(), fillIndex, innerWidth); | 440 memset(buffer.get(), fillIndex, innerWidth); |
| 421 for (; y < innerHeight; y++) { | 441 for (; y < innerHeight; y++) { |
| 422 void* dstRow = SkTAddOffset<void>(dst, | 442 void* dstRow = SkTAddOffset<void>(dst, dstRo
wBytes * |
| 423 dstRowByte
s * iter.nextY()); | 443 get_output_row_interlaced(y, innerHe
ight)); |
| 424 swizzler->swizzle(dstRow, buffer.get()); | 444 swizzler->swizzle(dstRow, buffer.get()); |
| 425 } | 445 } |
| 426 } | 446 } |
| 427 return gif_error(SkStringPrintf( | 447 return gif_error(SkStringPrintf( |
| 428 "Could not decode line %d of %d.\n", | 448 "Could not decode line %d of %d.\n", |
| 429 y, height - 1).c_str(), kIncompleteInput); | 449 y, height - 1).c_str(), kIncompleteInput); |
| 430 } | 450 } |
| 431 void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * ite
r.nextY()); | 451 void* dstRow = SkTAddOffset<void>(dst, |
| 452 dstRowBytes * get_output_row_interlaced(y, inner
Height)); |
| 432 swizzler->swizzle(dstRow, buffer.get()); | 453 swizzler->swizzle(dstRow, buffer.get()); |
| 433 } | 454 } |
| 434 } else { | 455 } else { |
| 435 // Standard mode | 456 // Standard mode |
| 436 void* dstRow = dst; | 457 void* dstRow = dst; |
| 437 for (int32_t y = 0; y < innerHeight; y++) { | 458 for (int32_t y = 0; y < innerHeight; y++) { |
| 438 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), innerWi
dth)) { | 459 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), innerWi
dth)) { |
| 439 if (!skipBackground) { | 460 if (!skipBackground) { |
| 440 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes, | 461 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes, |
| 441 innerHeight - y, fillIndex, col
orTable); | 462 innerHeight - y, fillIndex, col
orTable); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 504 default: | 525 default: |
| 505 // giflib returns an error code if the record type is not known. | 526 // giflib returns an error code if the record type is not known. |
| 506 // We should catch this error immediately. | 527 // We should catch this error immediately. |
| 507 SkASSERT(false); | 528 SkASSERT(false); |
| 508 break; | 529 break; |
| 509 } | 530 } |
| 510 } while (TERMINATE_RECORD_TYPE != recordType); | 531 } while (TERMINATE_RECORD_TYPE != recordType); |
| 511 | 532 |
| 512 return gif_error("Could not find any images to decode in gif file.\n", kInva
lidInput); | 533 return gif_error("Could not find any images to decode in gif file.\n", kInva
lidInput); |
| 513 } | 534 } |
| OLD | NEW |