diff options
Diffstat (limited to 'src/codec')
-rw-r--r-- | src/codec/SkCodecAnimation.h | 69 | ||||
-rw-r--r-- | src/codec/SkCodecAnimationPriv.h | 32 | ||||
-rw-r--r-- | src/codec/SkFrameHolder.h | 3 | ||||
-rw-r--r-- | src/codec/SkGifCodec.cpp | 63 | ||||
-rw-r--r-- | src/codec/SkWebpCodec.cpp | 39 |
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); + } } } |