Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/codec/SkPngCodec.cpp

Issue 2279313003: Make swizzler optional for SkPngCodec, refactor xforms (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Less spacing Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/codec/SkPngCodec.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 362 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 case kBGRA_8888_SkColorType: 373 case kBGRA_8888_SkColorType:
374 case kRGBA_F16_SkColorType: 374 case kRGBA_F16_SkColorType:
375 return true; 375 return true;
376 case kRGB_565_SkColorType: 376 case kRGB_565_SkColorType:
377 return kOpaque_SkAlphaType == src.alphaType(); 377 return kOpaque_SkAlphaType == src.alphaType();
378 default: 378 default:
379 return dst.colorType() == src.colorType(); 379 return dst.colorType() == src.colorType();
380 } 380 }
381 } 381 }
382 382
383 void SkPngCodec::allocateStorage() { 383 void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) {
384 size_t colorXformBytes = fColorXform ? fSwizzler->swizzleWidth() * sizeof(ui nt32_t) : 0; 384 switch (fXformMode) {
385 385 case kSwizzleOnly_XformMode:
386 fStorage.reset(SkAlign4(fSrcRowBytes) + colorXformBytes); 386 fStorage.reset(SkAlign4(fSrcRowBytes));
387 fSwizzlerSrcRow = fStorage.get(); 387 fSwizzlerSrcRow = fStorage.get();
388 fColorXformSrcRow = 388 break;
389 fColorXform ? SkTAddOffset<uint32_t>(fSwizzlerSrcRow, SkAlign4(fSrcR owBytes)) : 0; 389 case kColorOnly_XformMode:
390 // Intentional fall through. A swizzler hasn't been created yet, bu t one will
391 // be created later if we are sampling. We'll go ahead and allocate
392 // enough memory to swizzle if necessary.
393 case kSwizzleColor_XformMode: {
394 size_t colorXformBytes = dstInfo.width() * sizeof(uint32_t);
395 fStorage.reset(SkAlign4(fSrcRowBytes) + colorXformBytes);
396 fSwizzlerSrcRow = fStorage.get();
397 fColorXformSrcRow = SkTAddOffset<uint32_t>(fSwizzlerSrcRow, SkAlign4 (fSrcRowBytes));
398 break;
399 }
400 }
390 } 401 }
391 402
392 static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo ::Color srcColor) { 403 void SkPngCodec::applyXformRow(void* dst, const void* src, SkColorType colorType ,
393 // We will apply the color xform when reading the color table, unless F16 is requested. 404 SkAlphaType alphaType, int width) {
394 return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType; 405 switch (fXformMode) {
406 case kSwizzleOnly_XformMode:
407 fSwizzler->swizzle(dst, (const uint8_t*) src);
408 break;
409 case kColorOnly_XformMode:
410 fColorXform->apply(dst, (const uint32_t*) src, width, colorType, alp haType);
411 break;
412 case kSwizzleColor_XformMode:
413 fSwizzler->swizzle(fColorXformSrcRow, (const uint8_t*) src);
414 fColorXform->apply(dst, fColorXformSrcRow, width, colorType, alphaTy pe);
415 break;
416 }
395 } 417 }
396 418
397 class SkPngNormalCodec : public SkPngCodec { 419 class SkPngNormalCodec : public SkPngCodec {
398 public: 420 public:
399 SkPngNormalCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageI nfo, 421 SkPngNormalCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageI nfo,
400 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr , 422 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr ,
401 png_infop info_ptr, int bitDepth) 423 png_infop info_ptr, int bitDepth)
402 : INHERITED(encodedInfo, imageInfo, stream, chunkReader, png_ptr, info_p tr, bitDepth, 1) 424 : INHERITED(encodedInfo, imageInfo, stream, chunkReader, png_ptr, info_p tr, bitDepth, 1)
403 {} 425 {}
404 426
405 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, 427 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
406 SkPMColor ctable[], int* ctableCount) override { 428 SkPMColor ctable[], int* ctableCount) override {
407 if (!png_conversion_possible(dstInfo, this->getInfo()) || 429 if (!png_conversion_possible(dstInfo, this->getInfo()) ||
408 !this->initializeXforms(dstInfo, options, ctable, ctableCount)) 430 !this->initializeXforms(dstInfo, options, ctable, ctableCount))
409 { 431 {
410 return kInvalidConversion; 432 return kInvalidConversion;
411 } 433 }
412 434
413 this->allocateStorage(); 435 this->allocateStorage(dstInfo);
414 return kSuccess; 436 return kSuccess;
415 } 437 }
416 438
417 int readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int cou nt, int startRow) 439 int readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int cou nt, int startRow)
418 override { 440 override {
419 SkASSERT(0 == startRow); 441 SkASSERT(0 == startRow);
420 442
421 // Assume that an error in libpng indicates an incomplete input. 443 // Assume that an error in libpng indicates an incomplete input.
422 int y = 0; 444 int y = 0;
423 if (setjmp(png_jmpbuf((png_struct*)fPng_ptr))) { 445 if (setjmp(png_jmpbuf((png_struct*)fPng_ptr))) {
424 SkCodecPrintf("Failed to read row.\n"); 446 SkCodecPrintf("Failed to read row.\n");
425 return y; 447 return y;
426 } 448 }
427 449
428 void* swizzlerDstRow = dst;
429 size_t swizzlerDstRowBytes = rowBytes;
430
431 bool colorXform = fColorXform &&
432 apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo( ).color());
433 if (colorXform) {
434 swizzlerDstRow = fColorXformSrcRow;
435 swizzlerDstRowBytes = 0;
436 }
437
438 SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(), 450 SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(),
439 this->getInfo().alphaType( )); 451 this->getInfo().alphaType( ));
452 int width = fSwizzler ? fSwizzler->swizzleWidth() : dstInfo.width();
453
440 for (; y < count; y++) { 454 for (; y < count; y++) {
441 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr); 455 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr);
442 fSwizzler->swizzle(swizzlerDstRow, fSwizzlerSrcRow); 456 this->applyXformRow(dst, fSwizzlerSrcRow, dstInfo.colorType(), xform AlphaType, width);
443 457 dst = SkTAddOffset<void>(dst, rowBytes);
444 if (colorXform) {
445 fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizz ler->swizzleWidth(),
446 dstInfo.colorType(), xformAlphaType);
447 dst = SkTAddOffset<void>(dst, rowBytes);
448 }
449
450 swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBy tes);
451 } 458 }
452 459
453 return y; 460 return y;
454 } 461 }
455 462
456 int onGetScanlines(void* dst, int count, size_t rowBytes) override { 463 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
457 return this->readRows(this->dstInfo(), dst, rowBytes, count, 0); 464 return this->readRows(this->dstInfo(), dst, rowBytes, count, 0);
458 } 465 }
459 466
460 bool onSkipScanlines(int count) override { 467 bool onSkipScanlines(int count) override {
(...skipping 24 matching lines...) Expand all
485 } 492 }
486 493
487 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, 494 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
488 SkPMColor ctable[], int* ctableCount) override { 495 SkPMColor ctable[], int* ctableCount) override {
489 if (!png_conversion_possible(dstInfo, this->getInfo()) || 496 if (!png_conversion_possible(dstInfo, this->getInfo()) ||
490 !this->initializeXforms(dstInfo, options, ctable, ctableCount)) 497 !this->initializeXforms(dstInfo, options, ctable, ctableCount))
491 { 498 {
492 return kInvalidConversion; 499 return kInvalidConversion;
493 } 500 }
494 501
495 this->allocateStorage(); 502 this->allocateStorage(dstInfo);
496 fCanSkipRewind = true; 503 fCanSkipRewind = true;
497 return SkCodec::kSuccess; 504 return SkCodec::kSuccess;
498 } 505 }
499 506
500 int readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int cou nt, int startRow) 507 int readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int cou nt, int startRow)
501 override { 508 override {
502 if (setjmp(png_jmpbuf((png_struct*)fPng_ptr))) { 509 if (setjmp(png_jmpbuf((png_struct*)fPng_ptr))) {
503 SkCodecPrintf("Failed to get scanlines.\n"); 510 SkCodecPrintf("Failed to get scanlines.\n");
504 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass, 511 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass,
505 // we may be able to report that all of the memory has been initiali zed. Even if we 512 // we may be able to report that all of the memory has been initiali zed. Even if we
(...skipping 13 matching lines...) Expand all
519 for (int y = 0; y < count; y++) { 526 for (int y = 0; y < count; y++) {
520 png_read_row(fPng_ptr, srcRow, nullptr); 527 png_read_row(fPng_ptr, srcRow, nullptr);
521 srcRow += fSrcRowBytes; 528 srcRow += fSrcRowBytes;
522 } 529 }
523 // Discard rows that we don't need. 530 // Discard rows that we don't need.
524 for (int y = 0; y < this->getInfo().height() - startRow - count; y++ ) { 531 for (int y = 0; y < this->getInfo().height() - startRow - count; y++ ) {
525 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr); 532 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr);
526 } 533 }
527 } 534 }
528 535
529 // Swizzle and xform the rows we care about
530 void* swizzlerDstRow = dst;
531 size_t swizzlerDstRowBytes = rowBytes;
532
533 bool colorXform = fColorXform &&
534 apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo( ).color());
535 if (colorXform) {
536 swizzlerDstRow = fColorXformSrcRow;
537 swizzlerDstRowBytes = 0;
538 }
539
540 SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(), 536 SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(),
541 this->getInfo().alphaType( )); 537 this->getInfo().alphaType( ));
538 int width = fSwizzler ? fSwizzler->swizzleWidth() : dstInfo.width();
542 srcRow = storage.get(); 539 srcRow = storage.get();
543 for (int y = 0; y < count; y++) { 540 for (int y = 0; y < count; y++) {
544 fSwizzler->swizzle(swizzlerDstRow, srcRow); 541 this->applyXformRow(dst, srcRow, dstInfo.colorType(), xformAlphaType , width);
545 srcRow = SkTAddOffset<uint8_t>(srcRow, fSrcRowBytes); 542 srcRow = SkTAddOffset<uint8_t>(srcRow, fSrcRowBytes);
546 543 dst = SkTAddOffset<void>(dst, rowBytes);
547 if (colorXform) {
548 fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizz ler->swizzleWidth(),
549 dstInfo.colorType(), xformAlphaType);
550 dst = SkTAddOffset<void>(dst, rowBytes);
551 }
552
553 swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBy tes);
554 } 544 }
555 545
556 return count; 546 return count;
557 } 547 }
558 548
559 int onGetScanlines(void* dst, int count, size_t rowBytes) override { 549 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
560 // rewind stream if have previously called onGetScanlines, 550 // rewind stream if have previously called onGetScanlines,
561 // since we need entire progressive image to get scanlines 551 // since we need entire progressive image to get scanlines
562 if (fCanSkipRewind) { 552 if (fCanSkipRewind) {
563 // We already rewound in onStartScanlineDecode, so there is no reaso n to rewind. 553 // We already rewound in onStartScanlineDecode, so there is no reaso n to rewind.
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
809 /////////////////////////////////////////////////////////////////////////////// 799 ///////////////////////////////////////////////////////////////////////////////
810 800
811 bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& opt ions, 801 bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& opt ions,
812 SkPMColor ctable[], int* ctableCount) { 802 SkPMColor ctable[], int* ctableCount) {
813 if (setjmp(png_jmpbuf((png_struct*)fPng_ptr))) { 803 if (setjmp(png_jmpbuf((png_struct*)fPng_ptr))) {
814 SkCodecPrintf("Failed on png_read_update_info.\n"); 804 SkCodecPrintf("Failed on png_read_update_info.\n");
815 return false; 805 return false;
816 } 806 }
817 png_read_update_info(fPng_ptr, fInfo_ptr); 807 png_read_update_info(fPng_ptr, fInfo_ptr);
818 808
819 // It's important to reset fColorXform to nullptr. We don't do this on rewi nding 809 // Reset fSwizzler and fColorXform. We can't do this in onRewind() because the
820 // because the interlaced scanline decoder may need to rewind. 810 // interlaced scanline decoder may need to rewind.
811 fSwizzler.reset(nullptr);
821 fColorXform = nullptr; 812 fColorXform = nullptr;
822 SkImageInfo swizzlerInfo = dstInfo; 813
823 Options swizzlerOptions = options;
824 bool needsColorXform = needs_color_xform(dstInfo, this->getInfo()); 814 bool needsColorXform = needs_color_xform(dstInfo, this->getInfo());
825 if (needsColorXform) { 815 if (needsColorXform) {
826 switch (dstInfo.colorType()) { 816 if (kGray_8_SkColorType == dstInfo.colorType() ||
827 case kRGBA_8888_SkColorType: 817 kRGB_565_SkColorType == dstInfo.colorType())
828 case kBGRA_8888_SkColorType: 818 {
829 case kRGBA_F16_SkColorType: 819 return false;
830 swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType );
831 if (kPremul_SkAlphaType == dstInfo.alphaType()) {
832 swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaT ype);
833 }
834 break;
835 case kIndex_8_SkColorType:
836 break;
837 default:
838 return false;
839 } 820 }
840 821
841 fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpac e()), 822 fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpac e()),
842 sk_ref_sp(dstInfo.colorSpace())); 823 sk_ref_sp(dstInfo.colorSpace()));
843 824
844 if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) { 825 if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) {
845 return false; 826 return false;
846 } 827 }
828 }
847 829
848 // When there is a color xform, we swizzle into temporary memory, which is not 830 // If the image is RGBA and we have a color xform, we can skip the swizzler.
849 // zero initialized. 831 // FIXME (msarett):
850 // FIXME (msarett): 832 // Support more input types to fColorXform (ex: RGB, Gray) and skip the swiz zler more often.
851 // Is this a problem? 833 if (fColorXform && SkEncodedInfo::kRGBA_Color == this->getEncodedInfo().colo r() &&
852 swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized; 834 !options.fSubset)
835 {
836 fXformMode = kColorOnly_XformMode;
837 return true;
853 } 838 }
854 839
855 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) { 840 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
856 if (!this->createColorTable(dstInfo, ctableCount)) { 841 if (!this->createColorTable(dstInfo, ctableCount)) {
857 return false; 842 return false;
858 } 843 }
859 } 844 }
860 845
861 // Copy the color table to the client if they request kIndex8 mode 846 // Copy the color table to the client if they request kIndex8 mode.
862 copy_color_table(swizzlerInfo, fColorTable, ctable, ctableCount); 847 copy_color_table(dstInfo, fColorTable, ctable, ctableCount);
863 848
864 // Create the swizzler. SkPngCodec retains ownership of the color table. 849 this->initializeSwizzler(dstInfo, options);
850 return true;
851 }
852
853 static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo ::Color srcColor) {
854 // We will apply the color xform when reading the color table, unless F16 is requested.
855 return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType;
856 }
857
858 void SkPngCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& o ptions) {
859 SkImageInfo swizzlerInfo = dstInfo;
860 Options swizzlerOptions = options;
861 fXformMode = kSwizzleOnly_XformMode;
862 if (fColorXform && apply_xform_on_decode(dstInfo.colorType(), this->getEncod edInfo().color())) {
863 swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType);
864 if (kPremul_SkAlphaType == dstInfo.alphaType()) {
865 swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
866 }
867
868 fXformMode = kSwizzleColor_XformMode;
869
870 // Here, we swizzle into temporary memory, which is not zero initialized .
871 // FIXME (msarett):
872 // Is this a problem?
873 swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized;
874 }
875
865 const SkPMColor* colors = get_color_ptr(fColorTable.get()); 876 const SkPMColor* colors = get_color_ptr(fColorTable.get());
866 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, s wizzlerInfo, 877 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, s wizzlerInfo,
867 swizzlerOptions)); 878 swizzlerOptions));
868 SkASSERT(fSwizzler); 879 SkASSERT(fSwizzler);
869 return true; 880 }
881
882 SkSampler* SkPngCodec::getSampler(bool createIfNecessary) {
883 if (fSwizzler || !createIfNecessary) {
884 return fSwizzler;
885 }
886
887 this->initializeSwizzler(this->dstInfo(), this->options());
888 return fSwizzler;
870 } 889 }
871 890
872 bool SkPngCodec::onRewind() { 891 bool SkPngCodec::onRewind() {
873 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header 892 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
874 // succeeds, they will be repopulated, and if it fails, they will 893 // succeeds, they will be repopulated, and if it fails, they will
875 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will 894 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
876 // come through this function which will rewind and again attempt 895 // come through this function which will rewind and again attempt
877 // to reinitialize them. 896 // to reinitialize them.
878 this->destroyReadStruct(); 897 this->destroyReadStruct();
879 898
(...skipping 15 matching lines...) Expand all
895 if (!png_conversion_possible(dstInfo, this->getInfo()) || 914 if (!png_conversion_possible(dstInfo, this->getInfo()) ||
896 !this->initializeXforms(dstInfo, options, ctable, ctableCount)) 915 !this->initializeXforms(dstInfo, options, ctable, ctableCount))
897 { 916 {
898 return kInvalidConversion; 917 return kInvalidConversion;
899 } 918 }
900 919
901 if (options.fSubset) { 920 if (options.fSubset) {
902 return kUnimplemented; 921 return kUnimplemented;
903 } 922 }
904 923
905 this->allocateStorage(); 924 this->allocateStorage(dstInfo);
906 int count = this->readRows(dstInfo, dst, rowBytes, dstInfo.height(), 0); 925 int count = this->readRows(dstInfo, dst, rowBytes, dstInfo.height(), 0);
907 if (count > dstInfo.height()) { 926 if (count > dstInfo.height()) {
908 *rowsDecoded = count; 927 *rowsDecoded = count;
909 return kIncompleteInput; 928 return kIncompleteInput;
910 } 929 }
911 930
912 return kSuccess; 931 return kSuccess;
913 } 932 }
914 933
915 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { 934 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const {
(...skipping 10 matching lines...) Expand all
926 SkCodec* outCodec; 945 SkCodec* outCodec;
927 if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) { 946 if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) {
928 // Codec has taken ownership of the stream. 947 // Codec has taken ownership of the stream.
929 SkASSERT(outCodec); 948 SkASSERT(outCodec);
930 streamDeleter.release(); 949 streamDeleter.release();
931 return outCodec; 950 return outCodec;
932 } 951 }
933 952
934 return nullptr; 953 return nullptr;
935 } 954 }
OLDNEW
« no previous file with comments | « src/codec/SkPngCodec.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698