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 "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 |