aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/codec
diff options
context:
space:
mode:
Diffstat (limited to 'src/codec')
-rw-r--r--src/codec/SkCodecAnimation.h69
-rw-r--r--src/codec/SkCodecAnimationPriv.h32
-rw-r--r--src/codec/SkFrameHolder.h3
-rw-r--r--src/codec/SkGifCodec.cpp63
-rw-r--r--src/codec/SkWebpCodec.cpp39
5 files changed, 103 insertions, 103 deletions
diff --git a/src/codec/SkCodecAnimation.h b/src/codec/SkCodecAnimation.h
deleted file mode 100644
index 46a878a801..0000000000
--- a/src/codec/SkCodecAnimation.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkCodecAnimation_DEFINED
-#define SkCodecAnimation_DEFINED
-
-#include "SkCodec.h"
-#include "SkRect.h"
-
-class SkCodecAnimation {
-public:
- /**
- * This specifies how the next frame is based on this frame.
- *
- * Names are based on the GIF 89a spec.
- *
- * The numbers correspond to values in a GIF.
- */
- enum DisposalMethod {
- /**
- * The next frame should be drawn on top of this one.
- *
- * In a GIF, a value of 0 (not specified) is also treated as Keep.
- */
- Keep_DisposalMethod = 1,
-
- /**
- * Similar to Keep, except the area inside this frame's rectangle
- * should be cleared to the BackGround color (transparent) before
- * drawing the next frame.
- */
- RestoreBGColor_DisposalMethod = 2,
-
- /**
- * The next frame should be drawn on top of the previous frame - i.e.
- * disregarding this one.
- *
- * In a GIF, a value of 4 is also treated as RestorePrevious.
- */
- RestorePrevious_DisposalMethod = 3,
- };
-
- /**
- * How to blend the current frame.
- */
- enum class Blend {
- /**
- * Blend with the prior frame. This is the typical case, supported
- * by all animated image types.
- */
- kPriorFrame,
-
- /**
- * Do not blend.
- *
- * This frames pixels overwrite previous pixels "blending" with
- * the background color of transparent.
- */
- kBG,
- };
-
-private:
- SkCodecAnimation();
-};
-#endif // SkCodecAnimation_DEFINED
diff --git a/src/codec/SkCodecAnimationPriv.h b/src/codec/SkCodecAnimationPriv.h
new file mode 100644
index 0000000000..233a79b211
--- /dev/null
+++ b/src/codec/SkCodecAnimationPriv.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkCodecAnimationPriv_DEFINED
+#define SkCodecAnimationPriv_DEFINED
+
+namespace SkCodecAnimation {
+ /**
+ * How to blend the current frame.
+ */
+ enum class Blend {
+ /**
+ * Blend with the prior frame. This is the typical case, supported
+ * by all animated image types.
+ */
+ kPriorFrame,
+
+ /**
+ * Do not blend.
+ *
+ * This frames pixels overwrite previous pixels "blending" with
+ * the background color of transparent.
+ */
+ kBG,
+ };
+
+}
+#endif // SkCodecAnimationPriv_DEFINED
diff --git a/src/codec/SkFrameHolder.h b/src/codec/SkFrameHolder.h
index e92b40f9d8..0f30b65e5a 100644
--- a/src/codec/SkFrameHolder.h
+++ b/src/codec/SkFrameHolder.h
@@ -10,6 +10,7 @@
#include "SkTypes.h"
#include "SkCodecAnimation.h"
+#include "SkCodecAnimationPriv.h"
/**
* Base class for a single frame of an animated image.
@@ -23,7 +24,7 @@ public:
: fId(id)
, fHasAlpha(false)
, fRequiredFrame(kUninitialized)
- , fDisposalMethod(SkCodecAnimation::Keep_DisposalMethod)
+ , fDisposalMethod(SkCodecAnimation::DisposalMethod::kKeep)
, fDuration(0)
, fBlend(SkCodecAnimation::Blend::kPriorFrame)
{
diff --git a/src/codec/SkGifCodec.cpp b/src/codec/SkGifCodec.cpp
index f0495bc4b3..6c4273444c 100644
--- a/src/codec/SkGifCodec.cpp
+++ b/src/codec/SkGifCodec.cpp
@@ -153,6 +153,7 @@ bool SkGifCodec::onGetFrameInfo(int i, SkCodec::FrameInfo* frameInfo) const {
frameInfo->fFullyReceived = frameContext->isComplete();
frameInfo->fAlphaType = frameContext->hasAlpha() ? kUnpremul_SkAlphaType
: kOpaque_SkAlphaType;
+ frameInfo->fDisposalMethod = frameContext->getDisposalMethod();
}
return true;
}
@@ -398,11 +399,24 @@ SkCodec::Result SkGifCodec::decodeFrame(bool firstAttempt, const Options& opts,
}
} else {
// Not independent
- if (!opts.fHasPriorFrame) {
+ // FIXME: Share this code with WEBP
+ const int reqFrame = frameContext->getRequiredFrame();
+ if (opts.fPriorFrame != kNone) {
+ if (opts.fPriorFrame < reqFrame || opts.fPriorFrame >= frameIndex) {
+ // Alternatively, we could correct this to kNone.
+ return kInvalidParameters;
+ }
+ const auto* prevFrame = fReader->frameContext(opts.fPriorFrame);
+ if (prevFrame->getDisposalMethod()
+ == SkCodecAnimation::DisposalMethod::kRestorePrevious) {
+ // Similarly, this could be corrected to kNone.
+ return kInvalidParameters;
+ }
+ } else {
// Decode that frame into pixels.
Options prevFrameOpts(opts);
prevFrameOpts.fFrameIndex = frameContext->getRequiredFrame();
- prevFrameOpts.fHasPriorFrame = false;
+ prevFrameOpts.fPriorFrame = kNone;
// The prior frame may have a different color table, so update it and the
// swizzler.
this->initializeColorTable(dstInfo, prevFrameOpts.fFrameIndex);
@@ -424,24 +438,33 @@ SkCodec::Result SkGifCodec::decodeFrame(bool firstAttempt, const Options& opts,
this->initializeColorTable(dstInfo, frameIndex);
this->initializeSwizzler(dstInfo, frameIndex);
}
- const auto* prevFrame = fReader->frameContext(frameContext->getRequiredFrame());
- if (prevFrame->getDisposalMethod() == SkCodecAnimation::RestoreBGColor_DisposalMethod) {
- SkIRect prevRect = prevFrame->frameRect();
- if (prevRect.intersect(this->getInfo().bounds())) {
- // Do the divide ourselves for left and top, since we do not want
- // get_scaled_dimension to upgrade 0 to 1. (This is similar to SkSampledCodec's
- // sampling of the subset.)
- auto left = prevRect.fLeft / fSwizzler->sampleX();
- auto top = prevRect.fTop / fSwizzler->sampleY();
- void* const eraseDst = SkTAddOffset<void>(fDst, top * fDstRowBytes
- + left * SkColorTypeBytesPerPixel(dstInfo.colorType()));
- auto width = get_scaled_dimension(prevRect.width(), fSwizzler->sampleX());
- auto height = get_scaled_dimension(prevRect.height(), fSwizzler->sampleY());
- // fSwizzler->fill() would fill to the scaled width of the frame, but we want to
- // fill to the scaled with of the width of the PRIOR frame, so we do all the
- // scaling ourselves and call the static version.
- SkSampler::Fill(dstInfo.makeWH(width, height), eraseDst,
- fDstRowBytes, this->getFillValue(dstInfo), kNo_ZeroInitialized);
+
+ // If the required frame is RestoreBG, we need to erase it. If a frame after the
+ // required frame is provided, there is no need to erase, since it will be covered
+ // anyway.
+ if (opts.fPriorFrame == reqFrame || opts.fPriorFrame == kNone) {
+ const auto* prevFrame = fReader->frameContext(reqFrame);
+ if (prevFrame->getDisposalMethod()
+ == SkCodecAnimation::DisposalMethod::kRestoreBGColor) {
+ SkIRect prevRect = prevFrame->frameRect();
+ if (prevRect.intersect(this->getInfo().bounds())) {
+ // Do the divide ourselves for left and top, since we do not want
+ // get_scaled_dimension to upgrade 0 to 1. (This is similar to
+ // SkSampledCodec's sampling of the subset.)
+ const auto sampleX = fSwizzler->sampleX();
+ const auto sampleY = fSwizzler->sampleY();
+ auto left = prevRect.fLeft / sampleX;
+ auto top = prevRect.fTop / sampleY;
+ void* const eraseDst = SkTAddOffset<void>(fDst, top * fDstRowBytes
+ + left * SkColorTypeBytesPerPixel(dstInfo.colorType()));
+ auto width = get_scaled_dimension(prevRect.width(), sampleX);
+ auto height = get_scaled_dimension(prevRect.height(), sampleY);
+ // fSwizzler->fill() would fill to the scaled width of the frame, but we
+ // want to fill to the scaled with of the width of the PRIOR frame, so we
+ // do all the scaling ourselves and call the static version.
+ SkSampler::Fill(dstInfo.makeWH(width, height), eraseDst, fDstRowBytes,
+ this->getFillValue(dstInfo), kNo_ZeroInitialized);
+ }
}
}
filledBackground = true;
diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp
index 21d45da233..f702a3ae98 100644
--- a/src/codec/SkWebpCodec.cpp
+++ b/src/codec/SkWebpCodec.cpp
@@ -7,6 +7,8 @@
#include "SkBitmap.h"
#include "SkCanvas.h"
+#include "SkCodecAnimation.h"
+#include "SkCodecAnimationPriv.h"
#include "SkCodecPriv.h"
#include "SkColorSpaceXform.h"
#include "SkRasterPipeline.h"
@@ -253,8 +255,8 @@ int SkWebpCodec::onGetFrameCount() {
Frame* frame = fFrameHolder.appendNewFrame(iter.has_alpha);
frame->setXYWH(iter.x_offset, iter.y_offset, iter.width, iter.height);
frame->setDisposalMethod(iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ?
- SkCodecAnimation::RestoreBGColor_DisposalMethod :
- SkCodecAnimation::Keep_DisposalMethod);
+ SkCodecAnimation::DisposalMethod::kRestoreBGColor :
+ SkCodecAnimation::DisposalMethod::kKeep);
frame->setDuration(iter.duration);
if (WEBP_MUX_BLEND != iter.blend_method) {
frame->setBlend(SkCodecAnimation::Blend::kBG);
@@ -292,6 +294,7 @@ bool SkWebpCodec::onGetFrameInfo(int i, FrameInfo* frameInfo) const {
// animated image.
frameInfo->fFullyReceived = true;
frameInfo->fAlphaType = alpha_type(frame->hasAlpha());
+ frameInfo->fDisposalMethod = frame->getDisposalMethod();
}
return true;
@@ -437,9 +440,15 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
SkSampler::Fill(dstInfo, dst, rowBytes, 0, options.fZeroInitialized);
}
} else {
- if (!options.fHasPriorFrame) {
+ // FIXME: Share with GIF
+ if (options.fPriorFrame != kNone) {
+ if (options.fPriorFrame < requiredFrame || options.fPriorFrame >= index) {
+ return kInvalidParameters;
+ }
+ } else {
Options prevFrameOpts(options);
prevFrameOpts.fFrameIndex = requiredFrame;
+ prevFrameOpts.fPriorFrame = kNone;
const auto result = this->getPixels(dstInfo, dst, rowBytes, &prevFrameOpts,
nullptr, nullptr);
switch (result) {
@@ -452,16 +461,20 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
}
}
- // Dispose bg color
- const Frame* priorFrame = fFrameHolder.frame(requiredFrame);
- if (priorFrame->getDisposalMethod() == SkCodecAnimation::RestoreBGColor_DisposalMethod) {
- // FIXME: If we add support for scaling/subsets, this rectangle needs to be adjusted.
- const auto priorRect = priorFrame->frameRect();
- const auto info = dstInfo.makeWH(priorRect.width(), priorRect.height());
- const size_t bpp = SkColorTypeBytesPerPixel(dstInfo.colorType());
- const size_t offset = priorRect.x() * bpp + priorRect.y() * rowBytes;
- auto* eraseDst = SkTAddOffset<void>(dst, offset);
- SkSampler::Fill(info, eraseDst, rowBytes, 0, kNo_ZeroInitialized);
+ if (options.fPriorFrame == requiredFrame || options.fPriorFrame == kNone) {
+ // Dispose bg color
+ const Frame* priorFrame = fFrameHolder.frame(requiredFrame);
+ if (priorFrame->getDisposalMethod()
+ == SkCodecAnimation::DisposalMethod::kRestoreBGColor) {
+ // FIXME: If we add support for scaling/subsets, this rectangle needs to be
+ // adjusted.
+ const auto priorRect = priorFrame->frameRect();
+ const auto info = dstInfo.makeWH(priorRect.width(), priorRect.height());
+ const size_t bpp = SkColorTypeBytesPerPixel(dstInfo.colorType());
+ const size_t offset = priorRect.x() * bpp + priorRect.y() * rowBytes;
+ auto* eraseDst = SkTAddOffset<void>(dst, offset);
+ SkSampler::Fill(info, eraseDst, rowBytes, 0, kNo_ZeroInitialized);
+ }
}
}