1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkFrameHolder_DEFINED
9 #define SkFrameHolder_DEFINED
10 
11 #include "include/codec/SkCodecAnimation.h"
12 #include "include/core/SkRect.h"
13 #include "include/core/SkTypes.h"
14 #include "include/private/SkEncodedInfo.h"
15 #include "include/private/SkNoncopyable.h"
16 #include "src/codec/SkCodecAnimationPriv.h"
17 
18 /**
19  *  Base class for a single frame of an animated image.
20  *
21  *  Separate from SkCodec::FrameInfo, which is a pared down
22  *  interface that only contains the info the client needs.
23  */
24 class SkFrame : public SkNoncopyable {
25 public:
SkFrame(int id)26     SkFrame(int id)
27         : fId(id)
28         , fHasAlpha(false)
29         , fRequiredFrame(kUninitialized)
30         , fDisposalMethod(SkCodecAnimation::DisposalMethod::kKeep)
31         , fDuration(0)
32         , fBlend(SkCodecAnimation::Blend::kPriorFrame)
33     {
34         fRect.setEmpty();
35     }
36 
~SkFrame()37     virtual ~SkFrame() {}
38 
39     /**
40      * An explicit move constructor, as
41      * https://en.cppreference.com/w/cpp/language/move_constructor says that
42      * there is no implicit move constructor if there are user-declared
43      * destructors, and we have one, immediately above.
44      *
45      * Without a move constructor, it is harder to use an SkFrame, or an
46      * SkFrame subclass, inside a std::vector.
47      */
48     SkFrame(SkFrame&&) = default;
49 
50     /**
51      *  0-based index of the frame in the image sequence.
52      */
frameId()53     int frameId() const { return fId; }
54 
55     /**
56      *  How this frame reports its alpha.
57      *
58      *  This only considers the rectangle of this frame, and
59      *  considers it to have alpha even if it is opaque once
60      *  blended with the frame behind it.
61      */
reportedAlpha()62     SkEncodedInfo::Alpha reportedAlpha() const {
63         return this->onReportedAlpha();
64     }
65 
66     /**
67      *  Cached value representing whether the frame has alpha,
68      *  after compositing with the prior frame.
69      */
hasAlpha()70     bool hasAlpha() const { return fHasAlpha; }
71 
72     /**
73      *  Cache whether the finished frame has alpha.
74      */
setHasAlpha(bool alpha)75     void setHasAlpha(bool alpha) { fHasAlpha = alpha; }
76 
77     /**
78      *  Whether enough of the frame has been read to determine
79      *  fRequiredFrame and fHasAlpha.
80      */
reachedStartOfData()81     bool reachedStartOfData() const { return fRequiredFrame != kUninitialized; }
82 
83     /**
84      *  The frame this one depends on.
85      *
86      *  Must not be called until fRequiredFrame has been set properly.
87      */
getRequiredFrame()88     int getRequiredFrame() const {
89         SkASSERT(this->reachedStartOfData());
90         return fRequiredFrame;
91     }
92 
93     /**
94      *  Set the frame that this frame depends on.
95      */
setRequiredFrame(int req)96     void setRequiredFrame(int req) { fRequiredFrame = req; }
97 
98     /**
99      *  Set the rectangle that is updated by this frame.
100      */
setXYWH(int x,int y,int width,int height)101     void setXYWH(int x, int y, int width, int height) {
102         fRect.setXYWH(x, y, width, height);
103     }
104 
105     /**
106      *  The rectangle that is updated by this frame.
107      */
frameRect()108     SkIRect frameRect() const { return fRect; }
109 
xOffset()110     int xOffset() const { return fRect.x(); }
yOffset()111     int yOffset() const { return fRect.y(); }
width()112     int width()   const { return fRect.width(); }
height()113     int height()  const { return fRect.height(); }
114 
getDisposalMethod()115     SkCodecAnimation::DisposalMethod getDisposalMethod() const {
116         return fDisposalMethod;
117     }
118 
setDisposalMethod(SkCodecAnimation::DisposalMethod disposalMethod)119     void setDisposalMethod(SkCodecAnimation::DisposalMethod disposalMethod) {
120         fDisposalMethod = disposalMethod;
121     }
122 
123     /**
124      * Set the duration (in ms) to show this frame.
125      */
setDuration(int duration)126     void setDuration(int duration) {
127         fDuration = duration;
128     }
129 
130     /**
131      *  Duration in ms to show this frame.
132      */
getDuration()133     int getDuration() const {
134         return fDuration;
135     }
136 
setBlend(SkCodecAnimation::Blend blend)137     void setBlend(SkCodecAnimation::Blend blend) {
138         fBlend = blend;
139     }
140 
getBlend()141     SkCodecAnimation::Blend getBlend() const {
142         return fBlend;
143     }
144 
145 protected:
146     virtual SkEncodedInfo::Alpha onReportedAlpha() const = 0;
147 
148 private:
149     static constexpr int kUninitialized = -2;
150 
151     const int                           fId;
152     bool                                fHasAlpha;
153     int                                 fRequiredFrame;
154     SkIRect                             fRect;
155     SkCodecAnimation::DisposalMethod    fDisposalMethod;
156     int                                 fDuration;
157     SkCodecAnimation::Blend             fBlend;
158 };
159 
160 /**
161  *  Base class for an object which holds the SkFrames of an
162  *  image sequence.
163  */
164 class SkFrameHolder : public SkNoncopyable {
165 public:
SkFrameHolder()166     SkFrameHolder()
167         : fScreenWidth(0)
168         , fScreenHeight(0)
169     {}
170 
~SkFrameHolder()171     virtual ~SkFrameHolder() {}
172 
173     /**
174      *  Size of the image. Each frame will be contained in
175      *  these dimensions (possibly after clipping).
176      */
screenWidth()177     int screenWidth() const { return fScreenWidth; }
screenHeight()178     int screenHeight() const { return fScreenHeight; }
179 
180     /**
181      *  Compute the opacity and required frame, based on
182      *  the frame's reportedAlpha and how it blends
183      *  with prior frames.
184      */
185     void setAlphaAndRequiredFrame(SkFrame*);
186 
187     /**
188      *  Return the frame with frameId i.
189      */
getFrame(int i)190     const SkFrame* getFrame(int i) const {
191         return this->onGetFrame(i);
192     }
193 
194 protected:
195     int fScreenWidth;
196     int fScreenHeight;
197 
198     virtual const SkFrame* onGetFrame(int i) const = 0;
199 };
200 
201 #endif // SkFrameHolder_DEFINED
202