Chromium Code Reviews| 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 "SkBitmap.h" | 8 #include "SkBitmap.h" |
| 9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| (...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 508 break; | 508 break; |
| 509 } | 509 } |
| 510 } | 510 } |
| 511 | 511 |
| 512 class SkPngNormalDecoder : public SkPngCodec { | 512 class SkPngNormalDecoder : public SkPngCodec { |
| 513 public: | 513 public: |
| 514 SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo, SkStream* stream, | 514 SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo, SkStream* stream, |
| 515 SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, i nt bitDepth) | 515 SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, i nt bitDepth) |
| 516 : INHERITED(info, imageInfo, stream, reader, png_ptr, info_ptr, bitDepth ) | 516 : INHERITED(info, imageInfo, stream, reader, png_ptr, info_ptr, bitDepth ) |
| 517 , fLinesDecoded(0) | 517 , fLinesDecoded(0) |
| 518 , fRowsWrittenToOutput(0) | |
| 518 , fDst(nullptr) | 519 , fDst(nullptr) |
| 519 , fRowBytes(0) | 520 , fRowBytes(0) |
| 520 , fFirstRow(0) | 521 , fFirstRow(0) |
| 521 , fLastRow(0) | 522 , fLastRow(0) |
| 522 {} | 523 {} |
| 523 | 524 |
| 524 static void AllRowsCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) { | 525 static void AllRowsCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) { |
| 525 GetDecoder(png_ptr)->allRowsCallback(row, rowNum); | 526 GetDecoder(png_ptr)->allRowsCallback(row, rowNum); |
| 526 } | 527 } |
| 527 | 528 |
| 528 static void RowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowN um, int /*pass*/) { | 529 static void RowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowN um, int /*pass*/) { |
| 529 GetDecoder(png_ptr)->rowCallback(row, rowNum); | 530 GetDecoder(png_ptr)->rowCallback(row, rowNum); |
| 530 } | 531 } |
| 531 | 532 |
| 532 #ifdef SK_GOOGLE3_PNG_HACK | 533 #ifdef SK_GOOGLE3_PNG_HACK |
| 533 static void RereadInfoCallback(png_structp png_ptr, png_infop) { | 534 static void RereadInfoCallback(png_structp png_ptr, png_infop) { |
| 534 GetDecoder(png_ptr)->rereadInfoCallback(); | 535 GetDecoder(png_ptr)->rereadInfoCallback(); |
| 535 } | 536 } |
| 536 #endif | 537 #endif |
| 537 | 538 |
| 538 private: | 539 private: |
| 539 int fLinesDecoded; // FIXME: Move to baseclass? | 540 // This represents the number of lines reported by libpng, minus any we skip ped at the |
| 541 // beginning. Only used when we are skipping lines (i.e. not in decodeAllRow s). | |
| 542 int fLinesDecoded; | |
| 543 // While fLinesDecoded include lines that we skipped, this only includes lin es written to the | |
| 544 // output so we can report it to the caller for filling. | |
| 545 // FIXME: Can we remove fLinesDecoded and just rely on fRowsWrittenToOutput? | |
|
msarett
2016/10/10 17:19:58
I think this would be good. IMO using this to cou
scroggo_chromium
2016/10/10 18:15:04
Agreed. I don't think it's terribly hard, but it's
| |
| 546 int fRowsWrittenToOutput; | |
| 540 void* fDst; | 547 void* fDst; |
| 541 size_t fRowBytes; | 548 size_t fRowBytes; |
| 542 | 549 |
| 543 // Variables for partial decode | 550 // Variables for partial decode |
| 544 int fFirstRow; // FIXME: Move to baseclass? | 551 int fFirstRow; // FIXME: Move to baseclass? |
| 545 int fLastRow; | 552 int fLastRow; |
| 546 | 553 |
| 547 typedef SkPngCodec INHERITED; | 554 typedef SkPngCodec INHERITED; |
| 548 | 555 |
| 549 static SkPngNormalDecoder* GetDecoder(png_structp png_ptr) { | 556 static SkPngNormalDecoder* GetDecoder(png_structp png_ptr) { |
| 550 return static_cast<SkPngNormalDecoder*>(png_get_progressive_ptr(png_ptr) ); | 557 return static_cast<SkPngNormalDecoder*>(png_get_progressive_ptr(png_ptr) ); |
| 551 } | 558 } |
| 552 | 559 |
| 553 Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override { | 560 Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override { |
| 554 const int height = this->getInfo().height(); | 561 const int height = this->getInfo().height(); |
| 555 png_progressive_info_ptr callback = nullptr; | 562 png_progressive_info_ptr callback = nullptr; |
| 556 #ifdef SK_GOOGLE3_PNG_HACK | 563 #ifdef SK_GOOGLE3_PNG_HACK |
| 557 callback = RereadInfoCallback; | 564 callback = RereadInfoCallback; |
| 558 #endif | 565 #endif |
| 559 png_set_progressive_read_fn(this->png_ptr(), this, callback, AllRowsCall back, nullptr); | 566 png_set_progressive_read_fn(this->png_ptr(), this, callback, AllRowsCall back, nullptr); |
| 560 fDst = dst; | 567 fDst = dst; |
| 561 fRowBytes = rowBytes; | 568 fRowBytes = rowBytes; |
| 562 | 569 |
| 563 fLinesDecoded = 0; | 570 fRowsWrittenToOutput = 0; |
| 564 | 571 |
| 565 this->processData(); | 572 this->processData(); |
| 566 | 573 |
| 567 if (fLinesDecoded == height) { | 574 if (fRowsWrittenToOutput == height) { |
| 568 return SkCodec::kSuccess; | 575 return SkCodec::kSuccess; |
| 569 } | 576 } |
| 570 | 577 |
| 571 if (rowsDecoded) { | 578 if (rowsDecoded) { |
| 572 *rowsDecoded = fLinesDecoded; | 579 *rowsDecoded = fRowsWrittenToOutput; |
| 573 } | 580 } |
| 574 | 581 |
| 575 return SkCodec::kIncompleteInput; | 582 return SkCodec::kIncompleteInput; |
| 576 } | 583 } |
| 577 | 584 |
| 578 void allRowsCallback(png_bytep row, int rowNum) { | 585 void allRowsCallback(png_bytep row, int rowNum) { |
| 579 SkASSERT(rowNum == fLinesDecoded); | 586 SkASSERT(rowNum == fLinesDecoded); |
| 580 fLinesDecoded++; | 587 fLinesDecoded++; |
| 581 this->applyXformRow(fDst, row); | 588 this->applyXformRow(fDst, row); |
| 582 fDst = SkTAddOffset<void>(fDst, fRowBytes); | 589 fDst = SkTAddOffset<void>(fDst, fRowBytes); |
| 583 } | 590 } |
| 584 | 591 |
| 585 void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) overrid e { | 592 void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) overrid e { |
| 586 png_progressive_info_ptr callback = nullptr; | 593 png_progressive_info_ptr callback = nullptr; |
| 587 #ifdef SK_GOOGLE3_PNG_HACK | 594 #ifdef SK_GOOGLE3_PNG_HACK |
| 588 callback = RereadInfoCallback; | 595 callback = RereadInfoCallback; |
| 589 #endif | 596 #endif |
| 590 png_set_progressive_read_fn(this->png_ptr(), this, callback, RowCallback , nullptr); | 597 png_set_progressive_read_fn(this->png_ptr(), this, callback, RowCallback , nullptr); |
| 591 fFirstRow = firstRow; | 598 fFirstRow = firstRow; |
| 592 fLastRow = lastRow; | 599 fLastRow = lastRow; |
| 593 fDst = dst; | 600 fDst = dst; |
| 594 fRowBytes = rowBytes; | 601 fRowBytes = rowBytes; |
| 595 fLinesDecoded = 0; | 602 fLinesDecoded = 0; |
| 603 fRowsWrittenToOutput = 0; | |
| 596 } | 604 } |
| 597 | 605 |
| 598 SkCodec::Result decode(int* rowsDecoded) override { | 606 SkCodec::Result decode(int* rowsDecoded) override { |
| 599 this->processData(); | 607 this->processData(); |
| 600 | 608 |
| 601 if (fLinesDecoded == fLastRow - fFirstRow + 1) { | 609 if (fLinesDecoded == fLastRow - fFirstRow + 1) { |
| 602 return SkCodec::kSuccess; | 610 return SkCodec::kSuccess; |
| 603 } | 611 } |
| 604 | 612 |
| 605 if (rowsDecoded) { | 613 if (rowsDecoded) { |
| 606 *rowsDecoded = fLinesDecoded; | 614 *rowsDecoded = fRowsWrittenToOutput; |
| 607 } | 615 } |
| 608 | 616 |
| 609 return SkCodec::kIncompleteInput; | 617 return SkCodec::kIncompleteInput; |
| 610 } | 618 } |
| 611 | 619 |
| 612 void rowCallback(png_bytep row, int rowNum) { | 620 void rowCallback(png_bytep row, int rowNum) { |
| 613 if (rowNum < fFirstRow) { | 621 if (rowNum < fFirstRow) { |
| 614 // Ignore this row. | 622 // Ignore this row. |
| 615 return; | 623 return; |
| 616 } | 624 } |
| 617 | 625 |
| 618 SkASSERT(rowNum <= fLastRow); | 626 SkASSERT(rowNum <= fLastRow); |
| 619 | 627 |
| 620 // If there is no swizzler, all rows are needed. | 628 // If there is no swizzler, all rows are needed. |
| 621 if (!this->swizzler() || this->swizzler()->rowNeeded(fLinesDecoded)) { | 629 if (!this->swizzler() || this->swizzler()->rowNeeded(fLinesDecoded)) { |
| 622 this->applyXformRow(fDst, row); | 630 this->applyXformRow(fDst, row); |
| 623 fDst = SkTAddOffset<void>(fDst, fRowBytes); | 631 fDst = SkTAddOffset<void>(fDst, fRowBytes); |
| 632 fRowsWrittenToOutput++; | |
| 624 } | 633 } |
| 625 | 634 |
| 626 fLinesDecoded++; | 635 fLinesDecoded++; |
| 627 | 636 |
| 628 if (rowNum == fLastRow) { | 637 if (rowNum == fLastRow) { |
| 629 // Fake error to stop decoding scanlines. | 638 // Fake error to stop decoding scanlines. |
| 630 longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding); | 639 longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding); |
| 631 } | 640 } |
| 632 } | 641 } |
| 633 }; | 642 }; |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 763 // Now apply Xforms on all the rows that were decoded. | 772 // Now apply Xforms on all the rows that were decoded. |
| 764 if (!fLinesDecoded) { | 773 if (!fLinesDecoded) { |
| 765 if (rowsDecoded) { | 774 if (rowsDecoded) { |
| 766 *rowsDecoded = 0; | 775 *rowsDecoded = 0; |
| 767 } | 776 } |
| 768 return SkCodec::kIncompleteInput; | 777 return SkCodec::kIncompleteInput; |
| 769 } | 778 } |
| 770 const int lastRow = fLinesDecoded + fFirstRow - 1; | 779 const int lastRow = fLinesDecoded + fFirstRow - 1; |
| 771 SkASSERT(lastRow <= fLastRow); | 780 SkASSERT(lastRow <= fLastRow); |
| 772 | 781 |
| 782 int rowsWrittenToOutput = 0; | |
| 783 | |
| 773 // FIXME: For resuming interlace, we may swizzle a row that hasn't chang ed. But it | 784 // FIXME: For resuming interlace, we may swizzle a row that hasn't chang ed. But it |
| 774 // may be too tricky/expensive to handle that correctly. | 785 // may be too tricky/expensive to handle that correctly. |
| 775 png_bytep srcRow = fInterlaceBuffer.get(); | 786 png_bytep srcRow = fInterlaceBuffer.get(); |
| 776 const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1; | 787 const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1; |
| 777 void* dst = fDst; | 788 void* dst = fDst; |
| 778 for (int rowNum = fFirstRow; rowNum <= lastRow; rowNum += sampleY) { | 789 for (int rowNum = fFirstRow; rowNum <= lastRow; rowNum += sampleY) { |
| 779 this->applyXformRow(dst, srcRow); | 790 this->applyXformRow(dst, srcRow); |
| 780 dst = SkTAddOffset<void>(dst, fRowBytes); | 791 dst = SkTAddOffset<void>(dst, fRowBytes); |
| 781 srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes * sampleY); | 792 srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes * sampleY); |
| 793 rowsWrittenToOutput++; | |
| 782 } | 794 } |
| 783 | 795 |
| 784 if (fInterlacedComplete) { | 796 if (fInterlacedComplete) { |
| 785 return SkCodec::kSuccess; | 797 return SkCodec::kSuccess; |
| 786 } | 798 } |
| 787 | 799 |
| 788 if (rowsDecoded) { | 800 if (rowsDecoded) { |
| 789 *rowsDecoded = fLinesDecoded; | 801 *rowsDecoded = rowsWrittenToOutput; |
| 790 } | 802 } |
| 791 return SkCodec::kIncompleteInput; | 803 return SkCodec::kIncompleteInput; |
| 792 } | 804 } |
| 793 | 805 |
| 794 void setUpInterlaceBuffer(int height) { | 806 void setUpInterlaceBuffer(int height) { |
| 795 fPng_rowbytes = png_get_rowbytes(this->png_ptr(), this->info_ptr()); | 807 fPng_rowbytes = png_get_rowbytes(this->png_ptr(), this->info_ptr()); |
| 796 fInterlaceBuffer.reset(fPng_rowbytes * height); | 808 fInterlaceBuffer.reset(fPng_rowbytes * height); |
| 797 fInterlacedComplete = false; | 809 fInterlacedComplete = false; |
| 798 } | 810 } |
| 799 }; | 811 }; |
| (...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1302 SkCodec* outCodec = nullptr; | 1314 SkCodec* outCodec = nullptr; |
| 1303 if (read_header(streamDeleter.get(), chunkReader, &outCodec, nullptr, nullpt r)) { | 1315 if (read_header(streamDeleter.get(), chunkReader, &outCodec, nullptr, nullpt r)) { |
| 1304 // Codec has taken ownership of the stream. | 1316 // Codec has taken ownership of the stream. |
| 1305 SkASSERT(outCodec); | 1317 SkASSERT(outCodec); |
| 1306 streamDeleter.release(); | 1318 streamDeleter.release(); |
| 1307 return outCodec; | 1319 return outCodec; |
| 1308 } | 1320 } |
| 1309 | 1321 |
| 1310 return nullptr; | 1322 return nullptr; |
| 1311 } | 1323 } |
| OLD | NEW |