Index: dm/DMSrcSink.cpp |
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp |
index 585a51d7fdf28df03783002819f7f3bce6998e5e..73702b56d4b03656422449d69906b914a421e1a4 100644 |
--- a/dm/DMSrcSink.cpp |
+++ b/dm/DMSrcSink.cpp |
@@ -410,7 +410,8 @@ Error CodecSrc::draw(SkCanvas* canvas) const { |
const int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType()); |
const size_t rowBytes = size.width() * bpp; |
- SkAutoMalloc pixels(decodeInfo.getSafeSize(rowBytes)); |
+ const size_t safeSize = decodeInfo.getSafeSize(rowBytes); |
+ SkAutoMalloc pixels(safeSize); |
SkPMColor colorPtr[256]; |
int colorCount = 256; |
@@ -427,6 +428,58 @@ Error CodecSrc::draw(SkCanvas* canvas) const { |
} |
switch (fMode) { |
+ case kAnimated_Mode: { |
+ std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo(); |
+ if (frameInfos.size() <= 1) { |
+ return SkStringPrintf("%s is not an animated image.", fPath.c_str()); |
+ } |
+ |
+ SkAutoCanvasRestore acr(canvas, true); |
+ // Used to cache a frame that future frames will depend on. |
+ SkAutoMalloc priorFramePixels; |
+ size_t cachedFrame = SkCodec::kIndependentFrame; |
+ SkCodec::MultiFrameOptions multiOptions; |
+ options.fFrameOptions = &multiOptions; |
+ for (size_t i = 0; i < frameInfos.size(); i++) { |
+ multiOptions.fIndex = i; |
+ // Check for a prior frame |
+ const size_t reqFrame = frameInfos[i].fRequiredFrame; |
+ if (reqFrame != SkCodec::kIndependentFrame && reqFrame == cachedFrame |
cblume
2016/10/14 16:52:35
I wonder if we can find a better name than kIndepe
scroggo_chromium
2016/10/14 19:55:59
I understand your confusion, and I'm not opposed t
cblume
2016/10/18 21:57:32
I agree that I'm not a fan of kNotFound. It wasn't
scroggo_chromium
2016/10/20 17:57:12
Done.
|
+ && priorFramePixels.get()) { |
+ // Copy into pixels |
+ memcpy(pixels.get(), priorFramePixels.get(), safeSize); |
+ multiOptions.fHasPriorFrame = true; |
+ } else { |
+ multiOptions.fHasPriorFrame = false; |
+ } |
+ const SkCodec::Result result = codec->getPixels(decodeInfo, pixels.get(), |
+ rowBytes, &options, |
+ colorPtr, &colorCount); |
+ switch (result) { |
+ case SkCodec::kSuccess: |
+ case SkCodec::kIncompleteInput: |
+ draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, |
+ colorPtr, colorCount, fDstColorType); |
+ if (result == SkCodec::kIncompleteInput) { |
+ return ""; |
+ } |
+ break; |
+ default: |
+ return SkStringPrintf("Couldn't getPixels for frame %i in %s.", |
+ i, fPath.c_str()); |
+ } |
+ |
+ // If a future frame depends on this one, store it in priorFrame. |
+ // (Note that if i+1 does *not* depend on i, then no future frame can.) |
+ if (i+1 < frameInfos.size() && frameInfos[i+1].fRequiredFrame == i) { |
+ memcpy(priorFramePixels.reset(safeSize), pixels.get(), safeSize); |
+ cachedFrame = i; |
+ } |
cblume
2016/10/14 16:52:35
I like this way of dealing with DisposeOverwritePr
|
+ |
+ canvas->translate(SkIntToScalar(0), SkIntToScalar(decodeInfo.height())); |
+ } |
+ break; |
+ } |
case kCodecZeroInit_Mode: |
case kCodec_Mode: { |
switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options, |
@@ -448,10 +501,12 @@ Error CodecSrc::draw(SkCanvas* canvas) const { |
case kScanline_Mode: { |
void* dst = pixels.get(); |
uint32_t height = decodeInfo.height(); |
- const bool png = fPath.endsWith("png"); |
+ const bool useIncremental = fPath.endsWith("png") || fPath.endsWith("gif") || fPath.endsWith("GIF"); |
msarett
2016/10/14 14:58:50
nit: 100 chars
nit: Should we defensively add PNG
cblume
2016/10/14 16:52:35
or just toLower
scroggo_chromium
2016/10/14 19:55:59
done
|
+ // ico may use the old scanline method or the new one, depending on whether it |
+ // internally holds a bmp or a png. |
const bool ico = fPath.endsWith("ico"); |
- bool useOldScanlineMethod = !png && !ico; |
- if (png || ico) { |
+ bool useOldScanlineMethod = !useIncremental && !ico; |
+ if (useIncremental || ico) { |
if (SkCodec::kSuccess == codec->startIncrementalDecode(decodeInfo, dst, |
rowBytes, nullptr, colorPtr, &colorCount)) { |
int rowsDecoded; |
@@ -461,8 +516,8 @@ Error CodecSrc::draw(SkCanvas* canvas) const { |
rowsDecoded); |
} |
} else { |
- if (png) { |
- // Error: PNG should support incremental decode. |
+ if (useIncremental) { |
+ // Error: These should support incremental decode. |
return "Could not start incremental decode"; |
} |
// Otherwise, this is an ICO. Since incremental failed, it must contain a BMP, |
@@ -484,17 +539,6 @@ Error CodecSrc::draw(SkCanvas* canvas) const { |
// image, memory will be filled with a default value. |
codec->getScanlines(dst, height, rowBytes); |
break; |
- case SkCodec::kOutOfOrder_SkScanlineOrder: { |
- for (int y = 0; y < decodeInfo.height(); y++) { |
- int dstY = codec->outputScanline(y); |
- void* dstPtr = SkTAddOffset<void>(dst, rowBytes * dstY); |
- // We complete the loop, even if this call begins to fail |
- // due to an incomplete image. This ensures any uninitialized |
- // memory will be filled with the proper value. |
- codec->getScanlines(dstPtr, 1, rowBytes); |
- } |
- break; |
- } |
} |
} |
@@ -660,7 +704,14 @@ SkISize CodecSrc::size() const { |
if (nullptr == codec) { |
return SkISize::Make(0, 0); |
} |
- return codec->getScaledDimensions(fScale); |
+ |
+ auto imageSize = codec->getScaledDimensions(fScale); |
+ if (fMode == kAnimated_Mode) { |
+ // We'll draw one of each frame, so make it big enough to hold them all. |
+ const size_t count = codec->getFrameInfo().size(); |
+ imageSize.fHeight = imageSize.fHeight * count; |
+ } |
+ return imageSize; |
} |
Name CodecSrc::name() const { |