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_libpng.h" | 8 #include "SkCodec_libpng.h" |
9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
11 #include "SkColorTable.h" | 11 #include "SkColorTable.h" |
12 #include "SkBitmap.h" | 12 #include "SkBitmap.h" |
13 #include "SkMath.h" | 13 #include "SkMath.h" |
14 #include "SkSize.h" | 14 #include "SkSize.h" |
15 #include "SkStream.h" | 15 #include "SkStream.h" |
16 #include "SkSwizzler.h" | 16 #include "SkSwizzler.h" |
| 17 #include "SkTemplates.h" |
17 | 18 |
18 /////////////////////////////////////////////////////////////////////////////// | 19 /////////////////////////////////////////////////////////////////////////////// |
19 // Helper macros | 20 // Helper macros |
20 /////////////////////////////////////////////////////////////////////////////// | 21 /////////////////////////////////////////////////////////////////////////////// |
21 | 22 |
22 #ifndef png_jmpbuf | 23 #ifndef png_jmpbuf |
23 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) | 24 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) |
24 #endif | 25 #endif |
25 | 26 |
26 /* These were dropped in libpng >= 1.4 */ | 27 /* These were dropped in libpng >= 1.4 */ |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 | 497 |
497 // Note that ctable and ctableCount may be modified if there is a color tabl
e | 498 // Note that ctable and ctableCount may be modified if there is a color tabl
e |
498 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl
e, ctableCount); | 499 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl
e, ctableCount); |
499 if (result != kSuccess) { | 500 if (result != kSuccess) { |
500 return result; | 501 return result; |
501 } | 502 } |
502 // FIXME: Could we use the return value of setjmp to specify the type of | 503 // FIXME: Could we use the return value of setjmp to specify the type of |
503 // error? | 504 // error? |
504 int row = 0; | 505 int row = 0; |
505 // This must be declared above the call to setjmp to avoid memory leaks on i
ncomplete images. | 506 // This must be declared above the call to setjmp to avoid memory leaks on i
ncomplete images. |
506 SkAutoMalloc storage; | 507 SkAutoTMalloc<uint8_t> storage; |
507 if (setjmp(png_jmpbuf(fPng_ptr))) { | 508 if (setjmp(png_jmpbuf(fPng_ptr))) { |
508 // Assume that any error that occurs while reading rows is caused by an
incomplete input. | 509 // Assume that any error that occurs while reading rows is caused by an
incomplete input. |
509 if (fNumberPasses > 1) { | 510 if (fNumberPasses > 1) { |
510 // FIXME (msarett): Handle incomplete interlaced pngs. | 511 // FIXME (msarett): Handle incomplete interlaced pngs. |
511 return kInvalidInput; | 512 return kInvalidInput; |
512 } | 513 } |
513 // FIXME: We do a poor job on incomplete pngs compared to other decoders
(ex: Chromium, | 514 // FIXME: We do a poor job on incomplete pngs compared to other decoders
(ex: Chromium, |
514 // Ubuntu Image Viewer). This is because we use the default buffer size
in libpng (8192 | 515 // Ubuntu Image Viewer). This is because we use the default buffer size
in libpng (8192 |
515 // bytes), and if we can't fill the buffer, we immediately fail. | 516 // bytes), and if we can't fill the buffer, we immediately fail. |
516 // For example, if we try to read 8192 bytes, and the image (incorrectly
) only contains | 517 // For example, if we try to read 8192 bytes, and the image (incorrectly
) only contains |
(...skipping 11 matching lines...) Expand all Loading... |
528 bool hasAlpha = false; | 529 bool hasAlpha = false; |
529 // FIXME: We could split these out based on subclass. | 530 // FIXME: We could split these out based on subclass. |
530 void* dstRow = dst; | 531 void* dstRow = dst; |
531 if (fNumberPasses > 1) { | 532 if (fNumberPasses > 1) { |
532 const int width = requestedInfo.width(); | 533 const int width = requestedInfo.width(); |
533 const int height = requestedInfo.height(); | 534 const int height = requestedInfo.height(); |
534 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); | 535 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); |
535 const size_t srcRowBytes = width * bpp; | 536 const size_t srcRowBytes = width * bpp; |
536 | 537 |
537 storage.reset(width * height * bpp); | 538 storage.reset(width * height * bpp); |
538 uint8_t* const base = static_cast<uint8_t*>(storage.get()); | 539 uint8_t* const base = storage.get(); |
539 | 540 |
540 for (int i = 0; i < fNumberPasses; i++) { | 541 for (int i = 0; i < fNumberPasses; i++) { |
541 uint8_t* srcRow = base; | 542 uint8_t* srcRow = base; |
542 for (int y = 0; y < height; y++) { | 543 for (int y = 0; y < height; y++) { |
543 uint8_t* bmRow = srcRow; | 544 uint8_t* bmRow = srcRow; |
544 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); | 545 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); |
545 srcRow += srcRowBytes; | 546 srcRow += srcRowBytes; |
546 } | 547 } |
547 } | 548 } |
548 | 549 |
549 // Now swizzle it. | 550 // Now swizzle it. |
550 uint8_t* srcRow = base; | 551 uint8_t* srcRow = base; |
551 for (int y = 0; y < height; y++) { | 552 for (int y = 0; y < height; y++) { |
552 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)
); | 553 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)
); |
553 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 554 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
554 srcRow += srcRowBytes; | 555 srcRow += srcRowBytes; |
555 } | 556 } |
556 } else { | 557 } else { |
557 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf
ig)); | 558 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf
ig)); |
558 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); | 559 uint8_t* srcRow = storage.get(); |
559 for (; row < requestedInfo.height(); row++) { | 560 for (; row < requestedInfo.height(); row++) { |
560 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); | 561 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); |
561 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS
canlines. | 562 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS
canlines. |
562 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)
); | 563 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)
); |
563 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 564 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
564 } | 565 } |
565 } | 566 } |
566 | 567 |
567 if (hasAlpha) { | 568 if (hasAlpha) { |
568 fAlphaState = kHasAlpha_AlphaState; | 569 fAlphaState = kHasAlpha_AlphaState; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
635 } | 636 } |
636 | 637 |
637 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 638 const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
638 ctableCount); | 639 ctableCount); |
639 if (result != kSuccess) { | 640 if (result != kSuccess) { |
640 return result; | 641 return result; |
641 } | 642 } |
642 | 643 |
643 fAlphaState = kUnknown_AlphaState; | 644 fAlphaState = kUnknown_AlphaState; |
644 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig())); | 645 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig())); |
645 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | 646 fSrcRow = fStorage.get(); |
646 | 647 |
647 return kSuccess; | 648 return kSuccess; |
648 } | 649 } |
649 | 650 |
650 int onGetScanlines(void* dst, int count, size_t rowBytes) override { | 651 int onGetScanlines(void* dst, int count, size_t rowBytes) override { |
651 // Assume that an error in libpng indicates an incomplete input. | 652 // Assume that an error in libpng indicates an incomplete input. |
652 int row = 0; | 653 int row = 0; |
653 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 654 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
654 SkCodecPrintf("setjmp long jump!\n"); | 655 SkCodecPrintf("setjmp long jump!\n"); |
655 return row; | 656 return row; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
689 } | 690 } |
690 return true; | 691 return true; |
691 } | 692 } |
692 | 693 |
693 AlphaState alphaInScanlineDecode() const override { | 694 AlphaState alphaInScanlineDecode() const override { |
694 return fAlphaState; | 695 return fAlphaState; |
695 } | 696 } |
696 | 697 |
697 private: | 698 private: |
698 AlphaState fAlphaState; | 699 AlphaState fAlphaState; |
699 SkAutoMalloc fStorage; | 700 SkAutoTMalloc<uint8_t> fStorage; |
700 uint8_t* fSrcRow; | 701 uint8_t* fSrcRow; |
701 | 702 |
702 typedef SkPngCodec INHERITED; | 703 typedef SkPngCodec INHERITED; |
703 }; | 704 }; |
704 | 705 |
705 | 706 |
706 class SkPngInterlacedScanlineDecoder : public SkPngCodec { | 707 class SkPngInterlacedScanlineDecoder : public SkPngCodec { |
707 public: | 708 public: |
708 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, | 709 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
709 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p
tr, | 710 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p
tr, |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
762 this->updateCurrScanline(currScanline); | 763 this->updateCurrScanline(currScanline); |
763 } | 764 } |
764 | 765 |
765 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 766 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
766 SkCodecPrintf("setjmp long jump!\n"); | 767 SkCodecPrintf("setjmp long jump!\n"); |
767 // FIXME (msarett): Returning 0 is pessimistic. If we can complete
a single pass, | 768 // FIXME (msarett): Returning 0 is pessimistic. If we can complete
a single pass, |
768 // we may be able to report that all of the memory has been initiali
zed. Even if we | 769 // we may be able to report that all of the memory has been initiali
zed. Even if we |
769 // fail on the first pass, we can still report than some scanlines a
re initialized. | 770 // fail on the first pass, we can still report than some scanlines a
re initialized. |
770 return 0; | 771 return 0; |
771 } | 772 } |
772 SkAutoMalloc storage(count * fSrcRowBytes); | 773 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes); |
773 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); | 774 uint8_t* storagePtr = storage.get(); |
774 uint8_t* srcRow; | 775 uint8_t* srcRow; |
775 const int startRow = this->nextScanline(); | 776 const int startRow = this->nextScanline(); |
776 for (int i = 0; i < this->numberPasses(); i++) { | 777 for (int i = 0; i < this->numberPasses(); i++) { |
777 // read rows we planned to skip into garbage row | 778 // read rows we planned to skip into garbage row |
778 for (int y = 0; y < startRow; y++){ | 779 for (int y = 0; y < startRow; y++){ |
779 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL,
1); | 780 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL,
1); |
780 } | 781 } |
781 // read rows we care about into buffer | 782 // read rows we care about into buffer |
782 srcRow = storagePtr; | 783 srcRow = storagePtr; |
783 for (int y = 0; y < count; y++) { | 784 for (int y = 0; y < count; y++) { |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
857 } | 858 } |
858 | 859 |
859 if (1 == numberPasses) { | 860 if (1 == numberPasses) { |
860 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk
Reader, | 861 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk
Reader, |
861 png_ptr, info_ptr, bitDepth); | 862 png_ptr, info_ptr, bitDepth); |
862 } | 863 } |
863 | 864 |
864 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(),
chunkReader, | 865 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(),
chunkReader, |
865 png_ptr, info_ptr, bitDepth, numbe
rPasses); | 866 png_ptr, info_ptr, bitDepth, numbe
rPasses); |
866 } | 867 } |
OLD | NEW |