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" |
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 // Check for supported color types | 418 // Check for supported color types |
419 switch (dst.colorType()) { | 419 switch (dst.colorType()) { |
420 case kN32_SkColorType: | 420 case kN32_SkColorType: |
421 return true; | 421 return true; |
422 default: | 422 default: |
423 return dst.colorType() == src.colorType(); | 423 return dst.colorType() == src.colorType(); |
424 } | 424 } |
425 } | 425 } |
426 | 426 |
427 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, | 427 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, |
428 void* dst, size_t rowBytes, | |
429 const Options& options, | 428 const Options& options, |
430 SkPMColor ctable[], | 429 SkPMColor ctable[], |
431 int* ctableCount) { | 430 int* ctableCount) { |
432 // FIXME: Could we use the return value of setjmp to specify the type of | 431 // FIXME: Could we use the return value of setjmp to specify the type of |
433 // error? | 432 // error? |
434 if (setjmp(png_jmpbuf(fPng_ptr))) { | 433 if (setjmp(png_jmpbuf(fPng_ptr))) { |
435 SkCodecPrintf("setjmp long jump!\n"); | 434 SkCodecPrintf("setjmp long jump!\n"); |
436 return kInvalidInput; | 435 return kInvalidInput; |
437 } | 436 } |
438 fNumberPasses = png_set_interlace_handling(fPng_ptr); | 437 fNumberPasses = png_set_interlace_handling(fPng_ptr); |
(...skipping 28 matching lines...) Expand all Loading... |
467 //would have exited before now if the colorType was supported by png | 466 //would have exited before now if the colorType was supported by png |
468 SkASSERT(false); | 467 SkASSERT(false); |
469 } | 468 } |
470 | 469 |
471 // Copy the color table to the client if they request kIndex8 mode | 470 // Copy the color table to the client if they request kIndex8 mode |
472 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); | 471 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); |
473 | 472 |
474 // Create the swizzler. SkPngCodec retains ownership of the color table. | 473 // Create the swizzler. SkPngCodec retains ownership of the color table. |
475 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; | 474 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; |
476 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo
, | 475 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo
, |
477 dst, rowBytes, options.fZeroInitialized)); | 476 options.fZeroInitialized)); |
478 if (!fSwizzler) { | 477 if (!fSwizzler) { |
479 // FIXME: CreateSwizzler could fail for another reason. | 478 // FIXME: CreateSwizzler could fail for another reason. |
480 return kUnimplemented; | 479 return kUnimplemented; |
481 } | 480 } |
482 return kSuccess; | 481 return kSuccess; |
483 } | 482 } |
484 | 483 |
485 | 484 |
486 bool SkPngCodec::handleRewind() { | 485 bool SkPngCodec::handleRewind() { |
487 switch (this->rewindIfNeeded()) { | 486 switch (this->rewindIfNeeded()) { |
(...skipping 17 matching lines...) Expand all Loading... |
505 } | 504 } |
506 return false; | 505 return false; |
507 } | 506 } |
508 default: | 507 default: |
509 SkASSERT(false); | 508 SkASSERT(false); |
510 return false; | 509 return false; |
511 } | 510 } |
512 } | 511 } |
513 | 512 |
514 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, | 513 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, |
515 size_t rowBytes, const Options& options, | 514 size_t dstRowBytes, const Options& optio
ns, |
516 SkPMColor ctable[], int* ctableCount) { | 515 SkPMColor ctable[], int* ctableCount) { |
517 if (!conversion_possible(requestedInfo, this->getInfo())) { | 516 if (!conversion_possible(requestedInfo, this->getInfo())) { |
518 return kInvalidConversion; | 517 return kInvalidConversion; |
519 } | 518 } |
520 if (options.fSubset) { | 519 if (options.fSubset) { |
521 // Subsets are not supported. | 520 // Subsets are not supported. |
522 return kUnimplemented; | 521 return kUnimplemented; |
523 } | 522 } |
524 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { | 523 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { |
525 return kInvalidScale; | 524 return kInvalidScale; |
526 } | 525 } |
527 if (!this->handleRewind()) { | 526 if (!this->handleRewind()) { |
528 return kCouldNotRewind; | 527 return kCouldNotRewind; |
529 } | 528 } |
530 | 529 |
531 // Note that ctable and ctableCount may be modified if there is a color tabl
e | 530 // Note that ctable and ctableCount may be modified if there is a color tabl
e |
532 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, | 531 const Result result = this->initializeSwizzler(requestedInfo, options, |
533 options, ctable, ctableCount)
; | 532 ctable, ctableCount); |
534 if (result != kSuccess) { | 533 if (result != kSuccess) { |
535 return result; | 534 return result; |
536 } | 535 } |
537 // FIXME: Could we use the return value of setjmp to specify the type of | 536 // FIXME: Could we use the return value of setjmp to specify the type of |
538 // error? | 537 // error? |
539 if (setjmp(png_jmpbuf(fPng_ptr))) { | 538 if (setjmp(png_jmpbuf(fPng_ptr))) { |
540 SkCodecPrintf("setjmp long jump!\n"); | 539 SkCodecPrintf("setjmp long jump!\n"); |
541 return kInvalidInput; | 540 return kInvalidInput; |
542 } | 541 } |
543 | 542 |
544 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 543 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
545 SkAutoMalloc storage; | 544 SkAutoMalloc storage; |
| 545 void* dstRow = dst; |
546 if (fNumberPasses > 1) { | 546 if (fNumberPasses > 1) { |
547 const int width = requestedInfo.width(); | 547 const int width = requestedInfo.width(); |
548 const int height = requestedInfo.height(); | 548 const int height = requestedInfo.height(); |
549 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); | 549 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); |
550 const size_t rowBytes = width * bpp; | 550 const size_t srcRowBytes = width * bpp; |
551 | 551 |
552 storage.reset(width * height * bpp); | 552 storage.reset(width * height * bpp); |
553 uint8_t* const base = static_cast<uint8_t*>(storage.get()); | 553 uint8_t* const base = static_cast<uint8_t*>(storage.get()); |
554 | 554 |
555 for (int i = 0; i < fNumberPasses; i++) { | 555 for (int i = 0; i < fNumberPasses; i++) { |
556 uint8_t* row = base; | 556 uint8_t* srcRow = base; |
557 for (int y = 0; y < height; y++) { | 557 for (int y = 0; y < height; y++) { |
558 uint8_t* bmRow = row; | 558 uint8_t* bmRow = srcRow; |
559 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); | 559 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); |
560 row += rowBytes; | 560 srcRow += srcRowBytes; |
561 } | 561 } |
562 } | 562 } |
563 | 563 |
564 // Now swizzle it. | 564 // Now swizzle it. |
565 uint8_t* row = base; | 565 uint8_t* srcRow = base; |
566 for (int y = 0; y < height; y++) { | 566 for (int y = 0; y < height; y++) { |
567 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->next(row)); | 567 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow,
srcRow)); |
568 row += rowBytes; | 568 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
| 569 srcRow += srcRowBytes; |
569 } | 570 } |
570 } else { | 571 } else { |
571 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf
ig)); | 572 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf
ig)); |
572 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); | 573 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); |
573 for (int y = 0; y < requestedInfo.height(); y++) { | 574 for (int y = 0; y < requestedInfo.height(); y++) { |
574 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); | 575 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); |
575 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->next(srcRow)); | 576 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow,
srcRow)); |
| 577 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
576 } | 578 } |
577 } | 579 } |
578 | 580 |
579 // FIXME: do we need substituteTranspColor? Note that we cannot do it for | 581 // FIXME: do we need substituteTranspColor? Note that we cannot do it for |
580 // scanline decoding, but we could do it here. Alternatively, we could do | 582 // scanline decoding, but we could do it here. Alternatively, we could do |
581 // it as we go, instead of in post-processing like SkPNGImageDecoder. | 583 // it as we go, instead of in post-processing like SkPNGImageDecoder. |
582 | 584 |
583 if (setjmp(png_jmpbuf(fPng_ptr))) { | 585 if (setjmp(png_jmpbuf(fPng_ptr))) { |
584 // We've already read all the scanlines. This is a success. | 586 // We've already read all the scanlines. This is a success. |
585 return kSuccess; | 587 return kSuccess; |
(...skipping 14 matching lines...) Expand all Loading... |
600 fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC
onfig)); | 602 fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC
onfig)); |
601 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | 603 fSrcRow = static_cast<uint8_t*>(fStorage.get()); |
602 } | 604 } |
603 | 605 |
604 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri
de { | 606 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri
de { |
605 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 607 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
606 SkCodecPrintf("setjmp long jump!\n"); | 608 SkCodecPrintf("setjmp long jump!\n"); |
607 return SkCodec::kInvalidInput; | 609 return SkCodec::kInvalidInput; |
608 } | 610 } |
609 | 611 |
| 612 void* dstRow = dst; |
610 for (int i = 0; i < count; i++) { | 613 for (int i = 0; i < count; i++) { |
611 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | 614 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); |
612 fCodec->fSwizzler->setDstRow(dst); | 615 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow
, fSrcRow)); |
613 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(fSrcRow))
; | 616 dstRow = SkTAddOffset<void>(dstRow, rowBytes); |
614 dst = SkTAddOffset<void>(dst, rowBytes); | |
615 } | 617 } |
616 return SkCodec::kSuccess; | 618 return SkCodec::kSuccess; |
617 } | 619 } |
618 | 620 |
619 SkCodec::Result onSkipScanlines(int count) override { | 621 SkCodec::Result onSkipScanlines(int count) override { |
620 // FIXME: Could we use the return value of setjmp to specify the type of | 622 // FIXME: Could we use the return value of setjmp to specify the type of |
621 // error? | 623 // error? |
622 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 624 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
623 SkCodecPrintf("setjmp long jump!\n"); | 625 SkCodecPrintf("setjmp long jump!\n"); |
624 return SkCodec::kInvalidInput; | 626 return SkCodec::kInvalidInput; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
683 png_read_rows(fCodec->fPng_ptr, &srcRow, png_bytepp_NULL, 1); | 685 png_read_rows(fCodec->fPng_ptr, &srcRow, png_bytepp_NULL, 1); |
684 srcRow += fSrcRowBytes; | 686 srcRow += fSrcRowBytes; |
685 } | 687 } |
686 //read rows we don't want into garbage buffer | 688 //read rows we don't want into garbage buffer |
687 for (int y = 0; y < fHeight - fCurrentRow - count; y++) { | 689 for (int y = 0; y < fHeight - fCurrentRow - count; y++) { |
688 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL
, 1); | 690 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL
, 1); |
689 } | 691 } |
690 } | 692 } |
691 //swizzle the rows we care about | 693 //swizzle the rows we care about |
692 srcRow = storagePtr; | 694 srcRow = storagePtr; |
| 695 void* dstRow = dst; |
693 for (int y = 0; y < count; y++) { | 696 for (int y = 0; y < count; y++) { |
694 fCodec->fSwizzler->setDstRow(dst); | 697 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow
, srcRow)); |
695 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(srcRow)); | 698 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
696 dst = SkTAddOffset<void>(dst, dstRowBytes); | |
697 srcRow += fSrcRowBytes; | 699 srcRow += fSrcRowBytes; |
698 } | 700 } |
699 fCurrentRow += count; | 701 fCurrentRow += count; |
700 return SkCodec::kSuccess; | 702 return SkCodec::kSuccess; |
701 } | 703 } |
702 | 704 |
703 SkCodec::Result onSkipScanlines(int count) override { | 705 SkCodec::Result onSkipScanlines(int count) override { |
704 //when ongetScanlines is called it will skip to fCurrentRow | 706 //when ongetScanlines is called it will skip to fCurrentRow |
705 fCurrentRow += count; | 707 fCurrentRow += count; |
706 return SkCodec::kSuccess; | 708 return SkCodec::kSuccess; |
(...skipping 27 matching lines...) Expand all Loading... |
734 // Create a new SkPngCodec, to be owned by the scanline decoder. | 736 // Create a new SkPngCodec, to be owned by the scanline decoder. |
735 SkStream* stream = this->stream()->duplicate(); | 737 SkStream* stream = this->stream()->duplicate(); |
736 if (!stream) { | 738 if (!stream) { |
737 return NULL; | 739 return NULL; |
738 } | 740 } |
739 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro
mStream(stream))); | 741 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro
mStream(stream))); |
740 if (!codec) { | 742 if (!codec) { |
741 return NULL; | 743 return NULL; |
742 } | 744 } |
743 | 745 |
744 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee
ded, | 746 if (codec->initializeSwizzler(dstInfo, options, ctable, ctableCount) != kSuc
cess) { |
745 // since we'll be manually updating the dstRow, but the SkSwizzler requires
it to | |
746 // be at least dstInfo.minRowBytes. | |
747 if (codec->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options,
ctable, | |
748 ctableCount) != kSuccess) { | |
749 SkCodecPrintf("failed to initialize the swizzler.\n"); | 747 SkCodecPrintf("failed to initialize the swizzler.\n"); |
750 return NULL; | 748 return NULL; |
751 } | 749 } |
752 | 750 |
753 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); | 751 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); |
754 if (codec->fNumberPasses > 1) { | 752 if (codec->fNumberPasses > 1) { |
755 // interlaced image | 753 // interlaced image |
756 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, codec.detach
())); | 754 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, codec.detach
())); |
757 } | 755 } |
758 | 756 |
759 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, codec.detach())); | 757 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, codec.detach())); |
760 } | 758 } |
761 | 759 |
OLD | NEW |