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 |