| Index: src/codec/SkPngCodec.cpp
|
| diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp
|
| index 2c13b12c7e75ffa00a3e04da067def657fa35141..1b8cadbf5ee00835b9b7783e5d10250739693d8f 100644
|
| --- a/src/codec/SkPngCodec.cpp
|
| +++ b/src/codec/SkPngCodec.cpp
|
| @@ -380,18 +380,40 @@ static bool png_conversion_possible(const SkImageInfo& dst, const SkImageInfo& s
|
| }
|
| }
|
|
|
| -void SkPngCodec::allocateStorage() {
|
| - size_t colorXformBytes = fColorXform ? fSwizzler->swizzleWidth() * sizeof(uint32_t) : 0;
|
| -
|
| - fStorage.reset(SkAlign4(fSrcRowBytes) + colorXformBytes);
|
| - fSwizzlerSrcRow = fStorage.get();
|
| - fColorXformSrcRow =
|
| - fColorXform ? SkTAddOffset<uint32_t>(fSwizzlerSrcRow, SkAlign4(fSrcRowBytes)) : 0;
|
| +void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) {
|
| + switch (fXformMode) {
|
| + case kSwizzleOnly_XformMode:
|
| + fStorage.reset(SkAlign4(fSrcRowBytes));
|
| + fSwizzlerSrcRow = fStorage.get();
|
| + break;
|
| + case kColorOnly_XformMode:
|
| + // Intentional fall through. A swizzler hasn't been created yet, but one will
|
| + // be created later if we are sampling. We'll go ahead and allocate
|
| + // enough memory to swizzle if necessary.
|
| + case kSwizzleColor_XformMode: {
|
| + size_t colorXformBytes = dstInfo.width() * sizeof(uint32_t);
|
| + fStorage.reset(SkAlign4(fSrcRowBytes) + colorXformBytes);
|
| + fSwizzlerSrcRow = fStorage.get();
|
| + fColorXformSrcRow = SkTAddOffset<uint32_t>(fSwizzlerSrcRow, SkAlign4(fSrcRowBytes));
|
| + break;
|
| + }
|
| + }
|
| }
|
|
|
| -static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo::Color srcColor) {
|
| - // We will apply the color xform when reading the color table, unless F16 is requested.
|
| - return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType;
|
| +void SkPngCodec::applyXformRow(void* dst, const void* src, SkColorType colorType,
|
| + SkAlphaType alphaType, int width) {
|
| + switch (fXformMode) {
|
| + case kSwizzleOnly_XformMode:
|
| + fSwizzler->swizzle(dst, (const uint8_t*) src);
|
| + break;
|
| + case kColorOnly_XformMode:
|
| + fColorXform->apply(dst, (const uint32_t*) src, width, colorType, alphaType);
|
| + break;
|
| + case kSwizzleColor_XformMode:
|
| + fSwizzler->swizzle(fColorXformSrcRow, (const uint8_t*) src);
|
| + fColorXform->apply(dst, fColorXformSrcRow, width, colorType, alphaType);
|
| + break;
|
| + }
|
| }
|
|
|
| class SkPngNormalCodec : public SkPngCodec {
|
| @@ -410,7 +432,7 @@ public:
|
| return kInvalidConversion;
|
| }
|
|
|
| - this->allocateStorage();
|
| + this->allocateStorage(dstInfo);
|
| return kSuccess;
|
| }
|
|
|
| @@ -425,29 +447,14 @@ public:
|
| return y;
|
| }
|
|
|
| - void* swizzlerDstRow = dst;
|
| - size_t swizzlerDstRowBytes = rowBytes;
|
| -
|
| - bool colorXform = fColorXform &&
|
| - apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color());
|
| - if (colorXform) {
|
| - swizzlerDstRow = fColorXformSrcRow;
|
| - swizzlerDstRowBytes = 0;
|
| - }
|
| -
|
| SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(),
|
| this->getInfo().alphaType());
|
| + int width = fSwizzler ? fSwizzler->swizzleWidth() : dstInfo.width();
|
| +
|
| for (; y < count; y++) {
|
| png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr);
|
| - fSwizzler->swizzle(swizzlerDstRow, fSwizzlerSrcRow);
|
| -
|
| - if (colorXform) {
|
| - fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizzler->swizzleWidth(),
|
| - dstInfo.colorType(), xformAlphaType);
|
| - dst = SkTAddOffset<void>(dst, rowBytes);
|
| - }
|
| -
|
| - swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBytes);
|
| + this->applyXformRow(dst, fSwizzlerSrcRow, dstInfo.colorType(), xformAlphaType, width);
|
| + dst = SkTAddOffset<void>(dst, rowBytes);
|
| }
|
|
|
| return y;
|
| @@ -492,7 +499,7 @@ public:
|
| return kInvalidConversion;
|
| }
|
|
|
| - this->allocateStorage();
|
| + this->allocateStorage(dstInfo);
|
| fCanSkipRewind = true;
|
| return SkCodec::kSuccess;
|
| }
|
| @@ -526,31 +533,14 @@ public:
|
| }
|
| }
|
|
|
| - // Swizzle and xform the rows we care about
|
| - void* swizzlerDstRow = dst;
|
| - size_t swizzlerDstRowBytes = rowBytes;
|
| -
|
| - bool colorXform = fColorXform &&
|
| - apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color());
|
| - if (colorXform) {
|
| - swizzlerDstRow = fColorXformSrcRow;
|
| - swizzlerDstRowBytes = 0;
|
| - }
|
| -
|
| SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(),
|
| this->getInfo().alphaType());
|
| + int width = fSwizzler ? fSwizzler->swizzleWidth() : dstInfo.width();
|
| srcRow = storage.get();
|
| for (int y = 0; y < count; y++) {
|
| - fSwizzler->swizzle(swizzlerDstRow, srcRow);
|
| + this->applyXformRow(dst, srcRow, dstInfo.colorType(), xformAlphaType, width);
|
| srcRow = SkTAddOffset<uint8_t>(srcRow, fSrcRowBytes);
|
| -
|
| - if (colorXform) {
|
| - fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizzler->swizzleWidth(),
|
| - dstInfo.colorType(), xformAlphaType);
|
| - dst = SkTAddOffset<void>(dst, rowBytes);
|
| - }
|
| -
|
| - swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBytes);
|
| + dst = SkTAddOffset<void>(dst, rowBytes);
|
| }
|
|
|
| return count;
|
| @@ -816,26 +806,17 @@ bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& opt
|
| }
|
| png_read_update_info(fPng_ptr, fInfo_ptr);
|
|
|
| - // It's important to reset fColorXform to nullptr. We don't do this on rewinding
|
| - // because the interlaced scanline decoder may need to rewind.
|
| + // Reset fSwizzler and fColorXform. We can't do this in onRewind() because the
|
| + // interlaced scanline decoder may need to rewind.
|
| + fSwizzler.reset(nullptr);
|
| fColorXform = nullptr;
|
| - SkImageInfo swizzlerInfo = dstInfo;
|
| - Options swizzlerOptions = options;
|
| +
|
| bool needsColorXform = needs_color_xform(dstInfo, this->getInfo());
|
| if (needsColorXform) {
|
| - switch (dstInfo.colorType()) {
|
| - case kRGBA_8888_SkColorType:
|
| - case kBGRA_8888_SkColorType:
|
| - case kRGBA_F16_SkColorType:
|
| - swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType);
|
| - if (kPremul_SkAlphaType == dstInfo.alphaType()) {
|
| - swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
|
| - }
|
| - break;
|
| - case kIndex_8_SkColorType:
|
| - break;
|
| - default:
|
| - return false;
|
| + if (kGray_8_SkColorType == dstInfo.colorType() ||
|
| + kRGB_565_SkColorType == dstInfo.colorType())
|
| + {
|
| + return false;
|
| }
|
|
|
| fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpace()),
|
| @@ -844,12 +825,16 @@ bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& opt
|
| if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) {
|
| return false;
|
| }
|
| + }
|
|
|
| - // When there is a color xform, we swizzle into temporary memory, which is not
|
| - // zero initialized.
|
| - // FIXME (msarett):
|
| - // Is this a problem?
|
| - swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized;
|
| + // If the image is RGBA and we have a color xform, we can skip the swizzler.
|
| + // FIXME (msarett):
|
| + // Support more input types to fColorXform (ex: RGB, Gray) and skip the swizzler more often.
|
| + if (fColorXform && SkEncodedInfo::kRGBA_Color == this->getEncodedInfo().color() &&
|
| + !options.fSubset)
|
| + {
|
| + fXformMode = kColorOnly_XformMode;
|
| + return true;
|
| }
|
|
|
| if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
|
| @@ -858,15 +843,49 @@ bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& opt
|
| }
|
| }
|
|
|
| - // Copy the color table to the client if they request kIndex8 mode
|
| - copy_color_table(swizzlerInfo, fColorTable, ctable, ctableCount);
|
| + // Copy the color table to the client if they request kIndex8 mode.
|
| + copy_color_table(dstInfo, fColorTable, ctable, ctableCount);
|
| +
|
| + this->initializeSwizzler(dstInfo, options);
|
| + return true;
|
| +}
|
| +
|
| +static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo::Color srcColor) {
|
| + // We will apply the color xform when reading the color table, unless F16 is requested.
|
| + return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType;
|
| +}
|
| +
|
| +void SkPngCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
|
| + SkImageInfo swizzlerInfo = dstInfo;
|
| + Options swizzlerOptions = options;
|
| + fXformMode = kSwizzleOnly_XformMode;
|
| + if (fColorXform && apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color())) {
|
| + swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType);
|
| + if (kPremul_SkAlphaType == dstInfo.alphaType()) {
|
| + swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
|
| + }
|
| +
|
| + fXformMode = kSwizzleColor_XformMode;
|
| +
|
| + // Here, we swizzle into temporary memory, which is not zero initialized.
|
| + // FIXME (msarett):
|
| + // Is this a problem?
|
| + swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized;
|
| + }
|
|
|
| - // Create the swizzler. SkPngCodec retains ownership of the color table.
|
| const SkPMColor* colors = get_color_ptr(fColorTable.get());
|
| fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, swizzlerInfo,
|
| swizzlerOptions));
|
| SkASSERT(fSwizzler);
|
| - return true;
|
| +}
|
| +
|
| +SkSampler* SkPngCodec::getSampler(bool createIfNecessary) {
|
| + if (fSwizzler || !createIfNecessary) {
|
| + return fSwizzler;
|
| + }
|
| +
|
| + this->initializeSwizzler(this->dstInfo(), this->options());
|
| + return fSwizzler;
|
| }
|
|
|
| bool SkPngCodec::onRewind() {
|
| @@ -902,7 +921,7 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
|
| return kUnimplemented;
|
| }
|
|
|
| - this->allocateStorage();
|
| + this->allocateStorage(dstInfo);
|
| int count = this->readRows(dstInfo, dst, rowBytes, dstInfo.height(), 0);
|
| if (count > dstInfo.height()) {
|
| *rowsDecoded = count;
|
|
|