|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 * |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifndef mozilla_imagelib_FrameAnimator_h_ |
|
8 #define mozilla_imagelib_FrameAnimator_h_ |
|
9 |
|
10 #include "mozilla/TimeStamp.h" |
|
11 #include "nsRect.h" |
|
12 |
|
13 namespace mozilla { |
|
14 namespace image { |
|
15 |
|
16 class FrameBlender; |
|
17 |
|
18 class FrameAnimator |
|
19 { |
|
20 public: |
|
21 FrameAnimator(FrameBlender& aBlender, uint16_t aAnimationMode); |
|
22 |
|
23 /** |
|
24 * Return value from RequestRefresh. Tells callers what happened in that call |
|
25 * to RequestRefresh. |
|
26 */ |
|
27 struct RefreshResult |
|
28 { |
|
29 // The dirty rectangle to be re-drawn after this RequestRefresh(). |
|
30 nsIntRect dirtyRect; |
|
31 |
|
32 // Whether any frame changed, and hence the dirty rect was set. |
|
33 bool frameAdvanced : 1; |
|
34 |
|
35 // Whether the animation has finished playing. |
|
36 bool animationFinished : 1; |
|
37 |
|
38 // Whether an error has occurred when trying to advance a frame. Note that |
|
39 // errors do not, on their own, end the animation. |
|
40 bool error : 1; |
|
41 |
|
42 RefreshResult() |
|
43 : frameAdvanced(false) |
|
44 , animationFinished(false) |
|
45 , error(false) |
|
46 {} |
|
47 |
|
48 void Accumulate(const RefreshResult& other) |
|
49 { |
|
50 frameAdvanced = frameAdvanced || other.frameAdvanced; |
|
51 animationFinished = animationFinished || other.animationFinished; |
|
52 error = error || other.error; |
|
53 dirtyRect = dirtyRect.Union(other.dirtyRect); |
|
54 } |
|
55 }; |
|
56 |
|
57 /** |
|
58 * Re-evaluate what frame we're supposed to be on, and do whatever blending |
|
59 * is necessary to get us to that frame. |
|
60 * |
|
61 * Returns the result of that blending, including whether the current frame |
|
62 * changed and what the resulting dirty rectangle is. |
|
63 */ |
|
64 RefreshResult RequestRefresh(const mozilla::TimeStamp& aTime); |
|
65 |
|
66 /** |
|
67 * Call when this image is finished decoding so we know that there aren't any |
|
68 * more frames coming. |
|
69 */ |
|
70 void SetDoneDecoding(bool aDone); |
|
71 |
|
72 /** |
|
73 * Call when you need to re-start animating. Ensures we start from the first |
|
74 * frame. |
|
75 */ |
|
76 void ResetAnimation(); |
|
77 |
|
78 /** |
|
79 * The animation mode of the image. |
|
80 * |
|
81 * Constants defined in imgIContainer.idl. |
|
82 */ |
|
83 void SetAnimationMode(uint16_t aAnimationMode); |
|
84 |
|
85 /** |
|
86 * Set the area to refresh when we loop around to the first frame. |
|
87 */ |
|
88 void SetFirstFrameRefreshArea(const nsIntRect& aRect); |
|
89 |
|
90 /** |
|
91 * Union the area to refresh when we loop around to the first frame with this |
|
92 * rect. |
|
93 */ |
|
94 void UnionFirstFrameRefreshArea(const nsIntRect& aRect); |
|
95 |
|
96 /** |
|
97 * If the animation frame time has not yet been set, set it to |
|
98 * TimeStamp::Now(). |
|
99 */ |
|
100 void InitAnimationFrameTimeIfNecessary(); |
|
101 |
|
102 /** |
|
103 * Set the animation frame time to @aTime. |
|
104 */ |
|
105 void SetAnimationFrameTime(const TimeStamp& aTime); |
|
106 |
|
107 /** |
|
108 * The current frame we're on, from 0 to (numFrames - 1). |
|
109 */ |
|
110 uint32_t GetCurrentAnimationFrameIndex() const; |
|
111 |
|
112 /** |
|
113 * Get the area we refresh when we loop around to the first frame. |
|
114 */ |
|
115 nsIntRect GetFirstFrameRefreshArea() const; |
|
116 |
|
117 private: // methods |
|
118 /** |
|
119 * Gets the length of a single loop of this image, in milliseconds. |
|
120 * |
|
121 * If this image is not finished decoding, is not animated, or it is animated |
|
122 * but does not loop, returns -1. Can return 0 in the case of an animated image |
|
123 * that has a 0ms delay between its frames and does not loop. |
|
124 */ |
|
125 int32_t GetSingleLoopTime() const; |
|
126 |
|
127 /** |
|
128 * Advances the animation. Typically, this will advance a single frame, but it |
|
129 * may advance multiple frames. This may happen if we have infrequently |
|
130 * "ticking" refresh drivers (e.g. in background tabs), or extremely short- |
|
131 * lived animation frames. |
|
132 * |
|
133 * @param aTime the time that the animation should advance to. This will |
|
134 * typically be <= TimeStamp::Now(). |
|
135 * |
|
136 * @returns a RefreshResult that shows whether the frame was successfully |
|
137 * advanced, and its resulting dirty rect. |
|
138 */ |
|
139 RefreshResult AdvanceFrame(mozilla::TimeStamp aTime); |
|
140 |
|
141 /** |
|
142 * Get the time the frame we're currently displaying is supposed to end. |
|
143 * |
|
144 * In the error case, returns an "infinity" timestamp. |
|
145 */ |
|
146 mozilla::TimeStamp GetCurrentImgFrameEndTime() const; |
|
147 |
|
148 private: // data |
|
149 //! Area of the first frame that needs to be redrawn on subsequent loops. |
|
150 nsIntRect mFirstFrameRefreshArea; |
|
151 |
|
152 //! the time that the animation advanced to the current frame |
|
153 TimeStamp mCurrentAnimationFrameTime; |
|
154 |
|
155 //! The current frame index we're on. 0 to (numFrames - 1). |
|
156 uint32_t mCurrentAnimationFrameIndex; |
|
157 |
|
158 //! number of loops remaining before animation stops (-1 no stop) |
|
159 int32_t mLoopCounter; |
|
160 |
|
161 //! All the frames of the image, shared with our owner |
|
162 FrameBlender& mFrameBlender; |
|
163 |
|
164 //! The animation mode of this image. Constants defined in imgIContainer. |
|
165 uint16_t mAnimationMode; |
|
166 |
|
167 //! Whether this image is done being decoded. |
|
168 bool mDoneDecoding; |
|
169 }; |
|
170 |
|
171 } // namespace image |
|
172 } // namespace mozilla |
|
173 |
|
174 #endif /* mozilla_imagelib_FrameAnimator_h_ */ |