Index: src/codec/SkWebpCodec.cpp |
diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp |
index 32a8b78b14f2487e69305c6d90c89533319435bb..fea557d21ed9ddb8e9a86ff475a2c996a8fa749d 100644 |
--- a/src/codec/SkWebpCodec.cpp |
+++ b/src/codec/SkWebpCodec.cpp |
@@ -125,8 +125,26 @@ static WEBP_CSP_MODE webp_decode_mode(SkColorType ct, bool premultiply) { |
// is arbitrary. |
static const size_t BUFFER_SIZE = 4096; |
+bool SkWebpCodec::onGetValidSubset(SkIRect* desiredSubset) const { |
+ if (!desiredSubset) { |
+ return false; |
+ } |
+ |
+ SkIRect bounds = SkIRect::MakeSize(this->getInfo().dimensions()); |
+ if (!desiredSubset->intersect(bounds)) { |
+ return false; |
+ } |
+ |
+ // As stated below, libwebp snaps to even left and top. Make sure top and left are even, so we |
+ // decode this exact subset. |
+ // Leave right and bottom unmodified, so we suggest a slightly larger subset than requested. |
+ desiredSubset->fLeft = (desiredSubset->fLeft >> 1) << 1; |
+ desiredSubset->fTop = (desiredSubset->fTop >> 1) << 1; |
+ return true; |
+} |
+ |
SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, |
- const Options&, SkPMColor*, int*) { |
+ const Options& options, SkPMColor*, int*) { |
switch (this->rewindIfNeeded()) { |
case kCouldNotRewind_RewindState: |
return kCouldNotRewind; |
@@ -153,12 +171,48 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, |
// Free any memory associated with the buffer. Must be called last, so we declare it first. |
SkAutoTCallVProc<WebPDecBuffer, WebPFreeDecBuffer> autoFree(&(config.output)); |
- SkISize dimensions = dstInfo.dimensions(); |
- if (this->getInfo().dimensions() != dimensions) { |
+ SkIRect bounds = SkIRect::MakeSize(this->getInfo().dimensions()); |
+ if (options.fSubset) { |
+ // Caller is requesting a subset. |
+ if (!bounds.contains(*options.fSubset)) { |
+ // The subset is out of bounds. |
+ return kInvalidParameters; |
+ } |
+ |
+ bounds = *options.fSubset; |
+ |
+ // This is tricky. libwebp snaps the top and left to even values. We could let libwebp |
+ // do the snap, and return a subset which is a different one than requested. The problem |
+ // with that approach is that the caller may try to stitch subsets together, and if we |
+ // returned different subsets than requested, there would be artifacts at the boundaries. |
+ // Instead, we report that we cannot support odd values for top and left.. |
+ if (!SkIsAlign2(bounds.fLeft) || !SkIsAlign2(bounds.fTop)) { |
+ return kInvalidParameters; |
+ } |
+ |
+#ifdef SK_DEBUG |
+ { |
+ // Make a copy, since getValidSubset can change its input. |
+ SkIRect subset(bounds); |
+ // That said, getValidSubset should *not* change its input, in this case; otherwise |
+ // getValidSubset does not match the actual subsets we can do. |
+ SkASSERT(this->getValidSubset(&subset) && subset == bounds); |
+ } |
+#endif |
+ |
+ config.options.use_cropping = 1; |
+ config.options.crop_left = bounds.fLeft; |
+ config.options.crop_top = bounds.fTop; |
+ config.options.crop_width = bounds.width(); |
+ config.options.crop_height = bounds.height(); |
+ } |
+ |
+ SkISize dstDimensions = dstInfo.dimensions(); |
+ if (bounds.size() != dstDimensions) { |
// Caller is requesting scaling. |
config.options.use_scaling = 1; |
- config.options.scaled_width = dimensions.width(); |
- config.options.scaled_height = dimensions.height(); |
+ config.options.scaled_width = dstDimensions.width(); |
+ config.options.scaled_height = dstDimensions.height(); |
} |
config.output.colorspace = webp_decode_mode(dstInfo.colorType(), |