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: |
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 | |
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 | */ |
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 | */ |
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 | */ |
70 | bool hasAlpha() const { return fHasAlpha; } |
71 | |
72 | /** |
73 | * Cache whether the finished frame has alpha. |
74 | */ |
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 | */ |
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 | */ |
88 | int getRequiredFrame() const { |
89 | SkASSERT(this->reachedStartOfData()); |
90 | return fRequiredFrame; |
91 | } |
92 | |
93 | /** |
94 | * Set the frame that this frame depends on. |
95 | */ |
96 | void setRequiredFrame(int req) { fRequiredFrame = req; } |
97 | |
98 | /** |
99 | * Set the rectangle that is updated by this frame. |
100 | */ |
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 | */ |
108 | SkIRect frameRect() const { return fRect; } |
109 | |
110 | int xOffset() const { return fRect.x(); } |
111 | int yOffset() const { return fRect.y(); } |
112 | int width() const { return fRect.width(); } |
113 | int height() const { return fRect.height(); } |
114 | |
115 | SkCodecAnimation::DisposalMethod getDisposalMethod() const { |
116 | return fDisposalMethod; |
117 | } |
118 | |
119 | void setDisposalMethod(SkCodecAnimation::DisposalMethod disposalMethod) { |
120 | fDisposalMethod = disposalMethod; |
121 | } |
122 | |
123 | /** |
124 | * Set the duration (in ms) to show this frame. |
125 | */ |
126 | void setDuration(int duration) { |
127 | fDuration = duration; |
128 | } |
129 | |
130 | /** |
131 | * Duration in ms to show this frame. |
132 | */ |
133 | int getDuration() const { |
134 | return fDuration; |
135 | } |
136 | |
137 | void setBlend(SkCodecAnimation::Blend blend) { |
138 | fBlend = blend; |
139 | } |
140 | |
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: |
166 | SkFrameHolder() |
167 | : fScreenWidth(0) |
168 | , fScreenHeight(0) |
169 | {} |
170 | |
171 | virtual ~SkFrameHolder() {} |
172 | |
173 | /** |
174 | * Size of the image. Each frame will be contained in |
175 | * these dimensions (possibly after clipping). |
176 | */ |
177 | int screenWidth() const { return fScreenWidth; } |
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 | */ |
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 | |