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 "SkCodecPriv.h" | 8 #include "SkCodecPriv.h" |
9 #include "SkColorPriv.h" | 9 #include "SkColorPriv.h" |
10 #include "SkColorTable.h" | 10 #include "SkColorTable.h" |
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 if (options.fSubset) { | 471 if (options.fSubset) { |
472 // Subsets are not supported. | 472 // Subsets are not supported. |
473 return kUnimplemented; | 473 return kUnimplemented; |
474 } | 474 } |
475 | 475 |
476 // Note that ctable and ctableCount may be modified if there is a color tabl
e | 476 // Note that ctable and ctableCount may be modified if there is a color tabl
e |
477 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl
e, ctableCount); | 477 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl
e, ctableCount); |
478 if (result != kSuccess) { | 478 if (result != kSuccess) { |
479 return result; | 479 return result; |
480 } | 480 } |
| 481 |
| 482 const int width = requestedInfo.width(); |
| 483 const int height = requestedInfo.height(); |
| 484 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); |
| 485 const size_t srcRowBytes = width * bpp; |
| 486 |
481 // FIXME: Could we use the return value of setjmp to specify the type of | 487 // FIXME: Could we use the return value of setjmp to specify the type of |
482 // error? | 488 // error? |
483 int row = 0; | 489 int row = 0; |
484 // This must be declared above the call to setjmp to avoid memory leaks on i
ncomplete images. | 490 // This must be declared above the call to setjmp to avoid memory leaks on i
ncomplete images. |
485 SkAutoTMalloc<uint8_t> storage; | 491 SkAutoTMalloc<uint8_t> storage; |
486 if (setjmp(png_jmpbuf(fPng_ptr))) { | 492 if (setjmp(png_jmpbuf(fPng_ptr))) { |
487 // Assume that any error that occurs while reading rows is caused by an
incomplete input. | 493 // Assume that any error that occurs while reading rows is caused by an
incomplete input. |
488 if (fNumberPasses > 1) { | 494 if (fNumberPasses > 1) { |
489 // FIXME (msarett): Handle incomplete interlaced pngs. | 495 // FIXME (msarett): Handle incomplete interlaced pngs. |
490 return kInvalidInput; | 496 return (row == height) ? kSuccess : kInvalidInput; |
491 } | 497 } |
492 // FIXME: We do a poor job on incomplete pngs compared to other decoders
(ex: Chromium, | 498 // FIXME: We do a poor job on incomplete pngs compared to other decoders
(ex: Chromium, |
493 // Ubuntu Image Viewer). This is because we use the default buffer size
in libpng (8192 | 499 // Ubuntu Image Viewer). This is because we use the default buffer size
in libpng (8192 |
494 // bytes), and if we can't fill the buffer, we immediately fail. | 500 // bytes), and if we can't fill the buffer, we immediately fail. |
495 // For example, if we try to read 8192 bytes, and the image (incorrectly
) only contains | 501 // For example, if we try to read 8192 bytes, and the image (incorrectly
) only contains |
496 // half that, which may have been enough to contain a non-zero number of
lines, we fail | 502 // half that, which may have been enough to contain a non-zero number of
lines, we fail |
497 // when we could have decoded a few more lines and then failed. | 503 // when we could have decoded a few more lines and then failed. |
498 // The read function that we provide for libpng has no way of indicating
that we have | 504 // The read function that we provide for libpng has no way of indicating
that we have |
499 // made a partial read. | 505 // made a partial read. |
500 // Making our buffer size smaller improves our incomplete decodes, but w
hat impact does | 506 // Making our buffer size smaller improves our incomplete decodes, but w
hat impact does |
501 // it have on regular decode performance? Should we investigate using a
different API | 507 // it have on regular decode performance? Should we investigate using a
different API |
502 // instead of png_read_row(s)? Chromium uses png_process_data. | 508 // instead of png_read_row? Chromium uses png_process_data. |
503 *rowsDecoded = row; | 509 *rowsDecoded = row; |
504 return kIncompleteInput; | 510 return (row == height) ? kSuccess : kIncompleteInput; |
505 } | 511 } |
506 | 512 |
507 // FIXME: We could split these out based on subclass. | 513 // FIXME: We could split these out based on subclass. |
508 void* dstRow = dst; | 514 void* dstRow = dst; |
509 if (fNumberPasses > 1) { | 515 if (fNumberPasses > 1) { |
510 const int width = requestedInfo.width(); | 516 storage.reset(height * srcRowBytes); |
511 const int height = requestedInfo.height(); | |
512 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); | |
513 const size_t srcRowBytes = width * bpp; | |
514 | |
515 storage.reset(width * height * bpp); | |
516 uint8_t* const base = storage.get(); | 517 uint8_t* const base = storage.get(); |
517 | 518 |
518 for (int i = 0; i < fNumberPasses; i++) { | 519 for (int i = 0; i < fNumberPasses; i++) { |
519 uint8_t* srcRow = base; | 520 uint8_t* srcRow = base; |
520 for (int y = 0; y < height; y++) { | 521 for (int y = 0; y < height; y++) { |
521 uint8_t* bmRow = srcRow; | 522 png_read_row(fPng_ptr, srcRow, nullptr); |
522 png_read_rows(fPng_ptr, &bmRow, nullptr, 1); | |
523 srcRow += srcRowBytes; | 523 srcRow += srcRowBytes; |
524 } | 524 } |
525 } | 525 } |
526 | 526 |
527 // Now swizzle it. | 527 // Now swizzle it. |
528 uint8_t* srcRow = base; | 528 uint8_t* srcRow = base; |
529 for (int y = 0; y < height; y++) { | 529 for (; row < height; row++) { |
530 fSwizzler->swizzle(dstRow, srcRow); | 530 fSwizzler->swizzle(dstRow, srcRow); |
531 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 531 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
532 srcRow += srcRowBytes; | 532 srcRow += srcRowBytes; |
533 } | 533 } |
534 } else { | 534 } else { |
535 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf
ig)); | 535 storage.reset(srcRowBytes); |
536 uint8_t* srcRow = storage.get(); | 536 uint8_t* srcRow = storage.get(); |
537 for (; row < requestedInfo.height(); row++) { | 537 for (; row < height; row++) { |
538 png_read_rows(fPng_ptr, &srcRow, nullptr, 1); | 538 png_read_row(fPng_ptr, srcRow, nullptr); |
539 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS
canlines. | |
540 fSwizzler->swizzle(dstRow, srcRow); | 539 fSwizzler->swizzle(dstRow, srcRow); |
541 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 540 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
542 } | 541 } |
543 } | 542 } |
544 | 543 |
545 if (setjmp(png_jmpbuf(fPng_ptr))) { | |
546 // We've already read all the scanlines. This is a success. | |
547 return kSuccess; | |
548 } | |
549 | |
550 // read rest of file, and get additional comment and time chunks in info_ptr | 544 // read rest of file, and get additional comment and time chunks in info_ptr |
551 png_read_end(fPng_ptr, fInfo_ptr); | 545 png_read_end(fPng_ptr, fInfo_ptr); |
552 | 546 |
553 return kSuccess; | 547 return kSuccess; |
554 } | 548 } |
555 | 549 |
556 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { | 550 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { |
557 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 551 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
558 if (colorPtr) { | 552 if (colorPtr) { |
559 return get_color_table_fill_value(colorType, colorPtr, 0); | 553 return get_color_table_fill_value(colorType, colorPtr, 0); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 int onGetScanlines(void* dst, int count, size_t rowBytes) override { | 585 int onGetScanlines(void* dst, int count, size_t rowBytes) override { |
592 // Assume that an error in libpng indicates an incomplete input. | 586 // Assume that an error in libpng indicates an incomplete input. |
593 int row = 0; | 587 int row = 0; |
594 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 588 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
595 SkCodecPrintf("setjmp long jump!\n"); | 589 SkCodecPrintf("setjmp long jump!\n"); |
596 return row; | 590 return row; |
597 } | 591 } |
598 | 592 |
599 void* dstRow = dst; | 593 void* dstRow = dst; |
600 for (; row < count; row++) { | 594 for (; row < count; row++) { |
601 png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1); | 595 png_read_row(this->png_ptr(), fSrcRow, nullptr); |
602 this->swizzler()->swizzle(dstRow, fSrcRow); | 596 this->swizzler()->swizzle(dstRow, fSrcRow); |
603 dstRow = SkTAddOffset<void>(dstRow, rowBytes); | 597 dstRow = SkTAddOffset<void>(dstRow, rowBytes); |
604 } | 598 } |
605 | 599 |
606 return row; | 600 return row; |
607 } | 601 } |
608 | 602 |
609 bool onSkipScanlines(int count) override { | 603 bool onSkipScanlines(int count) override { |
610 // Assume that an error in libpng indicates an incomplete input. | 604 // Assume that an error in libpng indicates an incomplete input. |
611 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 605 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
612 SkCodecPrintf("setjmp long jump!\n"); | 606 SkCodecPrintf("setjmp long jump!\n"); |
613 return false; | 607 return false; |
614 } | 608 } |
615 //there is a potential tradeoff of memory vs speed created by putting th
is in a loop. | 609 |
616 //calling png_read_rows in a loop is insignificantly slower than calling
it once with count | |
617 //as png_read_rows has it's own loop which calls png_read_row count time
s. | |
618 for (int row = 0; row < count; row++) { | 610 for (int row = 0; row < count; row++) { |
619 png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1); | 611 png_read_row(this->png_ptr(), fSrcRow, nullptr); |
620 } | 612 } |
621 return true; | 613 return true; |
622 } | 614 } |
623 | 615 |
624 private: | 616 private: |
625 SkAutoTMalloc<uint8_t> fStorage; | 617 SkAutoTMalloc<uint8_t> fStorage; |
626 uint8_t* fSrcRow; | 618 uint8_t* fSrcRow; |
627 | 619 |
628 typedef SkPngCodec INHERITED; | 620 typedef SkPngCodec INHERITED; |
629 }; | 621 }; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
693 // fail on the first pass, we can still report than some scanlines a
re initialized. | 685 // fail on the first pass, we can still report than some scanlines a
re initialized. |
694 return 0; | 686 return 0; |
695 } | 687 } |
696 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes); | 688 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes); |
697 uint8_t* storagePtr = storage.get(); | 689 uint8_t* storagePtr = storage.get(); |
698 uint8_t* srcRow; | 690 uint8_t* srcRow; |
699 const int startRow = this->nextScanline(); | 691 const int startRow = this->nextScanline(); |
700 for (int i = 0; i < this->numberPasses(); i++) { | 692 for (int i = 0; i < this->numberPasses(); i++) { |
701 // read rows we planned to skip into garbage row | 693 // read rows we planned to skip into garbage row |
702 for (int y = 0; y < startRow; y++){ | 694 for (int y = 0; y < startRow; y++){ |
703 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); | 695 png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr); |
704 } | 696 } |
705 // read rows we care about into buffer | 697 // read rows we care about into buffer |
706 srcRow = storagePtr; | 698 srcRow = storagePtr; |
707 for (int y = 0; y < count; y++) { | 699 for (int y = 0; y < count; y++) { |
708 png_read_rows(this->png_ptr(), &srcRow, nullptr, 1); | 700 png_read_row(this->png_ptr(), srcRow, nullptr); |
709 srcRow += fSrcRowBytes; | 701 srcRow += fSrcRowBytes; |
710 } | 702 } |
711 // read rows we don't want into garbage buffer | 703 // read rows we don't want into garbage buffer |
712 for (int y = 0; y < fHeight - startRow - count; y++) { | 704 for (int y = 0; y < fHeight - startRow - count; y++) { |
713 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); | 705 png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr); |
714 } | 706 } |
715 } | 707 } |
716 //swizzle the rows we care about | 708 //swizzle the rows we care about |
717 srcRow = storagePtr; | 709 srcRow = storagePtr; |
718 void* dstRow = dst; | 710 void* dstRow = dst; |
719 for (int y = 0; y < count; y++) { | 711 for (int y = 0; y < count; y++) { |
720 this->swizzler()->swizzle(dstRow, srcRow); | 712 this->swizzler()->swizzle(dstRow, srcRow); |
721 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 713 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
722 srcRow += fSrcRowBytes; | 714 srcRow += fSrcRowBytes; |
723 } | 715 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
766 } | 758 } |
767 | 759 |
768 if (1 == numberPasses) { | 760 if (1 == numberPasses) { |
769 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk
Reader, | 761 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk
Reader, |
770 png_ptr, info_ptr, bitDepth); | 762 png_ptr, info_ptr, bitDepth); |
771 } | 763 } |
772 | 764 |
773 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(),
chunkReader, | 765 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(),
chunkReader, |
774 png_ptr, info_ptr, bitDepth, numbe
rPasses); | 766 png_ptr, info_ptr, bitDepth, numbe
rPasses); |
775 } | 767 } |
OLD | NEW |