/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkFrameHolder_DEFINED #define SkFrameHolder_DEFINED #include "include/codec/SkCodecAnimation.h" #include "include/core/SkRect.h" #include "include/core/SkTypes.h" #include "include/private/SkEncodedInfo.h" #include "include/private/SkNoncopyable.h" #include "src/codec/SkCodecAnimationPriv.h" /** * Base class for a single frame of an animated image. * * Separate from SkCodec::FrameInfo, which is a pared down * interface that only contains the info the client needs. */ class SkFrame : public SkNoncopyable { public: SkFrame(int id) : fId(id) , fHasAlpha(false) , fRequiredFrame(kUninitialized) , fDisposalMethod(SkCodecAnimation::DisposalMethod::kKeep) , fDuration(0) , fBlend(SkCodecAnimation::Blend::kPriorFrame) { fRect.setEmpty(); } virtual ~SkFrame() {} /** * An explicit move constructor, as * https://en.cppreference.com/w/cpp/language/move_constructor says that * there is no implicit move constructor if there are user-declared * destructors, and we have one, immediately above. * * Without a move constructor, it is harder to use an SkFrame, or an * SkFrame subclass, inside a std::vector. */ SkFrame(SkFrame&&) = default; /** * 0-based index of the frame in the image sequence. */ int frameId() const { return fId; } /** * How this frame reports its alpha. * * This only considers the rectangle of this frame, and * considers it to have alpha even if it is opaque once * blended with the frame behind it. */ SkEncodedInfo::Alpha reportedAlpha() const { return this->onReportedAlpha(); } /** * Cached value representing whether the frame has alpha, * after compositing with the prior frame. */ bool hasAlpha() const { return fHasAlpha; } /** * Cache whether the finished frame has alpha. */ void setHasAlpha(bool alpha) { fHasAlpha = alpha; } /** * Whether enough of the frame has been read to determine * fRequiredFrame and fHasAlpha. */ bool reachedStartOfData() const { return fRequiredFrame != kUninitialized; } /** * The frame this one depends on. * * Must not be called until fRequiredFrame has been set properly. */ int getRequiredFrame() const { SkASSERT(this->reachedStartOfData()); return fRequiredFrame; } /** * Set the frame that this frame depends on. */ void setRequiredFrame(int req) { fRequiredFrame = req; } /** * Set the rectangle that is updated by this frame. */ void setXYWH(int x, int y, int width, int height) { fRect.setXYWH(x, y, width, height); } /** * The rectangle that is updated by this frame. */ SkIRect frameRect() const { return fRect; } int xOffset() const { return fRect.x(); } int yOffset() const { return fRect.y(); } int width() const { return fRect.width(); } int height() const { return fRect.height(); } SkCodecAnimation::DisposalMethod getDisposalMethod() const { return fDisposalMethod; } void setDisposalMethod(SkCodecAnimation::DisposalMethod disposalMethod) { fDisposalMethod = disposalMethod; } /** * Set the duration (in ms) to show this frame. */ void setDuration(int duration) { fDuration = duration; } /** * Duration in ms to show this frame. */ int getDuration() const { return fDuration; } void setBlend(SkCodecAnimation::Blend blend) { fBlend = blend; } SkCodecAnimation::Blend getBlend() const { return fBlend; } protected: virtual SkEncodedInfo::Alpha onReportedAlpha() const = 0; private: static constexpr int kUninitialized = -2; const int fId; bool fHasAlpha; int fRequiredFrame; SkIRect fRect; SkCodecAnimation::DisposalMethod fDisposalMethod; int fDuration; SkCodecAnimation::Blend fBlend; }; /** * Base class for an object which holds the SkFrames of an * image sequence. */ class SkFrameHolder : public SkNoncopyable { public: SkFrameHolder() : fScreenWidth(0) , fScreenHeight(0) {} virtual ~SkFrameHolder() {} /** * Size of the image. Each frame will be contained in * these dimensions (possibly after clipping). */ int screenWidth() const { return fScreenWidth; } int screenHeight() const { return fScreenHeight; } /** * Compute the opacity and required frame, based on * the frame's reportedAlpha and how it blends * with prior frames. */ void setAlphaAndRequiredFrame(SkFrame*); /** * Return the frame with frameId i. */ const SkFrame* getFrame(int i) const { return this->onGetFrame(i); } protected: int fScreenWidth; int fScreenHeight; virtual const SkFrame* onGetFrame(int i) const = 0; }; #endif // SkFrameHolder_DEFINED