| Index: src/codec/SkCodec.cpp
|
| diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp
|
| index 6f298700b712c6a4b0f39c5ccd1761048d1384e1..84afc2bdee282b598b76f6f75234d276339712e6 100644
|
| --- a/src/codec/SkCodec.cpp
|
| +++ b/src/codec/SkCodec.cpp
|
| @@ -158,6 +158,8 @@ bool SkCodec::rewindIfNeeded() {
|
|
|
| // startScanlineDecode will need to be called before decoding scanlines.
|
| fCurrScanline = -1;
|
| + // startIncrementalDecode will need to be called before incrementalDecode.
|
| + fStartedIncrementalDecode = false;
|
|
|
| if (!fStream->rewind()) {
|
| return false;
|
| @@ -166,6 +168,20 @@ bool SkCodec::rewindIfNeeded() {
|
| return this->onRewind();
|
| }
|
|
|
| +#define CHECK_COLOR_TABLE \
|
| + if (kIndex_8_SkColorType == info.colorType()) { \
|
| + if (nullptr == ctable || nullptr == ctableCount) { \
|
| + return SkCodec::kInvalidParameters; \
|
| + } \
|
| + } else { \
|
| + if (ctableCount) { \
|
| + *ctableCount = 0; \
|
| + } \
|
| + ctableCount = nullptr; \
|
| + ctable = nullptr; \
|
| + }
|
| +
|
| +
|
| SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
|
| const Options* options, SkPMColor ctable[], int* ctableCount) {
|
| if (kUnknown_SkColorType == info.colorType()) {
|
| @@ -178,17 +194,7 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t
|
| return kInvalidParameters;
|
| }
|
|
|
| - if (kIndex_8_SkColorType == info.colorType()) {
|
| - if (nullptr == ctable || nullptr == ctableCount) {
|
| - return kInvalidParameters;
|
| - }
|
| - } else {
|
| - if (ctableCount) {
|
| - *ctableCount = 0;
|
| - }
|
| - ctableCount = nullptr;
|
| - ctable = nullptr;
|
| - }
|
| + CHECK_COLOR_TABLE;
|
|
|
| if (!this->rewindIfNeeded()) {
|
| return kCouldNotRewind;
|
| @@ -213,6 +219,11 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t
|
| return kInvalidScale;
|
| }
|
|
|
| + fDstInfo = info;
|
| + // FIXME: fOptions should be updated to options here, since fillIncompleteImage (called below
|
| + // in this method) accesses it. Without updating, it uses the old value.
|
| + //fOptions = *options;
|
| +
|
| // On an incomplete decode, the subclass will specify the number of scanlines that it decoded
|
| // successfully.
|
| int rowsDecoded = 0;
|
| @@ -240,23 +251,78 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t
|
| return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr);
|
| }
|
|
|
| -SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo,
|
| - const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) {
|
| - // Reset fCurrScanline in case of failure.
|
| - fCurrScanline = -1;
|
| +SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* pixels,
|
| + size_t rowBytes, const SkCodec::Options* options, SkPMColor* ctable, int* ctableCount) {
|
| + fStartedIncrementalDecode = false;
|
| +
|
| + if (kUnknown_SkColorType == info.colorType()) {
|
| + return kInvalidConversion;
|
| + }
|
| + if (nullptr == pixels) {
|
| + 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) {
|
| - return SkCodec::kInvalidParameters;
|
| + CHECK_COLOR_TABLE;
|
| +
|
| + // FIXME: If the rows come after the rows of a previous incremental decode,
|
| + // we might be able to skip the rewind, but only the implementation knows
|
| + // that. (e.g. PNG will always need to rewind, since we called longjmp, but
|
| + // a bottom-up BMP could skip rewinding if the new rows are above the old
|
| + // rows.)
|
| + if (!this->rewindIfNeeded()) {
|
| + return kCouldNotRewind;
|
| + }
|
| +
|
| + // Set options.
|
| + Options optsStorage;
|
| + if (nullptr == options) {
|
| + options = &optsStorage;
|
| + } else if (options->fSubset) {
|
| + SkIRect size = SkIRect::MakeSize(info.dimensions());
|
| + if (!size.contains(*options->fSubset)) {
|
| + return kInvalidParameters;
|
| }
|
| - } else {
|
| - if (ctableCount) {
|
| - *ctableCount = 0;
|
| +
|
| + const int top = options->fSubset->top();
|
| + const int bottom = options->fSubset->bottom();
|
| + if (top < 0 || top >= info.height() || top >= bottom || bottom > info.height()) {
|
| + return kInvalidParameters;
|
| }
|
| - ctableCount = nullptr;
|
| - ctable = nullptr;
|
| }
|
|
|
| + if (!this->dimensionsSupported(info.dimensions())) {
|
| + return kInvalidScale;
|
| + }
|
| +
|
| + fDstInfo = info;
|
| + fOptions = *options;
|
| +
|
| + const Result result = this->onStartIncrementalDecode(info, pixels, rowBytes,
|
| + fOptions, ctable, ctableCount);
|
| + if (kSuccess == result) {
|
| + fStartedIncrementalDecode = true;
|
| + } else if (kUnimplemented == result) {
|
| + // FIXME: This is temporarily necessary, until we transition SkCodec
|
| + // implementations from scanline decoding to incremental decoding.
|
| + // SkAndroidCodec will first attempt to use incremental decoding, but
|
| + // will fall back to scanline decoding if incremental returns
|
| + // kUnimplemented. rewindIfNeeded(), above, set fNeedsRewind to true
|
| + // (after potentially rewinding), but we do not want the next call to
|
| + // startScanlineDecode() to do a rewind.
|
| + fNeedsRewind = false;
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| +SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info,
|
| + const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) {
|
| + // Reset fCurrScanline in case of failure.
|
| + fCurrScanline = -1;
|
| + // Ensure that valid color ptrs are passed in for kIndex8 color type
|
| + CHECK_COLOR_TABLE;
|
| +
|
| if (!this->rewindIfNeeded()) {
|
| return kCouldNotRewind;
|
| }
|
| @@ -266,36 +332,38 @@ SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo,
|
| if (nullptr == options) {
|
| options = &optsStorage;
|
| } else if (options->fSubset) {
|
| - SkIRect size = SkIRect::MakeSize(dstInfo.dimensions());
|
| + SkIRect size = SkIRect::MakeSize(info.dimensions());
|
| if (!size.contains(*options->fSubset)) {
|
| return kInvalidInput;
|
| }
|
|
|
| // We only support subsetting in the x-dimension for scanline decoder.
|
| // Subsetting in the y-dimension can be accomplished using skipScanlines().
|
| - if (options->fSubset->top() != 0 || options->fSubset->height() != dstInfo.height()) {
|
| + if (options->fSubset->top() != 0 || options->fSubset->height() != info.height()) {
|
| return kInvalidInput;
|
| }
|
| }
|
|
|
| // FIXME: Support subsets somehow?
|
| - if (!this->dimensionsSupported(dstInfo.dimensions())) {
|
| + if (!this->dimensionsSupported(info.dimensions())) {
|
| return kInvalidScale;
|
| }
|
|
|
| - const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable, ctableCount);
|
| + const Result result = this->onStartScanlineDecode(info, *options, ctable, ctableCount);
|
| if (result != SkCodec::kSuccess) {
|
| return result;
|
| }
|
|
|
| fCurrScanline = 0;
|
| - fDstInfo = dstInfo;
|
| + fDstInfo = info;
|
| fOptions = *options;
|
| return kSuccess;
|
| }
|
|
|
| -SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) {
|
| - return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr);
|
| +#undef CHECK_COLOR_TABLE
|
| +
|
| +SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info) {
|
| + return this->startScanlineDecode(info, nullptr, nullptr, nullptr);
|
| }
|
|
|
| int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) {
|
| @@ -343,7 +411,6 @@ int SkCodec::outputScanline(int inputScanline) const {
|
| int SkCodec::onOutputScanline(int inputScanline) const {
|
| switch (this->getScanlineOrder()) {
|
| case kTopDown_SkScanlineOrder:
|
| - case kNone_SkScanlineOrder:
|
| return inputScanline;
|
| case kBottomUp_SkScanlineOrder:
|
| return this->getInfo().height() - inputScanline - 1;
|
| @@ -393,8 +460,7 @@ void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t row
|
| }
|
|
|
| switch (this->getScanlineOrder()) {
|
| - case kTopDown_SkScanlineOrder:
|
| - case kNone_SkScanlineOrder: {
|
| + case kTopDown_SkScanlineOrder: {
|
| const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining);
|
| fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes);
|
| fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler);
|
|
|