| 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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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(frameIsSubset) |
| 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 19 matching lines...) Expand all Loading... |
| 403 colorPtr[i] = colorPtr[fFillIndex]; | 403 colorPtr[i] = colorPtr[fFillIndex]; |
| 404 } | 404 } |
| 405 | 405 |
| 406 fColorTable.reset(new SkColorTable(colorPtr, maxColors)); | 406 fColorTable.reset(new SkColorTable(colorPtr, maxColors)); |
| 407 copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount)
; | 407 copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount)
; |
| 408 } | 408 } |
| 409 | 409 |
| 410 SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColo
r* inputColorPtr, | 410 SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColo
r* inputColorPtr, |
| 411 int* inputColorCount, const Options& opts) { | 411 int* inputColorCount, const Options& opts) { |
| 412 // Check for valid input parameters | 412 // Check for valid input parameters |
| 413 if (opts.fSubset) { | |
| 414 // Subsets are not supported. | |
| 415 return kUnimplemented; | |
| 416 } | |
| 417 if (!conversion_possible(dstInfo, this->getInfo())) { | 413 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 418 return gif_error("Cannot convert input type to output type.\n", | 414 return gif_error("Cannot convert input type to output type.\n", |
| 419 kInvalidConversion); | 415 kInvalidConversion); |
| 420 } | 416 } |
| 421 | 417 |
| 422 // Initialize color table and copy to the client if necessary | 418 // Initialize color table and copy to the client if necessary |
| 423 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); | 419 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); |
| 424 return kSuccess; | 420 return kSuccess; |
| 425 } | 421 } |
| 426 | 422 |
| 427 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, | 423 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, const
Options& opts) { |
| 428 ZeroInitialized zeroInit) { | |
| 429 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 424 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
| 430 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, | 425 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, colorPtr, dst
Info, opts)); |
| 431 colorPtr, dstInfo, zeroInit)); | |
| 432 if (nullptr != fSwizzler.get()) { | 426 if (nullptr != fSwizzler.get()) { |
| 433 return kSuccess; | 427 return kSuccess; |
| 434 } | 428 } |
| 435 return kUnimplemented; | 429 return kUnimplemented; |
| 436 } | 430 } |
| 437 | 431 |
| 438 bool SkGifCodec::readRow() { | 432 bool SkGifCodec::readRow() { |
| 439 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width()); | 433 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width()); |
| 440 } | 434 } |
| 441 | 435 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 453 return result; | 447 return result; |
| 454 } | 448 } |
| 455 | 449 |
| 456 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 450 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 457 return gif_error("Scaling not supported.\n", kInvalidScale); | 451 return gif_error("Scaling not supported.\n", kInvalidScale); |
| 458 } | 452 } |
| 459 | 453 |
| 460 // Initialize the swizzler | 454 // Initialize the swizzler |
| 461 if (fFrameIsSubset) { | 455 if (fFrameIsSubset) { |
| 462 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); | 456 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); |
| 463 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 457 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) { |
| 464 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 458 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
| 465 } | 459 } |
| 466 | 460 |
| 467 // Fill the background | 461 // Fill the background |
| 468 SkSampler::Fill(dst, dstInfo, dstRowBytes, | 462 SkSampler::Fill(dst, dstInfo, dstRowBytes, |
| 469 this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()), | 463 this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()), |
| 470 opts.fZeroInitialized); | 464 opts.fZeroInitialized); |
| 471 | 465 |
| 472 // Modify the dst pointer | 466 // Modify the dst pointer |
| 473 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); | 467 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); |
| 474 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + | 468 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + |
| 475 dstBytesPerPixel * fFrameRect.left()); | 469 dstBytesPerPixel * fFrameRect.left()); |
| 476 } else { | 470 } else { |
| 477 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 471 if (kSuccess != this->initializeSwizzler(dstInfo, opts)) { |
| 478 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 472 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
| 479 } | 473 } |
| 480 } | 474 } |
| 481 | 475 |
| 482 // Iterate over rows of the input | 476 // Iterate over rows of the input |
| 483 uint32_t width = fFrameRect.width(); | 477 uint32_t width = fFrameRect.width(); |
| 484 uint32_t height = fFrameRect.height(); | 478 uint32_t height = fFrameRect.height(); |
| 485 for (uint32_t y = 0; y < height; y++) { | 479 for (uint32_t y = 0; y < height; y++) { |
| 486 if (!this->readRow()) { | 480 if (!this->readRow()) { |
| 487 *rowsDecoded = y; | 481 *rowsDecoded = y; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 502 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { | 496 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { |
| 503 | 497 |
| 504 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, this->options()); | 498 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, this->options()); |
| 505 if (kSuccess != result) { | 499 if (kSuccess != result) { |
| 506 return result; | 500 return result; |
| 507 } | 501 } |
| 508 | 502 |
| 509 // Initialize the swizzler | 503 // Initialize the swizzler |
| 510 if (fFrameIsSubset) { | 504 if (fFrameIsSubset) { |
| 511 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); | 505 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); |
| 512 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 506 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) { |
| 513 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 507 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
| 514 } | 508 } |
| 515 } else { | 509 } else { |
| 516 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 510 if (kSuccess != this->initializeSwizzler(dstInfo, opts)) { |
| 517 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 511 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
| 518 } | 512 } |
| 519 } | 513 } |
| 520 | 514 |
| 521 return kSuccess; | 515 return kSuccess; |
| 522 } | 516 } |
| 523 | 517 |
| 524 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { | 518 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { |
| 525 int rowsBeforeFrame = 0; | 519 int rowsBeforeFrame = 0; |
| 526 int rowsAfterFrame = 0; | 520 int rowsAfterFrame = 0; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 566 | 560 |
| 567 int SkGifCodec::onOutputScanline(int inputScanline) const { | 561 int SkGifCodec::onOutputScanline(int inputScanline) const { |
| 568 if (fGif->Image.Interlace) { | 562 if (fGif->Image.Interlace) { |
| 569 if (inputScanline < fFrameRect.top() || inputScanline >= fFrameRect.bott
om()) { | 563 if (inputScanline < fFrameRect.top() || inputScanline >= fFrameRect.bott
om()) { |
| 570 return inputScanline; | 564 return inputScanline; |
| 571 } | 565 } |
| 572 return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFram
eRect.height()); | 566 return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFram
eRect.height()); |
| 573 } | 567 } |
| 574 return inputScanline; | 568 return inputScanline; |
| 575 } | 569 } |
| OLD | NEW |