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 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
419 fSrcConfig = SkSwizzler::kRGBA; | 419 fSrcConfig = SkSwizzler::kRGBA; |
420 } | 420 } |
421 } | 421 } |
422 break; | 422 break; |
423 } | 423 } |
424 default: | 424 default: |
425 // We will always recommend one of the above colorTypes. | 425 // We will always recommend one of the above colorTypes. |
426 SkASSERT(false); | 426 SkASSERT(false); |
427 } | 427 } |
428 | 428 |
429 // If we are not performing a subset decode, and the swizzle will not change the | |
430 // number of bytes per pixel, we can swizzle in place. | |
431 fInPlaceSwizzle = (SkSwizzler::BytesPerPixel(fSrcConfig) == | |
432 SkColorTypeBytesPerPixel(requestedInfo.colorType()) && !options.fSub set); | |
433 | |
429 // Copy the color table to the client if they request kIndex8 mode | 434 // Copy the color table to the client if they request kIndex8 mode |
430 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); | 435 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); |
431 | 436 |
432 // Create the swizzler. SkPngCodec retains ownership of the color table. | 437 // Create the swizzler. SkPngCodec retains ownership of the color table. |
433 const SkPMColor* colors = get_color_ptr(fColorTable.get()); | 438 const SkPMColor* colors = get_color_ptr(fColorTable.get()); |
434 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , options)); | 439 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , options)); |
435 SkASSERT(fSwizzler); | 440 SkASSERT(fSwizzler); |
436 | 441 |
437 return kSuccess; | 442 return kSuccess; |
438 } | 443 } |
(...skipping 29 matching lines...) Expand all Loading... | |
468 if (options.fSubset) { | 473 if (options.fSubset) { |
469 // Subsets are not supported. | 474 // Subsets are not supported. |
470 return kUnimplemented; | 475 return kUnimplemented; |
471 } | 476 } |
472 | 477 |
473 // Note that ctable and ctableCount may be modified if there is a color tabl e | 478 // Note that ctable and ctableCount may be modified if there is a color tabl e |
474 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl e, ctableCount); | 479 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl e, ctableCount); |
475 if (result != kSuccess) { | 480 if (result != kSuccess) { |
476 return result; | 481 return result; |
477 } | 482 } |
483 | |
484 const int width = requestedInfo.width(); | |
485 const int height = requestedInfo.height(); | |
486 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); | |
487 | |
478 // FIXME: Could we use the return value of setjmp to specify the type of | 488 // FIXME: Could we use the return value of setjmp to specify the type of |
479 // error? | 489 // error? |
480 int row = 0; | 490 int row = 0; |
481 // This must be declared above the call to setjmp to avoid memory leaks on i ncomplete images. | 491 // This must be declared above the call to setjmp to avoid memory leaks on i ncomplete images. |
482 SkAutoTMalloc<uint8_t> storage; | 492 SkAutoTMalloc<uint8_t> storage; |
483 if (setjmp(png_jmpbuf(fPng_ptr))) { | 493 if (setjmp(png_jmpbuf(fPng_ptr))) { |
484 // Assume that any error that occurs while reading rows is caused by an incomplete input. | 494 // Assume that any error that occurs while reading rows is caused by an incomplete input. |
485 if (fNumberPasses > 1) { | 495 if (fNumberPasses > 1) { |
486 // FIXME (msarett): Handle incomplete interlaced pngs. | 496 // FIXME (msarett): Handle incomplete interlaced pngs. |
487 return kInvalidInput; | 497 return row == height ? kSuccess : kInvalidInput; |
488 } | 498 } |
489 // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium, | 499 // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium, |
490 // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192 | 500 // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192 |
491 // bytes), and if we can't fill the buffer, we immediately fail. | 501 // bytes), and if we can't fill the buffer, we immediately fail. |
492 // For example, if we try to read 8192 bytes, and the image (incorrectly ) only contains | 502 // For example, if we try to read 8192 bytes, and the image (incorrectly ) only contains |
493 // half that, which may have been enough to contain a non-zero number of lines, we fail | 503 // half that, which may have been enough to contain a non-zero number of lines, we fail |
494 // when we could have decoded a few more lines and then failed. | 504 // when we could have decoded a few more lines and then failed. |
495 // The read function that we provide for libpng has no way of indicating that we have | 505 // The read function that we provide for libpng has no way of indicating that we have |
496 // made a partial read. | 506 // made a partial read. |
497 // Making our buffer size smaller improves our incomplete decodes, but w hat impact does | 507 // Making our buffer size smaller improves our incomplete decodes, but w hat impact does |
498 // it have on regular decode performance? Should we investigate using a different API | 508 // it have on regular decode performance? Should we investigate using a different API |
499 // instead of png_read_row(s)? Chromium uses png_process_data. | 509 // instead of png_read_row(s)? Chromium uses png_process_data. |
500 *rowsDecoded = row; | 510 *rowsDecoded = row; |
501 return kIncompleteInput; | 511 return row == height ? kSuccess : kIncompleteInput; |
502 } | 512 } |
503 | 513 |
504 // FIXME: We could split these out based on subclass. | 514 // FIXME: We could split these out based on subclass. |
505 void* dstRow = dst; | 515 void* dstRow = dst; |
506 if (fNumberPasses > 1) { | 516 if (fNumberPasses > 1) { |
507 const int width = requestedInfo.width(); | 517 uint8_t* const base = fInPlaceSwizzle ? (uint8_t*) dstRow : |
508 const int height = requestedInfo.height(); | 518 storage.reset(width * height * bpp); |
509 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); | 519 const size_t srcRowBytes = fInPlaceSwizzle ? dstRowBytes : width * bpp; |
510 const size_t srcRowBytes = width * bpp; | |
511 | |
512 storage.reset(width * height * bpp); | |
513 uint8_t* const base = storage.get(); | |
514 | 520 |
515 for (int i = 0; i < fNumberPasses; i++) { | 521 for (int i = 0; i < fNumberPasses; i++) { |
516 uint8_t* srcRow = base; | 522 uint8_t* srcRow = base; |
517 for (int y = 0; y < height; y++) { | 523 for (int y = 0; y < height; y++) { |
518 uint8_t* bmRow = srcRow; | 524 png_read_rows(fPng_ptr, &srcRow, nullptr, 1); |
519 png_read_rows(fPng_ptr, &bmRow, nullptr, 1); | |
520 srcRow += srcRowBytes; | 525 srcRow += srcRowBytes; |
521 } | 526 } |
522 } | 527 } |
523 | 528 |
524 // Now swizzle it. | 529 // Now swizzle it. |
525 uint8_t* srcRow = base; | 530 uint8_t* srcRow = base; |
526 for (int y = 0; y < height; y++) { | 531 for (int y = 0; y < height; y++) { |
527 fSwizzler->swizzle(dstRow, srcRow); | 532 fSwizzler->swizzle(dstRow, srcRow); |
msarett
2016/02/05 20:48:18
Problem:
I think this will still perform a functi
| |
528 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 533 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
529 srcRow += srcRowBytes; | 534 srcRow += srcRowBytes; |
530 } | 535 } |
531 } else { | 536 } else { |
532 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); | 537 uint8_t* srcRow = fInPlaceSwizzle ? (uint8_t*) dstRow : storage.reset(wi dth * bpp); |
533 uint8_t* srcRow = storage.get(); | 538 const size_t srcRowBytes = fInPlaceSwizzle ? dstRowBytes : 0; |
534 for (; row < requestedInfo.height(); row++) { | 539 for (; row < requestedInfo.height(); row++) { |
535 png_read_rows(fPng_ptr, &srcRow, nullptr, 1); | 540 png_read_rows(fPng_ptr, &srcRow, nullptr, 1); |
536 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines. | |
537 fSwizzler->swizzle(dstRow, srcRow); | 541 fSwizzler->swizzle(dstRow, srcRow); |
538 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 542 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
543 srcRow += srcRowBytes; | |
539 } | 544 } |
540 } | 545 } |
541 | 546 |
542 if (setjmp(png_jmpbuf(fPng_ptr))) { | |
543 // We've already read all the scanlines. This is a success. | |
544 return kSuccess; | |
545 } | |
546 | |
547 // read rest of file, and get additional comment and time chunks in info_ptr | 547 // read rest of file, and get additional comment and time chunks in info_ptr |
548 png_read_end(fPng_ptr, fInfo_ptr); | 548 png_read_end(fPng_ptr, fInfo_ptr); |
549 | 549 |
550 return kSuccess; | 550 return kSuccess; |
551 } | 551 } |
552 | 552 |
553 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { | 553 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { |
554 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 554 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
555 if (colorPtr) { | 555 if (colorPtr) { |
556 return get_color_table_fill_value(colorType, colorPtr, 0); | 556 return get_color_table_fill_value(colorType, colorPtr, 0); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
588 int onGetScanlines(void* dst, int count, size_t rowBytes) override { | 588 int onGetScanlines(void* dst, int count, size_t rowBytes) override { |
589 // Assume that an error in libpng indicates an incomplete input. | 589 // Assume that an error in libpng indicates an incomplete input. |
590 int row = 0; | 590 int row = 0; |
591 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 591 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
592 SkCodecPrintf("setjmp long jump!\n"); | 592 SkCodecPrintf("setjmp long jump!\n"); |
593 return row; | 593 return row; |
594 } | 594 } |
595 | 595 |
596 void* dstRow = dst; | 596 void* dstRow = dst; |
597 for (; row < count; row++) { | 597 for (; row < count; row++) { |
598 png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1); | 598 uint8_t* srcRow = this->inPlaceSwizzle() ? (uint8_t*) dstRow : fSrcR ow; |
599 this->swizzler()->swizzle(dstRow, fSrcRow); | 599 png_read_rows(this->png_ptr(), &srcRow, nullptr, 1); |
600 this->swizzler()->swizzle(dstRow, srcRow); | |
600 dstRow = SkTAddOffset<void>(dstRow, rowBytes); | 601 dstRow = SkTAddOffset<void>(dstRow, rowBytes); |
601 } | 602 } |
602 | 603 |
603 return row; | 604 return row; |
604 } | 605 } |
605 | 606 |
606 bool onSkipScanlines(int count) override { | 607 bool onSkipScanlines(int count) override { |
607 // Assume that an error in libpng indicates an incomplete input. | 608 // Assume that an error in libpng indicates an incomplete input. |
608 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 609 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
609 SkCodecPrintf("setjmp long jump!\n"); | 610 SkCodecPrintf("setjmp long jump!\n"); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
683 this->updateCurrScanline(currScanline); | 684 this->updateCurrScanline(currScanline); |
684 } | 685 } |
685 | 686 |
686 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 687 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
687 SkCodecPrintf("setjmp long jump!\n"); | 688 SkCodecPrintf("setjmp long jump!\n"); |
688 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass, | 689 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass, |
689 // we may be able to report that all of the memory has been initiali zed. Even if we | 690 // we may be able to report that all of the memory has been initiali zed. Even if we |
690 // fail on the first pass, we can still report than some scanlines a re initialized. | 691 // fail on the first pass, we can still report than some scanlines a re initialized. |
691 return 0; | 692 return 0; |
692 } | 693 } |
693 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes); | 694 SkAutoTMalloc<uint8_t> storage; |
694 uint8_t* storagePtr = storage.get(); | 695 uint8_t* const base = this->inPlaceSwizzle() ? (uint8_t*) dst : |
696 storage.reset(count * fSrcRowBytes); | |
697 const size_t srcRowBytes = this->inPlaceSwizzle() ? dstRowBytes : fSrcRo wBytes; | |
695 uint8_t* srcRow; | 698 uint8_t* srcRow; |
696 const int startRow = this->nextScanline(); | 699 const int startRow = this->nextScanline(); |
697 for (int i = 0; i < this->numberPasses(); i++) { | 700 for (int i = 0; i < this->numberPasses(); i++) { |
698 // read rows we planned to skip into garbage row | 701 // read rows we planned to skip into garbage row |
699 for (int y = 0; y < startRow; y++){ | 702 for (int y = 0; y < startRow; y++){ |
700 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); | 703 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); |
701 } | 704 } |
702 // read rows we care about into buffer | 705 // read rows we care about into buffer |
703 srcRow = storagePtr; | 706 uint8_t* srcRow = base; |
704 for (int y = 0; y < count; y++) { | 707 for (int y = 0; y < count; y++) { |
705 png_read_rows(this->png_ptr(), &srcRow, nullptr, 1); | 708 png_read_rows(this->png_ptr(), &srcRow, nullptr, 1); |
706 srcRow += fSrcRowBytes; | 709 srcRow += srcRowBytes; |
707 } | 710 } |
708 // read rows we don't want into garbage buffer | 711 // read rows we don't want into garbage buffer |
709 for (int y = 0; y < fHeight - startRow - count; y++) { | 712 for (int y = 0; y < fHeight - startRow - count; y++) { |
710 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); | 713 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); |
711 } | 714 } |
712 } | 715 } |
713 //swizzle the rows we care about | 716 //swizzle the rows we care about |
714 srcRow = storagePtr; | 717 srcRow = base; |
715 void* dstRow = dst; | 718 void* dstRow = dst; |
716 for (int y = 0; y < count; y++) { | 719 for (int y = 0; y < count; y++) { |
717 this->swizzler()->swizzle(dstRow, srcRow); | 720 this->swizzler()->swizzle(dstRow, srcRow); |
718 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 721 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
719 srcRow += fSrcRowBytes; | 722 srcRow += srcRowBytes; |
720 } | 723 } |
721 | 724 |
722 return count; | 725 return count; |
723 } | 726 } |
724 | 727 |
725 bool onSkipScanlines(int count) override { | 728 bool onSkipScanlines(int count) override { |
726 // The non-virtual version will update fCurrScanline. | 729 // The non-virtual version will update fCurrScanline. |
727 return true; | 730 return true; |
728 } | 731 } |
729 | 732 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
763 } | 766 } |
764 | 767 |
765 if (1 == numberPasses) { | 768 if (1 == numberPasses) { |
766 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, | 769 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, |
767 png_ptr, info_ptr, bitDepth); | 770 png_ptr, info_ptr, bitDepth); |
768 } | 771 } |
769 | 772 |
770 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, | 773 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, |
771 png_ptr, info_ptr, bitDepth, numbe rPasses); | 774 png_ptr, info_ptr, bitDepth, numbe rPasses); |
772 } | 775 } |
OLD | NEW |