Chromium Code Reviews| Index: src/codec/SkCodec.cpp |
| diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp |
| index 1171bb0bd0324109acf54a247614d34a25b221d8..9bed4bf7d093942dade4f19fb59c047d320245ca 100644 |
| --- a/src/codec/SkCodec.cpp |
| +++ b/src/codec/SkCodec.cpp |
| @@ -82,6 +82,7 @@ SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream) |
| , fDstInfo() |
| , fOptions() |
| , fCurrScanline(-1) |
| + , fSubsetWidth(0) |
| {} |
| SkCodec::~SkCodec() {} |
| @@ -103,6 +104,7 @@ bool SkCodec::rewindIfNeeded() { |
| // startScanlineDecode will need to be called before decoding scanlines. |
| fCurrScanline = -1; |
| + fSubsetWidth = 0; |
| if (!fStream->rewind()) { |
| return false; |
| @@ -111,6 +113,59 @@ bool SkCodec::rewindIfNeeded() { |
| return this->onRewind(); |
| } |
| +SkISize SkCodec::getScaledDimensions(float desiredScale) const { |
| + // Negative and zero scales are errors. |
| + SkASSERT(desiredScale > 0.0f); |
| + if (desiredScale <= 0.0f) { |
| + return SkISize::Make(0, 0); |
| + } |
| + |
| + // Upscaling is not supported. Return the original size if the client |
| + // requests an upscale. |
| + if (desiredScale >= 1.0f) { |
| + return this->getInfo().dimensions(); |
| + } |
| + return this->onGetScaledDimensions(desiredScale); |
| +} |
| + |
| +bool SkCodec::getValidSubset(SkIRect* desiredSubset) const { |
| + if (!desiredSubset) { |
| + return false; |
| + } |
| + |
| + if (!is_valid_subset(desiredSubset, this->getInfo().dimensions())) { |
| + return false; |
| + } |
| + |
| + return this->onGetValidSubset(desiredSubset); |
| +} |
| + |
| +bool SkCodec::getScaledSubsetDimensions(float desiredScale, Options* options) const { |
| + // Negative and zero scales are errors. |
| + SkASSERT(desiredScale > 0.0f); |
| + if (desiredScale <= 0.0f) { |
| + return false; |
| + } |
| + |
| + // Upscaling is not supported. We will suggest a full decode if |
| + // upscaling is requested. |
| + if (desiredScale >= 1.0f) { |
| + desiredScale = 1.0f; |
| + } |
| + |
| + // If the client is not requesting a subset decode, |
| + // getScaledDimensions() should be used. |
| + if (nullptr == options->fSubset) { |
| + return false; |
| + } |
| + |
| + if (!is_valid_subset(options->fSubset, this->getInfo().dimensions())) { |
| + return false; |
| + } |
| + |
| + return this->onGetScaledSubsetDimensions(desiredScale, options); |
| +} |
| + |
| SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, |
| const Options* options, SkPMColor ctable[], int* ctableCount) { |
| if (kUnknown_SkColorType == info.colorType()) { |
| @@ -182,9 +237,17 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t |
| } |
| SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, |
| - const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { |
| + const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount, int subsetLeft, |
| + int subsetWidth) { |
| // Reset fCurrScanline in case of failure. |
| fCurrScanline = -1; |
| + |
| + // Ensure that the subset parameters are valid |
| + if (0 > subsetLeft || subsetLeft >= dstInfo.width() || 0 > subsetWidth || |
|
scroggo
2015/10/02 18:27:03
nit: I would lean towards separating these out log
|
| + subsetLeft + subsetWidth > dstInfo.width()) { |
| + return kInvalidParameters; |
| + } |
| + |
| // Ensure that valid color ptrs are passed in for kIndex8 color type |
| if (kIndex_8_SkColorType == dstInfo.colorType()) { |
| if (nullptr == ctable || nullptr == ctableCount) { |
| @@ -208,7 +271,8 @@ SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, |
| options = &optsStorage; |
| } |
| - const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable, ctableCount); |
| + const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable, ctableCount, |
| + subsetLeft, subsetWidth); |
| if (result != SkCodec::kSuccess) { |
| return result; |
| } |
| @@ -216,11 +280,17 @@ SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, |
| fCurrScanline = 0; |
| fDstInfo = dstInfo; |
| fOptions = *options; |
| + fSubsetWidth = subsetWidth; |
| return kSuccess; |
| } |
| +SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, |
| + const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { |
| + return this->startScanlineDecode(dstInfo, options, ctable, ctableCount, 0, dstInfo.width()); |
| +} |
| + |
| SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) { |
| - return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr); |
| + return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr, 0, dstInfo.width()); |
| } |
| int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { |
| @@ -229,8 +299,7 @@ int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { |
| } |
| SkASSERT(!fDstInfo.isEmpty()); |
| - if ((rowBytes < fDstInfo.minRowBytes() && countLines > 1 ) || countLines <= 0 |
| - || fCurrScanline + countLines > fDstInfo.height()) { |
| + if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) { |
| return 0; |
| } |
| @@ -282,21 +351,22 @@ void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t row |
| SkImageInfo fillInfo; |
| const uint32_t fillValue = this->getFillValue(info.colorType(), info.alphaType()); |
| const int linesRemaining = linesRequested - linesDecoded; |
| + const int fillWidth = fSubsetWidth ? fSubsetWidth : info.width(); |
| switch (this->getScanlineOrder()) { |
| case kTopDown_SkScanlineOrder: |
| case kNone_SkScanlineOrder: |
| fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes); |
| - fillInfo = info.makeWH(info.width(), linesRemaining); |
| + fillInfo = info.makeWH(fillWidth, linesRemaining); |
| SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); |
| break; |
| case kBottomUp_SkScanlineOrder: |
| fillDst = dst; |
| - fillInfo = info.makeWH(info.width(), linesRemaining); |
| + fillInfo = info.makeWH(fillWidth, linesRemaining); |
| SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); |
| break; |
| case kOutOfOrder_SkScanlineOrder: |
| SkASSERT(1 == linesRequested || this->getInfo().height() == linesRequested); |
| - fillInfo = info.makeWH(info.width(), 1); |
| + fillInfo = info.makeWH(fillWidth, 1); |
| for (int srcY = linesDecoded; srcY < linesRequested; srcY++) { |
| fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * rowBytes); |
| SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); |