| 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 |