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" |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 // Use maximum unsigned int (surely an invalid index) to indicate that a val
id | 93 // Use maximum unsigned int (surely an invalid index) to indicate that a val
id |
94 // index was not found. | 94 // index was not found. |
95 return SK_MaxU32; | 95 return SK_MaxU32; |
96 } | 96 } |
97 | 97 |
98 /* | 98 /* |
99 * This function cleans up the gif object after the decode completes | 99 * This function cleans up the gif object after the decode completes |
100 * It is used in a SkAutoTCallIProc template | 100 * It is used in a SkAutoTCallIProc template |
101 */ | 101 */ |
102 void SkGifCodec::CloseGif(GifFileType* gif) { | 102 void SkGifCodec::CloseGif(GifFileType* gif) { |
103 DGifCloseFile(gif, NULL); | 103 DGifCloseFile(gif, nullptr); |
104 } | 104 } |
105 | 105 |
106 /* | 106 /* |
107 * This function free extension data that has been saved to assist the image | 107 * This function free extension data that has been saved to assist the image |
108 * decoder | 108 * decoder |
109 */ | 109 */ |
110 void SkGifCodec::FreeExtension(SavedImage* image) { | 110 void SkGifCodec::FreeExtension(SavedImage* image) { |
111 if (NULL != image->ExtensionBlocks) { | 111 if (nullptr != image->ExtensionBlocks) { |
112 GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks); | 112 GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks); |
113 } | 113 } |
114 } | 114 } |
115 | 115 |
116 /* | 116 /* |
117 * Read enough of the stream to initialize the SkGifCodec. | 117 * Read enough of the stream to initialize the SkGifCodec. |
118 * Returns a bool representing success or failure. | 118 * Returns a bool representing success or failure. |
119 * | 119 * |
120 * @param codecOut | 120 * @param codecOut |
121 * If it returned true, and codecOut was not nullptr, | 121 * If it returned true, and codecOut was not nullptr, |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 , fGif(gif) | 213 , fGif(gif) |
214 , fSrcBuffer(new uint8_t[this->getInfo().width()]) | 214 , fSrcBuffer(new uint8_t[this->getInfo().width()]) |
215 // If it is valid, fTransIndex will be used to set fFillIndex. We don't kno
w if | 215 // If it is valid, fTransIndex will be used to set fFillIndex. We don't kno
w if |
216 // fTransIndex is valid until we process the color table, since fTransIndex
may | 216 // fTransIndex is valid until we process the color table, since fTransIndex
may |
217 // be greater than the size of the color table. | 217 // be greater than the size of the color table. |
218 , fTransIndex(transIndex) | 218 , fTransIndex(transIndex) |
219 // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid,
or if | 219 // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid,
or if |
220 // there is a valid background color. | 220 // there is a valid background color. |
221 , fFillIndex(0) | 221 , fFillIndex(0) |
222 , fFrameRect(frameRect) | 222 , fFrameRect(frameRect) |
223 , fFrameIsSubset(frameIsSubset) | 223 , fFrameIsSubset(false) |
224 , fColorTable(NULL) | 224 , fColorTable(nullptr) |
225 , fSwizzler(NULL) | 225 , fSwizzler(nullptr) |
226 {} | 226 {} |
227 | 227 |
228 bool SkGifCodec::onRewind() { | 228 bool SkGifCodec::onRewind() { |
229 GifFileType* gifOut = nullptr; | 229 GifFileType* gifOut = nullptr; |
230 if (!ReadHeader(this->stream(), nullptr, &gifOut)) { | 230 if (!ReadHeader(this->stream(), nullptr, &gifOut)) { |
231 return false; | 231 return false; |
232 } | 232 } |
233 | 233 |
234 SkASSERT(nullptr != gifOut); | 234 SkASSERT(nullptr != gifOut); |
235 fGif.reset(gifOut); | 235 fGif.reset(gifOut); |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 frameRect->setXYWH(frameLeft, frameTop, frameWidth, frameHeight); | 348 frameRect->setXYWH(frameLeft, frameTop, frameWidth, frameHeight); |
349 size->set(width, height); | 349 size->set(width, height); |
350 return true; | 350 return true; |
351 } | 351 } |
352 | 352 |
353 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp
utColorPtr, | 353 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp
utColorPtr, |
354 int* inputColorCount) { | 354 int* inputColorCount) { |
355 // Set up our own color table | 355 // Set up our own color table |
356 const uint32_t maxColors = 256; | 356 const uint32_t maxColors = 256; |
357 SkPMColor colorPtr[256]; | 357 SkPMColor colorPtr[256]; |
358 if (NULL != inputColorCount) { | 358 if (nullptr != inputColorCount) { |
359 // We set the number of colors to maxColors in order to ensure | 359 // We set the number of colors to maxColors in order to ensure |
360 // safe memory accesses. Otherwise, an invalid pixel could | 360 // safe memory accesses. Otherwise, an invalid pixel could |
361 // access memory outside of our color table array. | 361 // access memory outside of our color table array. |
362 *inputColorCount = maxColors; | 362 *inputColorCount = maxColors; |
363 } | 363 } |
364 | 364 |
365 // Get local color table | 365 // Get local color table |
366 ColorMapObject* colorMap = fGif->Image.ColorMap; | 366 ColorMapObject* colorMap = fGif->Image.ColorMap; |
367 // If there is no local color table, use the global color table | 367 // If there is no local color table, use the global color table |
368 if (NULL == colorMap) { | 368 if (nullptr == colorMap) { |
369 colorMap = fGif->SColorMap; | 369 colorMap = fGif->SColorMap; |
370 } | 370 } |
371 | 371 |
372 uint32_t colorCount = 0; | 372 uint32_t colorCount = 0; |
373 if (NULL != colorMap) { | 373 if (nullptr != colorMap) { |
374 colorCount = colorMap->ColorCount; | 374 colorCount = colorMap->ColorCount; |
375 // giflib guarantees these properties | 375 // giflib guarantees these properties |
376 SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel))); | 376 SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel))); |
377 SkASSERT(colorCount <= 256); | 377 SkASSERT(colorCount <= 256); |
378 for (uint32_t i = 0; i < colorCount; i++) { | 378 for (uint32_t i = 0; i < colorCount; i++) { |
379 colorPtr[i] = SkPackARGB32(0xFF, colorMap->Colors[i].Red, | 379 colorPtr[i] = SkPackARGB32(0xFF, colorMap->Colors[i].Red, |
380 colorMap->Colors[i].Green, colorMap->Colors[i].Blue); | 380 colorMap->Colors[i].Green, colorMap->Colors[i].Blue); |
381 } | 381 } |
382 } | 382 } |
383 | 383 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 return gif_error("Cannot convert input type to output type.\n", | 418 return gif_error("Cannot convert input type to output type.\n", |
419 kInvalidConversion); | 419 kInvalidConversion); |
420 } | 420 } |
421 | 421 |
422 // Initialize color table and copy to the client if necessary | 422 // Initialize color table and copy to the client if necessary |
423 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); | 423 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); |
424 return kSuccess; | 424 return kSuccess; |
425 } | 425 } |
426 | 426 |
427 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, | 427 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, |
428 ZeroInitialized zeroInit) { | 428 ZeroInitialized zeroInit, int subsetLeft, int subsetWidth) { |
429 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 429 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
430 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, | 430 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, colorPtr, dst
Info, zeroInit, |
431 colorPtr, dstInfo, zeroInit)); | 431 subsetLeft, subsetWidth)); |
432 if (nullptr != fSwizzler.get()) { | 432 if (nullptr != fSwizzler.get()) { |
433 return kSuccess; | 433 return kSuccess; |
434 } | 434 } |
435 return kUnimplemented; | 435 return kUnimplemented; |
436 } | 436 } |
437 | 437 |
438 bool SkGifCodec::readRow() { | 438 bool SkGifCodec::readRow() { |
439 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width()); | 439 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width()); |
440 } | 440 } |
441 | 441 |
(...skipping 11 matching lines...) Expand all Loading... |
453 return result; | 453 return result; |
454 } | 454 } |
455 | 455 |
456 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 456 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
457 return gif_error("Scaling not supported.\n", kInvalidScale); | 457 return gif_error("Scaling not supported.\n", kInvalidScale); |
458 } | 458 } |
459 | 459 |
460 // Initialize the swizzler | 460 // Initialize the swizzler |
461 if (fFrameIsSubset) { | 461 if (fFrameIsSubset) { |
462 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); | 462 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); |
463 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 463 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized, 0, |
| 464 fFrameRect.width())) { |
464 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 465 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
465 } | 466 } |
466 | 467 |
467 // Fill the background | 468 // Fill the background |
468 fSwizzler->fill(dst, dstInfo.colorType(), dstInfo.height(), dstRowBytes, | 469 fSwizzler->fill(dst, dstInfo.colorType(), dstInfo.height(), dstRowBytes, |
469 this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()), | 470 this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()), |
470 opts.fZeroInitialized); | 471 opts.fZeroInitialized); |
471 | 472 |
472 // Modify the dst pointer | 473 // Modify the dst pointer |
473 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); | 474 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); |
474 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + | 475 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + |
475 dstBytesPerPixel * fFrameRect.left()); | 476 dstBytesPerPixel * fFrameRect.left()); |
476 } else { | 477 } else { |
477 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 478 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized,
0, |
| 479 dstInfo.width())) { |
478 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 480 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
479 } | 481 } |
480 } | 482 } |
481 | 483 |
482 // Iterate over rows of the input | 484 // Iterate over rows of the input |
483 uint32_t width = fFrameRect.width(); | 485 uint32_t width = fFrameRect.width(); |
484 uint32_t height = fFrameRect.height(); | 486 uint32_t height = fFrameRect.height(); |
485 for (uint32_t y = 0; y < height; y++) { | 487 for (uint32_t y = 0; y < height; y++) { |
486 if (!this->readRow()) { | 488 if (!this->readRow()) { |
487 *rowsDecoded = y; | 489 *rowsDecoded = y; |
488 return gif_error("Could not decode line.\n", kIncompleteInput); | 490 return gif_error("Could not decode line.\n", kIncompleteInput); |
489 } | 491 } |
490 void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * this->outputScanlin
e(y)); | 492 void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * this->outputScanlin
e(y)); |
491 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 493 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); |
492 } | 494 } |
493 return kSuccess; | 495 return kSuccess; |
494 } | 496 } |
495 | 497 |
496 uint32_t SkGifCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType
) const { | 498 uint32_t SkGifCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType
) const { |
497 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 499 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
498 return get_color_table_fill_value(colorType, colorPtr, fFillIndex); | 500 return get_color_table_fill_value(colorType, colorPtr, fFillIndex); |
499 } | 501 } |
500 | 502 |
501 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, | 503 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, |
502 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { | 504 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count, |
| 505 int subsetLeft, int subsetWidth) { |
503 | 506 |
504 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, this->options()); | 507 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, this->options()); |
505 if (kSuccess != result) { | 508 if (kSuccess != result) { |
506 return result; | 509 return result; |
507 } | 510 } |
508 | 511 |
509 // Initialize the swizzler | 512 // Initialize the swizzler |
510 if (fFrameIsSubset) { | 513 if (fFrameIsSubset) { |
511 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); | 514 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); |
512 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 515 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized, subsetLeft, |
| 516 subsetWidth)) { |
513 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 517 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
514 } | 518 } |
515 } else { | 519 } else { |
516 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 520 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized,
subsetLeft, |
| 521 subsetWidth)) { |
517 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 522 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
518 } | 523 } |
519 } | 524 } |
520 | 525 |
521 return kSuccess; | 526 return kSuccess; |
522 } | 527 } |
523 | 528 |
524 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { | 529 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { |
525 int rowsBeforeFrame = 0; | 530 int rowsBeforeFrame = 0; |
526 int rowsAfterFrame = 0; | 531 int rowsAfterFrame = 0; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
566 | 571 |
567 int SkGifCodec::onOutputScanline(int inputScanline) const { | 572 int SkGifCodec::onOutputScanline(int inputScanline) const { |
568 if (fGif->Image.Interlace) { | 573 if (fGif->Image.Interlace) { |
569 if (inputScanline < fFrameRect.top() || inputScanline >= fFrameRect.bott
om()) { | 574 if (inputScanline < fFrameRect.top() || inputScanline >= fFrameRect.bott
om()) { |
570 return inputScanline; | 575 return inputScanline; |
571 } | 576 } |
572 return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFram
eRect.height()); | 577 return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFram
eRect.height()); |
573 } | 578 } |
574 return inputScanline; | 579 return inputScanline; |
575 } | 580 } |
OLD | NEW |