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 */
24class SkFrame : public SkNoncopyable {
25public:
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
145protected:
146 virtual SkEncodedInfo::Alpha onReportedAlpha() const = 0;
147
148private:
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 */
164class SkFrameHolder : public SkNoncopyable {
165public:
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
194protected:
195 int fScreenWidth;
196 int fScreenHeight;
197
198 virtual const SkFrame* onGetFrame(int i) const = 0;
199};
200
201#endif // SkFrameHolder_DEFINED
202