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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 94 // Use maximum unsigned int (surely an invalid index) to indicate that a val id | 94 // Use maximum unsigned int (surely an invalid index) to indicate that a val id |
| 95 // index was not found. | 95 // index was not found. |
| 96 return SK_MaxU32; | 96 return SK_MaxU32; |
| 97 } | 97 } |
| 98 | 98 |
| 99 /* | 99 /* |
| 100 * This function cleans up the gif object after the decode completes | 100 * This function cleans up the gif object after the decode completes |
| 101 * It is used in a SkAutoTCallIProc template | 101 * It is used in a SkAutoTCallIProc template |
| 102 */ | 102 */ |
| 103 void SkGifCodec::CloseGif(GifFileType* gif) { | 103 void SkGifCodec::CloseGif(GifFileType* gif) { |
| 104 DGifCloseFile(gif, NULL); | 104 DGifCloseFile(gif, nullptr); |
| 105 } | 105 } |
| 106 | 106 |
| 107 /* | 107 /* |
| 108 * This function free extension data that has been saved to assist the image | 108 * This function free extension data that has been saved to assist the image |
| 109 * decoder | 109 * decoder |
| 110 */ | 110 */ |
| 111 void SkGifCodec::FreeExtension(SavedImage* image) { | 111 void SkGifCodec::FreeExtension(SavedImage* image) { |
| 112 if (NULL != image->ExtensionBlocks) { | 112 if (nullptr != image->ExtensionBlocks) { |
| 113 GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks); | 113 GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks); |
| 114 } | 114 } |
| 115 } | 115 } |
| 116 | 116 |
| 117 /* | 117 /* |
| 118 * Read enough of the stream to initialize the SkGifCodec. | 118 * Read enough of the stream to initialize the SkGifCodec. |
| 119 * Returns a bool representing success or failure. | 119 * Returns a bool representing success or failure. |
| 120 * | 120 * |
| 121 * @param codecOut | 121 * @param codecOut |
| 122 * If it returned true, and codecOut was not nullptr, | 122 * If it returned true, and codecOut was not nullptr, |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 215 , fSrcBuffer(new uint8_t[this->getInfo().width()]) | 215 , fSrcBuffer(new uint8_t[this->getInfo().width()]) |
| 216 // If it is valid, fTransIndex will be used to set fFillIndex. We don't kno w if | 216 // If it is valid, fTransIndex will be used to set fFillIndex. We don't kno w if |
| 217 // fTransIndex is valid until we process the color table, since fTransIndex may | 217 // fTransIndex is valid until we process the color table, since fTransIndex may |
| 218 // be greater than the size of the color table. | 218 // be greater than the size of the color table. |
| 219 , fTransIndex(transIndex) | 219 , fTransIndex(transIndex) |
| 220 // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid, or if | 220 // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid, or if |
| 221 // there is a valid background color. | 221 // there is a valid background color. |
| 222 , fFillIndex(0) | 222 , fFillIndex(0) |
| 223 , fFrameDims(SkIRect::MakeEmpty()) | 223 , fFrameDims(SkIRect::MakeEmpty()) |
| 224 , fFrameIsSubset(false) | 224 , fFrameIsSubset(false) |
| 225 , fColorTable(NULL) | 225 , fColorTable(nullptr) |
| 226 , fSwizzler(NULL) | 226 , fSwizzler(nullptr) |
| 227 {} | 227 {} |
| 228 | 228 |
| 229 bool SkGifCodec::onRewind() { | 229 bool SkGifCodec::onRewind() { |
| 230 GifFileType* gifOut = nullptr; | 230 GifFileType* gifOut = nullptr; |
| 231 if (!ReadHeader(this->stream(), nullptr, &gifOut)) { | 231 if (!ReadHeader(this->stream(), nullptr, &gifOut)) { |
| 232 return false; | 232 return false; |
| 233 } | 233 } |
| 234 | 234 |
| 235 SkASSERT(nullptr != gifOut); | 235 SkASSERT(nullptr != gifOut); |
| 236 fGif.reset(gifOut); | 236 fGif.reset(gifOut); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 370 } | 370 } |
| 371 | 371 |
| 372 return true; | 372 return true; |
| 373 } | 373 } |
| 374 | 374 |
| 375 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp utColorPtr, | 375 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp utColorPtr, |
| 376 int* inputColorCount) { | 376 int* inputColorCount) { |
| 377 // Set up our own color table | 377 // Set up our own color table |
| 378 const uint32_t maxColors = 256; | 378 const uint32_t maxColors = 256; |
| 379 SkPMColor colorPtr[256]; | 379 SkPMColor colorPtr[256]; |
| 380 if (NULL != inputColorCount) { | 380 if (nullptr != inputColorCount) { |
| 381 // We set the number of colors to maxColors in order to ensure | 381 // We set the number of colors to maxColors in order to ensure |
| 382 // safe memory accesses. Otherwise, an invalid pixel could | 382 // safe memory accesses. Otherwise, an invalid pixel could |
| 383 // access memory outside of our color table array. | 383 // access memory outside of our color table array. |
| 384 *inputColorCount = maxColors; | 384 *inputColorCount = maxColors; |
| 385 } | 385 } |
| 386 | 386 |
| 387 // Get local color table | 387 // Get local color table |
| 388 ColorMapObject* colorMap = fGif->Image.ColorMap; | 388 ColorMapObject* colorMap = fGif->Image.ColorMap; |
| 389 // If there is no local color table, use the global color table | 389 // If there is no local color table, use the global color table |
| 390 if (NULL == colorMap) { | 390 if (nullptr == colorMap) { |
| 391 colorMap = fGif->SColorMap; | 391 colorMap = fGif->SColorMap; |
| 392 } | 392 } |
| 393 | 393 |
| 394 uint32_t colorCount = 0; | 394 uint32_t colorCount = 0; |
| 395 if (NULL != colorMap) { | 395 if (nullptr != colorMap) { |
| 396 colorCount = colorMap->ColorCount; | 396 colorCount = colorMap->ColorCount; |
| 397 // giflib guarantees these properties | 397 // giflib guarantees these properties |
| 398 SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel))); | 398 SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel))); |
| 399 SkASSERT(colorCount <= 256); | 399 SkASSERT(colorCount <= 256); |
| 400 for (uint32_t i = 0; i < colorCount; i++) { | 400 for (uint32_t i = 0; i < colorCount; i++) { |
| 401 colorPtr[i] = SkPackARGB32(0xFF, colorMap->Colors[i].Red, | 401 colorPtr[i] = SkPackARGB32(0xFF, colorMap->Colors[i].Red, |
| 402 colorMap->Colors[i].Green, colorMap->Colors[i].Blue); | 402 colorMap->Colors[i].Green, colorMap->Colors[i].Blue); |
| 403 } | 403 } |
| 404 } | 404 } |
| 405 | 405 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 450 if(!this->setFrameDimensions(desc)) { | 450 if(!this->setFrameDimensions(desc)) { |
| 451 return gif_error("Invalid dimensions for image frame.\n", kInvalidInput) ; | 451 return gif_error("Invalid dimensions for image frame.\n", kInvalidInput) ; |
| 452 } | 452 } |
| 453 | 453 |
| 454 // Initialize color table and copy to the client if necessary | 454 // Initialize color table and copy to the client if necessary |
| 455 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); | 455 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); |
| 456 return kSuccess; | 456 return kSuccess; |
| 457 } | 457 } |
| 458 | 458 |
| 459 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, | 459 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, |
| 460 ZeroInitialized zeroInit) { | 460 ZeroInitialized zeroInit, int subsetLeft, int subsetWidth) { |
| 461 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 461 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
| 462 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, | 462 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, colorPtr, dst Info, zeroInit, |
| 463 colorPtr, dstInfo, zeroInit, this->getInfo())); | 463 this->getInfo(), subsetLeft, subsetWidth)); |
|
scroggo
2015/10/02 18:27:03
If we stick these on options, we can update SkSwiz
| |
| 464 if (nullptr != fSwizzler.get()) { | 464 if (nullptr != fSwizzler.get()) { |
| 465 return kSuccess; | 465 return kSuccess; |
| 466 } | 466 } |
| 467 return kUnimplemented; | 467 return kUnimplemented; |
| 468 } | 468 } |
| 469 | 469 |
| 470 bool SkGifCodec::readRow() { | 470 bool SkGifCodec::readRow() { |
| 471 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameDims.width()); | 471 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameDims.width()); |
| 472 } | 472 } |
| 473 | 473 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 485 return result; | 485 return result; |
| 486 } | 486 } |
| 487 | 487 |
| 488 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 488 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 489 return gif_error("Scaling not supported.\n", kInvalidScale); | 489 return gif_error("Scaling not supported.\n", kInvalidScale); |
| 490 } | 490 } |
| 491 | 491 |
| 492 // Initialize the swizzler | 492 // Initialize the swizzler |
| 493 if (fFrameIsSubset) { | 493 if (fFrameIsSubset) { |
| 494 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr ameDims.height()); | 494 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr ameDims.height()); |
| 495 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized)) { | 495 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized, 0, |
| 496 fFrameDims.width())) { | |
| 496 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; | 497 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; |
| 497 } | 498 } |
| 498 | 499 |
| 499 // Fill the background | 500 // Fill the background |
| 500 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 501 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
| 501 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getFillValue(dstInfo.c olorType(), | 502 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getFillValue(dstInfo.c olorType(), |
| 502 dstInfo.alphaType()), opts.fZeroInitialized); | 503 dstInfo.alphaType()), opts.fZeroInitialized); |
| 503 | 504 |
| 504 // Modify the dst pointer | 505 // Modify the dst pointer |
| 505 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT ype()); | 506 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT ype()); |
| 506 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameDims.top() + | 507 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameDims.top() + |
| 507 dstBytesPerPixel * fFrameDims.left()); | 508 dstBytesPerPixel * fFrameDims.left()); |
| 508 } else { | 509 } else { |
| 509 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized) ) { | 510 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized, 0, |
| 511 dstInfo.width())) { | |
| 510 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; | 512 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; |
| 511 } | 513 } |
| 512 } | 514 } |
| 513 | 515 |
| 514 // Iterate over rows of the input | 516 // Iterate over rows of the input |
| 515 uint32_t width = fFrameDims.width(); | 517 uint32_t width = fFrameDims.width(); |
| 516 uint32_t height = fFrameDims.height(); | 518 uint32_t height = fFrameDims.height(); |
| 517 for (uint32_t y = 0; y < height; y++) { | 519 for (uint32_t y = 0; y < height; y++) { |
| 518 if (!this->readRow()) { | 520 if (!this->readRow()) { |
| 519 *rowsDecoded = y; | 521 *rowsDecoded = y; |
| 520 return gif_error("Could not decode line.\n", kIncompleteInput); | 522 return gif_error("Could not decode line.\n", kIncompleteInput); |
| 521 } | 523 } |
| 522 void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * this->outputScanlin e(y)); | 524 void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * this->outputScanlin e(y)); |
| 523 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 525 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); |
| 524 } | 526 } |
| 525 return kSuccess; | 527 return kSuccess; |
| 526 } | 528 } |
| 527 | 529 |
| 528 uint32_t SkGifCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType ) const { | 530 uint32_t SkGifCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType ) const { |
| 529 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 531 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
| 530 return get_color_table_fill_value(colorType, colorPtr, fFillIndex); | 532 return get_color_table_fill_value(colorType, colorPtr, fFillIndex); |
| 531 } | 533 } |
| 532 | 534 |
| 533 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, | 535 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, |
| 534 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor Count) { | 536 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor Count, |
| 537 int subsetLeft, int subsetWidth) { | |
| 535 | 538 |
| 536 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun t, this->options()); | 539 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun t, this->options()); |
| 537 if (kSuccess != result) { | 540 if (kSuccess != result) { |
| 538 return result; | 541 return result; |
| 539 } | 542 } |
| 540 | 543 |
| 541 // Check to see if scaling was requested. | 544 // Check to see if scaling was requested. |
| 542 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 545 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 543 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstI nfo)) { | 546 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstI nfo)) { |
| 544 return gif_error("Scaling not supported.\n", SkCodec::kInvalidScale) ; | 547 return gif_error("Scaling not supported.\n", SkCodec::kInvalidScale) ; |
| 545 } | 548 } |
| 546 } | 549 } |
| 547 | 550 |
| 548 // Initialize the swizzler | 551 // Initialize the swizzler |
| 549 if (fFrameIsSubset) { | 552 if (fFrameIsSubset) { |
| 550 int sampleX; | 553 int sampleX; |
| 551 SkScaledCodec::ComputeSampleSize(dstInfo, this->getInfo(), &sampleX, NUL L); | 554 SkScaledCodec::ComputeSampleSize(dstInfo.dimensions(), this->getInfo().d imensions(), |
| 555 &sampleX, NULL); | |
| 552 const SkImageInfo subsetDstInfo = dstInfo.makeWH( | 556 const SkImageInfo subsetDstInfo = dstInfo.makeWH( |
| 553 get_scaled_dimension(fFrameDims.width(), sampleX), | 557 get_scaled_dimension(fFrameDims.width(), sampleX), |
| 554 fFrameDims.height()); | 558 fFrameDims.height()); |
| 555 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized)) { | 559 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized, subsetLeft, |
| 560 subsetWidth)) { | |
| 556 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; | 561 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; |
| 557 } | 562 } |
| 558 } else { | 563 } else { |
| 559 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized) ) { | 564 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized, subsetLeft, |
| 565 subsetWidth)) { | |
| 560 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; | 566 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; |
| 561 } | 567 } |
| 562 } | 568 } |
| 563 | 569 |
| 564 return kSuccess; | 570 return kSuccess; |
| 565 } | 571 } |
| 566 | 572 |
| 567 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { | 573 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { |
| 568 int rowsBeforeFrame = 0; | 574 int rowsBeforeFrame = 0; |
| 569 int rowsAfterFrame = 0; | 575 int rowsAfterFrame = 0; |
| 570 if (fFrameIsSubset) { | 576 if (fFrameIsSubset) { |
| 571 // Fill the requested rows | 577 // Fill the requested rows |
| 572 SkSwizzler::Fill(dst, this->dstInfo().makeWH(this->dstInfo().width(), co unt), rowBytes, | 578 SkSwizzler::Fill(dst, this->dstInfo().makeWH(this->subsetWidth(), count) , rowBytes, |
| 573 this->onGetFillValue(this->dstInfo().colorType(), this->dstInfo( ).alphaType()), | 579 this->onGetFillValue(this->dstInfo().colorType(), this->dstInfo( ).alphaType()), |
| 574 this->options().fZeroInitialized); | 580 this->options().fZeroInitialized); |
| 575 | 581 |
| 576 // Do nothing for rows before the image frame | 582 // Do nothing for rows before the image frame |
| 577 // FIXME: Do we handle fFrameIsSubset properly for interlaced images? | 583 // FIXME: Do we handle fFrameIsSubset properly for interlaced images? |
| 578 rowsBeforeFrame = SkTMax(0, fFrameDims.top() - this->nextScanline()); | 584 rowsBeforeFrame = SkTMax(0, fFrameDims.top() - this->nextScanline()); |
| 579 count = SkTMax(0, count - rowsBeforeFrame); | 585 count = SkTMax(0, count - rowsBeforeFrame); |
| 580 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); | 586 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); |
| 581 | 587 |
| 582 // Do nothing for rows after the image frame | 588 // Do nothing for rows after the image frame |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 597 } | 603 } |
| 598 return count + rowsBeforeFrame + rowsAfterFrame; | 604 return count + rowsBeforeFrame + rowsAfterFrame; |
| 599 } | 605 } |
| 600 | 606 |
| 601 SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const { | 607 SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const { |
| 602 if (fGif->Image.Interlace) { | 608 if (fGif->Image.Interlace) { |
| 603 return kOutOfOrder_SkScanlineOrder; | 609 return kOutOfOrder_SkScanlineOrder; |
| 604 } | 610 } |
| 605 return kTopDown_SkScanlineOrder; | 611 return kTopDown_SkScanlineOrder; |
| 606 } | 612 } |
| OLD | NEW |