diff options
Diffstat (limited to 'dm')
-rw-r--r-- | dm/DM.cpp | 19 | ||||
-rw-r--r-- | dm/DMSrcSink.cpp | 93 | ||||
-rw-r--r-- | dm/DMSrcSink.h | 1 |
3 files changed, 93 insertions, 20 deletions
@@ -36,6 +36,8 @@ #include "sk_tool_utils.h" #include "SkScan.h" +#include <vector> + #ifdef SK_PDF_IMAGE_STATS extern void SkPDFImageDumpStats(); #endif @@ -357,10 +359,11 @@ static void push_src(const char* tag, ImplicitString options, Src* s) { static void push_codec_src(Path path, CodecSrc::Mode mode, CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType, float scale) { if (FLAGS_simpleCodec) { - if (mode != CodecSrc::kCodec_Mode || dstColorType != CodecSrc::kGetFromCanvas_DstColorType - || scale != 1.0f) + const bool simple = CodecSrc::kCodec_Mode == mode || CodecSrc::kAnimated_Mode == mode; + if (!simple || dstColorType != CodecSrc::kGetFromCanvas_DstColorType || scale != 1.0f) { // Only decode in the simple case. return; + } } SkString folder; switch (mode) { @@ -382,6 +385,9 @@ static void push_codec_src(Path path, CodecSrc::Mode mode, CodecSrc::DstColorTyp case CodecSrc::kSubset_Mode: folder.append("codec_subset"); break; + case CodecSrc::kAnimated_Mode: + folder.append("codec_animated"); + break; } switch (dstColorType) { @@ -574,6 +580,15 @@ static void push_codec_srcs(Path path) { } } + { + std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo(); + if (frameInfos.size() > 1) { + push_codec_src(path, CodecSrc::kAnimated_Mode, CodecSrc::kGetFromCanvas_DstColorType, + kPremul_SkAlphaType, 1.0f); + } + + } + if (FLAGS_simpleCodec) { return; } diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp index 8ff8b4c055..9efccd3042 100644 --- a/dm/DMSrcSink.cpp +++ b/dm/DMSrcSink.cpp @@ -409,7 +409,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; @@ -426,6 +427,56 @@ 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::kNone; + for (size_t i = 0; i < frameInfos.size(); i++) { + options.fFrameIndex = i; + // Check for a prior frame + const size_t reqFrame = frameInfos[i].fRequiredFrame; + if (reqFrame != SkCodec::kNone && reqFrame == cachedFrame + && priorFramePixels.get()) { + // Copy into pixels + memcpy(pixels.get(), priorFramePixels.get(), safeSize); + options.fHasPriorFrame = true; + } else { + options.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; + } + + canvas->translate(SkIntToScalar(0), SkIntToScalar(decodeInfo.height())); + } + break; + } case kCodecZeroInit_Mode: case kCodec_Mode: { switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options, @@ -447,10 +498,20 @@ 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 = [this]() { + auto exts = { "png", "PNG", "gif", "GIF" }; + for (auto ext : exts) { + if (fPath.endsWith(ext)) { + return true; + } + } + return false; + }(); + // 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; @@ -460,8 +521,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, @@ -483,17 +544,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; - } } } @@ -659,7 +709,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 { diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h index e8466aa50d..4be9878afa 100644 --- a/dm/DMSrcSink.h +++ b/dm/DMSrcSink.h @@ -118,6 +118,7 @@ public: kStripe_Mode, // Tests the skipping of scanlines kCroppedScanline_Mode, // Tests (jpeg) cropped scanline optimization kSubset_Mode, // For codecs that support subsets directly. + kAnimated_Mode, // For codecs that support animation. }; enum DstColorType { kGetFromCanvas_DstColorType, |