Chromium Code Reviews| 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 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 118 } | 118 } |
| 119 // Fourth pass | 119 // Fourth pass |
| 120 return 1 + 2 * (encodedRow - ceil_div(height, 2)); | 120 return 1 + 2 * (encodedRow - ceil_div(height, 2)); |
| 121 } | 121 } |
| 122 | 122 |
| 123 /* | 123 /* |
| 124 * This function cleans up the gif object after the decode completes | 124 * This function cleans up the gif object after the decode completes |
| 125 * It is used in a SkAutoTCallIProc template | 125 * It is used in a SkAutoTCallIProc template |
| 126 */ | 126 */ |
| 127 void SkGifCodec::CloseGif(GifFileType* gif) { | 127 void SkGifCodec::CloseGif(GifFileType* gif) { |
| 128 DGifCloseFile(gif, NULL); | 128 DGifCloseFile(gif, nullptr); |
|
scroggo
2015/10/08 20:16:07
This change deserves to be a separate CL. It makes
msarett
2015/10/09 20:03:44
Removing.
| |
| 129 } | 129 } |
| 130 | 130 |
| 131 /* | 131 /* |
| 132 * This function free extension data that has been saved to assist the image | 132 * This function free extension data that has been saved to assist the image |
| 133 * decoder | 133 * decoder |
| 134 */ | 134 */ |
| 135 void SkGifCodec::FreeExtension(SavedImage* image) { | 135 void SkGifCodec::FreeExtension(SavedImage* image) { |
| 136 if (NULL != image->ExtensionBlocks) { | 136 if (nullptr != image->ExtensionBlocks) { |
| 137 GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks); | 137 GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks); |
| 138 } | 138 } |
| 139 } | 139 } |
| 140 | 140 |
| 141 /* | 141 /* |
| 142 * Read enough of the stream to initialize the SkGifCodec. | 142 * Read enough of the stream to initialize the SkGifCodec. |
| 143 * Returns a bool representing success or failure. | 143 * Returns a bool representing success or failure. |
| 144 * | 144 * |
| 145 * @param codecOut | 145 * @param codecOut |
| 146 * If it returned true, and codecOut was not nullptr, | 146 * If it returned true, and codecOut was not nullptr, |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 239 , fSrcBuffer(new uint8_t[this->getInfo().width()]) | 239 , fSrcBuffer(new uint8_t[this->getInfo().width()]) |
| 240 // If it is valid, fTransIndex will be used to set fFillIndex. We don't kno w if | 240 // If it is valid, fTransIndex will be used to set fFillIndex. We don't kno w if |
| 241 // fTransIndex is valid until we process the color table, since fTransIndex may | 241 // fTransIndex is valid until we process the color table, since fTransIndex may |
| 242 // be greater than the size of the color table. | 242 // be greater than the size of the color table. |
| 243 , fTransIndex(transIndex) | 243 , fTransIndex(transIndex) |
| 244 // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid, or if | 244 // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid, or if |
| 245 // there is a valid background color. | 245 // there is a valid background color. |
| 246 , fFillIndex(0) | 246 , fFillIndex(0) |
| 247 , fFrameRect(frameRect) | 247 , fFrameRect(frameRect) |
| 248 , fFrameIsSubset(frameIsSubset) | 248 , fFrameIsSubset(frameIsSubset) |
| 249 , fColorTable(NULL) | 249 , fColorTable(nullptr) |
| 250 , fSwizzler(NULL) | 250 , fSwizzler(nullptr) |
| 251 {} | 251 {} |
| 252 | 252 |
| 253 bool SkGifCodec::onRewind() { | 253 bool SkGifCodec::onRewind() { |
| 254 GifFileType* gifOut = nullptr; | 254 GifFileType* gifOut = nullptr; |
| 255 if (!ReadHeader(this->stream(), nullptr, &gifOut)) { | 255 if (!ReadHeader(this->stream(), nullptr, &gifOut)) { |
| 256 return false; | 256 return false; |
| 257 } | 257 } |
| 258 | 258 |
| 259 SkASSERT(nullptr != gifOut); | 259 SkASSERT(nullptr != gifOut); |
| 260 fGif.reset(gifOut); | 260 fGif.reset(gifOut); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 373 frameRect->setXYWH(frameLeft, frameTop, frameWidth, frameHeight); | 373 frameRect->setXYWH(frameLeft, frameTop, frameWidth, frameHeight); |
| 374 size->set(width, height); | 374 size->set(width, height); |
| 375 return true; | 375 return true; |
| 376 } | 376 } |
| 377 | 377 |
| 378 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp utColorPtr, | 378 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp utColorPtr, |
| 379 int* inputColorCount) { | 379 int* inputColorCount) { |
| 380 // Set up our own color table | 380 // Set up our own color table |
| 381 const uint32_t maxColors = 256; | 381 const uint32_t maxColors = 256; |
| 382 SkPMColor colorPtr[256]; | 382 SkPMColor colorPtr[256]; |
| 383 if (NULL != inputColorCount) { | 383 if (nullptr != inputColorCount) { |
| 384 // We set the number of colors to maxColors in order to ensure | 384 // We set the number of colors to maxColors in order to ensure |
| 385 // safe memory accesses. Otherwise, an invalid pixel could | 385 // safe memory accesses. Otherwise, an invalid pixel could |
| 386 // access memory outside of our color table array. | 386 // access memory outside of our color table array. |
| 387 *inputColorCount = maxColors; | 387 *inputColorCount = maxColors; |
| 388 } | 388 } |
| 389 | 389 |
| 390 // Get local color table | 390 // Get local color table |
| 391 ColorMapObject* colorMap = fGif->Image.ColorMap; | 391 ColorMapObject* colorMap = fGif->Image.ColorMap; |
| 392 // If there is no local color table, use the global color table | 392 // If there is no local color table, use the global color table |
| 393 if (NULL == colorMap) { | 393 if (nullptr == colorMap) { |
| 394 colorMap = fGif->SColorMap; | 394 colorMap = fGif->SColorMap; |
| 395 } | 395 } |
| 396 | 396 |
| 397 uint32_t colorCount = 0; | 397 uint32_t colorCount = 0; |
| 398 if (NULL != colorMap) { | 398 if (nullptr != colorMap) { |
| 399 colorCount = colorMap->ColorCount; | 399 colorCount = colorMap->ColorCount; |
| 400 // giflib guarantees these properties | 400 // giflib guarantees these properties |
| 401 SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel))); | 401 SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel))); |
| 402 SkASSERT(colorCount <= 256); | 402 SkASSERT(colorCount <= 256); |
| 403 for (uint32_t i = 0; i < colorCount; i++) { | 403 for (uint32_t i = 0; i < colorCount; i++) { |
| 404 colorPtr[i] = SkPackARGB32(0xFF, colorMap->Colors[i].Red, | 404 colorPtr[i] = SkPackARGB32(0xFF, colorMap->Colors[i].Red, |
| 405 colorMap->Colors[i].Green, colorMap->Colors[i].Blue); | 405 colorMap->Colors[i].Green, colorMap->Colors[i].Blue); |
| 406 } | 406 } |
| 407 } | 407 } |
| 408 | 408 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 428 colorPtr[i] = colorPtr[fFillIndex]; | 428 colorPtr[i] = colorPtr[fFillIndex]; |
| 429 } | 429 } |
| 430 | 430 |
| 431 fColorTable.reset(new SkColorTable(colorPtr, maxColors)); | 431 fColorTable.reset(new SkColorTable(colorPtr, maxColors)); |
| 432 copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount) ; | 432 copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount) ; |
| 433 } | 433 } |
| 434 | 434 |
| 435 SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColo r* inputColorPtr, | 435 SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColo r* inputColorPtr, |
| 436 int* inputColorCount, const Options& opts) { | 436 int* inputColorCount, const Options& opts) { |
| 437 // Check for valid input parameters | 437 // Check for valid input parameters |
| 438 if (opts.fSubset) { | |
| 439 // Subsets are not supported. | |
| 440 return kUnimplemented; | |
| 441 } | |
| 442 if (!conversion_possible(dstInfo, this->getInfo())) { | 438 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 443 return gif_error("Cannot convert input type to output type.\n", | 439 return gif_error("Cannot convert input type to output type.\n", |
| 444 kInvalidConversion); | 440 kInvalidConversion); |
| 445 } | 441 } |
| 446 | 442 |
| 447 // Initialize color table and copy to the client if necessary | 443 // Initialize color table and copy to the client if necessary |
| 448 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); | 444 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); |
| 449 return kSuccess; | 445 return kSuccess; |
| 450 } | 446 } |
| 451 | 447 |
| 452 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, | 448 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) { |
| 453 ZeroInitialized zeroInit) { | |
| 454 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 449 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
| 455 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, | 450 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, colorPtr, dst Info, opts)); |
| 456 colorPtr, dstInfo, zeroInit)); | |
| 457 if (nullptr != fSwizzler.get()) { | 451 if (nullptr != fSwizzler.get()) { |
| 458 return kSuccess; | 452 return kSuccess; |
| 459 } | 453 } |
| 460 return kUnimplemented; | 454 return kUnimplemented; |
| 461 } | 455 } |
| 462 | 456 |
| 463 bool SkGifCodec::readRow() { | 457 bool SkGifCodec::readRow() { |
| 464 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width()); | 458 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width()); |
| 465 } | 459 } |
| 466 | 460 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 478 return result; | 472 return result; |
| 479 } | 473 } |
| 480 | 474 |
| 481 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 475 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 482 return gif_error("Scaling not supported.\n", kInvalidScale); | 476 return gif_error("Scaling not supported.\n", kInvalidScale); |
| 483 } | 477 } |
| 484 | 478 |
| 485 // Initialize the swizzler | 479 // Initialize the swizzler |
| 486 if (fFrameIsSubset) { | 480 if (fFrameIsSubset) { |
| 487 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr ameRect.height()); | 481 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr ameRect.height()); |
| 488 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized)) { | 482 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) { |
| 489 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; | 483 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; |
| 490 } | 484 } |
| 491 | 485 |
| 492 // Fill the background | 486 // Fill the background |
| 493 SkSampler::Fill(dstInfo, dst, dstRowBytes, | 487 SkSampler::Fill(dstInfo, dst, dstRowBytes, |
| 494 this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()), | 488 this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()), |
| 495 opts.fZeroInitialized); | 489 opts.fZeroInitialized); |
| 496 | 490 |
| 497 // Modify the dst pointer | 491 // Modify the dst pointer |
| 498 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT ype()); | 492 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT ype()); |
| 499 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + | 493 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + |
| 500 dstBytesPerPixel * fFrameRect.left()); | 494 dstBytesPerPixel * fFrameRect.left()); |
| 501 } else { | 495 } else { |
| 502 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized) ) { | 496 if (kSuccess != this->initializeSwizzler(dstInfo, opts)) { |
| 503 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; | 497 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; |
| 504 } | 498 } |
| 505 } | 499 } |
| 506 | 500 |
| 507 // Iterate over rows of the input | 501 // Iterate over rows of the input |
| 508 uint32_t width = fFrameRect.width(); | 502 uint32_t width = fFrameRect.width(); |
| 509 uint32_t height = fFrameRect.height(); | 503 uint32_t height = fFrameRect.height(); |
| 510 for (uint32_t y = 0; y < height; y++) { | 504 for (uint32_t y = 0; y < height; y++) { |
| 511 if (!this->readRow()) { | 505 if (!this->readRow()) { |
| 512 *rowsDecoded = y; | 506 *rowsDecoded = y; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 529 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor Count) { | 523 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor Count) { |
| 530 | 524 |
| 531 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun t, this->options()); | 525 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun t, this->options()); |
| 532 if (kSuccess != result) { | 526 if (kSuccess != result) { |
| 533 return result; | 527 return result; |
| 534 } | 528 } |
| 535 | 529 |
| 536 // Initialize the swizzler | 530 // Initialize the swizzler |
| 537 if (fFrameIsSubset) { | 531 if (fFrameIsSubset) { |
| 538 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr ameRect.height()); | 532 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr ameRect.height()); |
| 539 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized)) { | 533 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) { |
| 540 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; | 534 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; |
| 541 } | 535 } |
| 542 } else { | 536 } else { |
| 543 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized) ) { | 537 if (kSuccess != this->initializeSwizzler(dstInfo, opts)) { |
| 544 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; | 538 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; |
| 545 } | 539 } |
| 546 } | 540 } |
| 547 | 541 |
| 548 return kSuccess; | 542 return kSuccess; |
| 549 } | 543 } |
| 550 | 544 |
| 551 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { | 545 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { |
| 552 int rowsBeforeFrame = 0; | 546 int rowsBeforeFrame = 0; |
| 553 int rowsAfterFrame = 0; | 547 int rowsAfterFrame = 0; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 594 | 588 |
| 595 int SkGifCodec::onOutputScanline(int inputScanline) const { | 589 int SkGifCodec::onOutputScanline(int inputScanline) const { |
| 596 if (fGif->Image.Interlace) { | 590 if (fGif->Image.Interlace) { |
| 597 if (inputScanline < fFrameRect.top() || inputScanline >= fFrameRect.bott om()) { | 591 if (inputScanline < fFrameRect.top() || inputScanline >= fFrameRect.bott om()) { |
| 598 return inputScanline; | 592 return inputScanline; |
| 599 } | 593 } |
| 600 return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFram eRect.height()); | 594 return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFram eRect.height()); |
| 601 } | 595 } |
| 602 return inputScanline; | 596 return inputScanline; |
| 603 } | 597 } |
| OLD | NEW |