Index: src/codec/SkSampledCodec.cpp |
diff --git a/src/codec/SkSampledCodec.cpp b/src/codec/SkSampledCodec.cpp |
index 8c39f277ae2c34e07acdfee257a919c8ea3b9a78..49c939c1f887c500f8795173a031dc2c996b36eb 100644 |
--- a/src/codec/SkSampledCodec.cpp |
+++ b/src/codec/SkSampledCodec.cpp |
@@ -101,65 +101,37 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void |
int scaledSubsetWidth = info.width(); |
int scaledSubsetHeight = info.height(); |
- const SkImageInfo scaledInfo = info.makeWH(scaledSize.width(), scaledSize.height()); |
- |
- { |
- // Although startScanlineDecode expects the bottom and top to match the |
- // SkImageInfo, startIncrementalDecode uses them to determine when to start |
- // and end calling the callback. |
- SkIRect incrementalSubset = SkIRect::MakeXYWH(scaledSubsetX, scaledSubsetY, |
- scaledSubsetWidth, scaledSubsetHeight); |
- codecOptions.fSubset = &incrementalSubset; |
- const SkCodec::Result startResult = this->codec()->startIncrementalDecode( |
- scaledInfo, pixels, rowBytes, &codecOptions, |
- options.fColorPtr, options.fColorCount); |
- if (SkCodec::kSuccess == startResult) { |
- int rowsDecoded; |
- const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded); |
- if (incResult == SkCodec::kSuccess) { |
- return SkCodec::kSuccess; |
- } |
- SkASSERT(SkCodec::kIncompleteInput == incResult); |
- |
- // FIXME: Can zero initialized be read from SkCodec::fOptions? |
- this->codec()->fillIncompleteImage(scaledInfo, pixels, rowBytes, |
- options.fZeroInitialized, scaledSubsetHeight, rowsDecoded); |
- return SkCodec::kIncompleteInput; |
- } else if (startResult != SkCodec::kUnimplemented) { |
- return startResult; |
- } |
- // Otherwise fall down to use the old scanline decoder. |
- // codecOptions.fSubset will be reset below, so it will not continue to |
- // point to the object that is no longer on the stack. |
- } |
- |
// Start the scanline decode. |
SkIRect scanlineSubset = SkIRect::MakeXYWH(scaledSubsetX, 0, scaledSubsetWidth, |
scaledSize.height()); |
codecOptions.fSubset = &scanlineSubset; |
- |
- SkCodec::Result result = this->codec()->startScanlineDecode(scaledInfo, |
- &codecOptions, options.fColorPtr, options.fColorCount); |
+ SkCodec::Result result = this->codec()->startScanlineDecode(info.makeWH(scaledSize.width(), |
+ scaledSize.height()), &codecOptions, options.fColorPtr, options.fColorCount); |
if (SkCodec::kSuccess != result) { |
return result; |
} |
// At this point, we are only concerned with subsetting. Either no scale was |
// requested, or the this->codec() is handling the scale. |
- // Note that subsetting is only supported for kTopDown, so this code will not be |
- // reached for other orders. |
- SkASSERT(this->codec()->getScanlineOrder() == SkCodec::kTopDown_SkScanlineOrder); |
- if (!this->codec()->skipScanlines(scaledSubsetY)) { |
- this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, |
- scaledSubsetHeight, 0); |
- return SkCodec::kIncompleteInput; |
- } |
+ switch (this->codec()->getScanlineOrder()) { |
+ case SkCodec::kTopDown_SkScanlineOrder: |
+ case SkCodec::kNone_SkScanlineOrder: { |
+ if (!this->codec()->skipScanlines(scaledSubsetY)) { |
+ this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, |
+ scaledSubsetHeight, 0); |
+ return SkCodec::kIncompleteInput; |
+ } |
- int decodedLines = this->codec()->getScanlines(pixels, scaledSubsetHeight, rowBytes); |
- if (decodedLines != scaledSubsetHeight) { |
- return SkCodec::kIncompleteInput; |
+ int decodedLines = this->codec()->getScanlines(pixels, scaledSubsetHeight, rowBytes); |
+ if (decodedLines != scaledSubsetHeight) { |
+ return SkCodec::kIncompleteInput; |
+ } |
+ return SkCodec::kSuccess; |
+ } |
+ default: |
+ SkASSERT(false); |
+ return SkCodec::kUnimplemented; |
} |
- return SkCodec::kSuccess; |
} |
@@ -202,70 +174,10 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix |
sampledOptions.fSubset = ⊂ |
} |
- // Since we guarantee that output dimensions are always at least one (even if the sampleSize |
- // is greater than a given dimension), the input sampleSize is not always the sampleSize that |
- // we use in practice. |
- const int sampleX = subsetWidth / info.width(); |
- const int sampleY = subsetHeight / info.height(); |
- |
- const int samplingOffsetY = get_start_coord(sampleY); |
- const int startY = samplingOffsetY + subsetY; |
- int dstHeight = info.height(); |
- |
- const SkImageInfo nativeInfo = info.makeWH(nativeSize.width(), nativeSize.height()); |
- |
- { |
- // Although startScanlineDecode expects the bottom and top to match the |
- // SkImageInfo, startIncrementalDecode uses them to determine when to start |
- // and end calling the callback. |
- SkIRect incrementalSubset; |
- incrementalSubset.fTop = startY; |
- incrementalSubset.fBottom = startY + (dstHeight - 1) * sampleY + 1; |
- if (sampledOptions.fSubset) { |
- incrementalSubset.fLeft = sampledOptions.fSubset->fLeft; |
- incrementalSubset.fRight = sampledOptions.fSubset->fRight; |
- } else { |
- incrementalSubset.fLeft = 0; |
- incrementalSubset.fRight = nativeSize.width(); |
- } |
- SkCodec::Options incrementalOptions = sampledOptions; |
- incrementalOptions.fSubset = &incrementalSubset; |
- const SkCodec::Result startResult = this->codec()->startIncrementalDecode(nativeInfo, |
- pixels, rowBytes, &incrementalOptions, options.fColorPtr, options.fColorCount); |
- if (SkCodec::kSuccess == startResult) { |
- SkSampler* sampler = this->codec()->getSampler(true); |
- if (!sampler) { |
- return SkCodec::kUnimplemented; |
- } |
- |
- if (sampler->setSampleX(sampleX) != info.width()) { |
- return SkCodec::kInvalidScale; |
- } |
- if (get_scaled_dimension(subsetHeight, sampleY) != info.height()) { |
- return SkCodec::kInvalidScale; |
- } |
- |
- sampler->setSampleY(sampleY); |
- |
- int rowsDecoded; |
- const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded); |
- if (incResult == SkCodec::kSuccess) { |
- return SkCodec::kSuccess; |
- } |
- SkASSERT(incResult == SkCodec::kIncompleteInput); |
- const int lastRowInOutput = (rowsDecoded - startY) / sampleY; |
- // FIXME: Should this be info or nativeInfo? Does it make a difference? |
- this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, |
- info.height(), lastRowInOutput); |
- return SkCodec::kIncompleteInput; |
- } else if (startResult != SkCodec::kUnimplemented) { |
- return startResult; |
- } // kUnimplemented means use the old method. |
- } |
- |
// Start the scanline decode. |
- SkCodec::Result result = this->codec()->startScanlineDecode(nativeInfo, |
- &sampledOptions, options.fColorPtr, options.fColorCount); |
+ SkCodec::Result result = this->codec()->startScanlineDecode( |
+ info.makeWH(nativeSize.width(), nativeSize.height()), &sampledOptions, |
+ options.fColorPtr, options.fColorCount); |
if (SkCodec::kSuccess != result) { |
return result; |
} |
@@ -275,6 +187,11 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix |
return SkCodec::kUnimplemented; |
} |
+ // Since we guarantee that output dimensions are always at least one (even if the sampleSize |
+ // is greater than a given dimension), the input sampleSize is not always the sampleSize that |
+ // we use in practice. |
+ const int sampleX = subsetWidth / info.width(); |
+ const int sampleY = subsetHeight / info.height(); |
if (sampler->setSampleX(sampleX) != info.width()) { |
return SkCodec::kInvalidScale; |
} |
@@ -282,6 +199,9 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix |
return SkCodec::kInvalidScale; |
} |
+ const int samplingOffsetY = get_start_coord(sampleY); |
+ const int startY = samplingOffsetY + subsetY; |
+ int dstHeight = info.height(); |
switch(this->codec()->getScanlineOrder()) { |
case SkCodec::kTopDown_SkScanlineOrder: { |
if (!this->codec()->skipScanlines(startY)) { |
@@ -346,6 +266,30 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix |
} |
return SkCodec::kIncompleteInput; |
} |
+ case SkCodec::kNone_SkScanlineOrder: { |
+ const int linesNeeded = subsetHeight - samplingOffsetY; |
+ SkAutoTMalloc<uint8_t> storage(linesNeeded * rowBytes); |
+ uint8_t* storagePtr = storage.get(); |
+ |
+ if (!this->codec()->skipScanlines(startY)) { |
+ this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, |
+ dstHeight, 0); |
+ return SkCodec::kIncompleteInput; |
+ } |
+ int scanlines = this->codec()->getScanlines(storagePtr, linesNeeded, rowBytes); |
+ |
+ for (int y = 0; y < dstHeight; y++) { |
+ memcpy(pixels, storagePtr, info.minRowBytes()); |
+ storagePtr += sampleY * rowBytes; |
+ pixels = SkTAddOffset<void>(pixels, rowBytes); |
+ } |
+ |
+ if (scanlines < dstHeight) { |
+ // this->codec() has already handled filling uninitialized memory. |
+ return SkCodec::kIncompleteInput; |
+ } |
+ return SkCodec::kSuccess; |
+ } |
default: |
SkASSERT(false); |
return SkCodec::kUnimplemented; |