Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(301)

Side by Side Diff: Source/core/svg/animation/SMILTimeContainer.cpp

Issue 179293004: Drive SVG Animations via requestAnimationFrame (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Use AnimationClock. Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/svg/animation/SMILTimeContainer.h ('k') | Source/core/svg/graphics/SVGImage.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2008 Apple Inc. All rights reserved. 2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * 12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */ 24 */
25 25
26 #include "config.h" 26 #include "config.h"
27 #include "core/svg/animation/SMILTimeContainer.h" 27 #include "core/svg/animation/SMILTimeContainer.h"
28 28
29 #include "core/animation/AnimationClock.h"
30 #include "core/animation/DocumentTimeline.h"
29 #include "core/dom/ElementTraversal.h" 31 #include "core/dom/ElementTraversal.h"
32 #include "core/frame/FrameView.h"
30 #include "core/svg/SVGSVGElement.h" 33 #include "core/svg/SVGSVGElement.h"
31 #include "core/svg/animation/SVGSMILElement.h" 34 #include "core/svg/animation/SVGSMILElement.h"
32 #include "wtf/CurrentTime.h"
33 35
34 using namespace std; 36 using namespace std;
35 37
36 namespace WebCore { 38 namespace WebCore {
37 39
38 static const double animationFrameDelay = 0.025;
39
40 SMILTimeContainer::SMILTimeContainer(SVGSVGElement* owner) 40 SMILTimeContainer::SMILTimeContainer(SVGSVGElement* owner)
41 : m_beginTime(0) 41 : m_beginTime(0)
42 , m_pauseTime(0) 42 , m_pauseTime(0)
43 , m_resumeTime(0) 43 , m_resumeTime(0)
44 , m_accumulatedActiveTime(0) 44 , m_accumulatedActiveTime(0)
45 , m_presetStartTime(0) 45 , m_presetStartTime(0)
46 , m_documentOrderIndexesDirty(false) 46 , m_documentOrderIndexesDirty(false)
47 , m_timer(this, &SMILTimeContainer::timerFired) 47 , m_framePending(false)
48 , m_animationClock(AnimationClock::create())
49 , m_wakeupTimer(this, &SMILTimeContainer::wakeupTimerFired)
48 , m_ownerSVGElement(owner) 50 , m_ownerSVGElement(owner)
49 #ifndef NDEBUG 51 #ifndef NDEBUG
50 , m_preventScheduledAnimationsChanges(false) 52 , m_preventScheduledAnimationsChanges(false)
51 #endif 53 #endif
52 { 54 {
53 } 55 }
54 56
55 SMILTimeContainer::~SMILTimeContainer() 57 SMILTimeContainer::~SMILTimeContainer()
56 { 58 {
57 cancelAnimationFrame(); 59 cancelAnimationFrame();
58 ASSERT(!m_timer.isActive()); 60 ASSERT(!m_wakeupTimer.isActive());
59 #ifndef NDEBUG 61 #ifndef NDEBUG
60 ASSERT(!m_preventScheduledAnimationsChanges); 62 ASSERT(!m_preventScheduledAnimationsChanges);
61 #endif 63 #endif
62 } 64 }
63 65
64 void SMILTimeContainer::schedule(SVGSMILElement* animation, SVGElement* target, const QualifiedName& attributeName) 66 void SMILTimeContainer::schedule(SVGSMILElement* animation, SVGElement* target, const QualifiedName& attributeName)
65 { 67 {
66 ASSERT(animation->timeContainer() == this); 68 ASSERT(animation->timeContainer() == this);
67 ASSERT(target); 69 ASSERT(target);
68 ASSERT(animation->hasValidAttributeName()); 70 ASSERT(animation->hasValidAttributeName());
(...skipping 23 matching lines...) Expand all
92 #endif 94 #endif
93 95
94 ElementAttributePair key(target, attributeName); 96 ElementAttributePair key(target, attributeName);
95 AnimationsVector* scheduled = m_scheduledAnimations.get(key); 97 AnimationsVector* scheduled = m_scheduledAnimations.get(key);
96 ASSERT(scheduled); 98 ASSERT(scheduled);
97 size_t idx = scheduled->find(animation); 99 size_t idx = scheduled->find(animation);
98 ASSERT(idx != kNotFound); 100 ASSERT(idx != kNotFound);
99 scheduled->remove(idx); 101 scheduled->remove(idx);
100 } 102 }
101 103
104 bool SMILTimeContainer::hasAnimations() const
105 {
106 return !m_scheduledAnimations.isEmpty();
107 }
108
102 void SMILTimeContainer::notifyIntervalsChanged() 109 void SMILTimeContainer::notifyIntervalsChanged()
103 { 110 {
104 // Schedule updateAnimations() to be called asynchronously so multiple inter vals 111 // Schedule updateAnimations() to be called asynchronously so multiple inter vals
105 // can change with updateAnimations() only called once at the end. 112 // can change with updateAnimations() only called once at the end.
106 scheduleAnimationFrame(); 113 scheduleAnimationFrame();
107 } 114 }
108 115
109 SMILTime SMILTimeContainer::elapsed() const 116 SMILTime SMILTimeContainer::elapsed() const
110 { 117 {
111 if (!m_beginTime) 118 if (!m_beginTime)
112 return 0; 119 return 0;
113 120
114 if (isPaused()) 121 if (isPaused())
115 return m_accumulatedActiveTime; 122 return m_accumulatedActiveTime;
116 123
117 return currentTime() + m_accumulatedActiveTime - lastResumeTime(); 124 return m_animationClock->currentTime() + m_accumulatedActiveTime - lastResum eTime();
118 } 125 }
119 126
120 bool SMILTimeContainer::isPaused() const 127 bool SMILTimeContainer::isPaused() const
121 { 128 {
122 return m_pauseTime; 129 return m_pauseTime;
123 } 130 }
124 131
125 bool SMILTimeContainer::isStarted() const 132 bool SMILTimeContainer::isStarted() const
126 { 133 {
127 return m_beginTime; 134 return m_beginTime;
128 } 135 }
129 136
130 void SMILTimeContainer::begin() 137 void SMILTimeContainer::begin()
131 { 138 {
132 ASSERT(!m_beginTime); 139 ASSERT(!m_beginTime);
133 double now = currentTime(); 140 double now = m_animationClock->currentTime();
134 141
135 // If 'm_presetStartTime' is set, the timeline was modified via setElapsed() before the document began. 142 // If 'm_presetStartTime' is set, the timeline was modified via setElapsed() before the document began.
136 // In this case pass on 'seekToTime=true' to updateAnimations(). 143 // In this case pass on 'seekToTime=true' to updateAnimations().
137 m_beginTime = now - m_presetStartTime; 144 m_beginTime = now - m_presetStartTime;
138 updateAnimations(SMILTime(m_presetStartTime), m_presetStartTime ? true : fal se); 145 updateAnimations(SMILTime(m_presetStartTime), m_presetStartTime ? true : fal se);
139 m_presetStartTime = 0; 146 m_presetStartTime = 0;
140 147
141 if (m_pauseTime) { 148 if (m_pauseTime) {
142 m_pauseTime = now; 149 m_pauseTime = now;
143 cancelAnimationFrame(); 150 cancelAnimationFrame();
151 } else {
152 // Latch the clock to this time (0 or the preset start time).
153 m_animationClock->updateTime(now);
144 } 154 }
145 } 155 }
146 156
147 void SMILTimeContainer::pause() 157 void SMILTimeContainer::pause()
148 { 158 {
149 ASSERT(!isPaused()); 159 ASSERT(!isPaused());
150 m_pauseTime = currentTime(); 160 m_pauseTime = m_animationClock->currentTime();
151 161
152 if (m_beginTime) { 162 if (m_beginTime) {
153 m_accumulatedActiveTime += m_pauseTime - lastResumeTime(); 163 m_accumulatedActiveTime += m_pauseTime - lastResumeTime();
154 cancelAnimationFrame(); 164 cancelAnimationFrame();
155 } 165 }
156 m_resumeTime = 0; 166 m_resumeTime = 0;
167 m_animationClock->unfreeze();
157 } 168 }
158 169
159 void SMILTimeContainer::resume() 170 void SMILTimeContainer::resume()
160 { 171 {
161 ASSERT(isPaused()); 172 ASSERT(isPaused());
162 m_resumeTime = currentTime(); 173 m_resumeTime = m_animationClock->currentTime();
163 174
164 m_pauseTime = 0; 175 m_pauseTime = 0;
165 scheduleAnimationFrame(); 176 scheduleAnimationFrame();
177 m_animationClock->unfreeze();
166 } 178 }
167 179
168 void SMILTimeContainer::setElapsed(SMILTime time) 180 void SMILTimeContainer::setElapsed(SMILTime time)
169 { 181 {
170 // If the documment didn't begin yet, record a new start time, we'll seek to once its possible. 182 // If the documment didn't begin yet, record a new start time, we'll seek to once its possible.
171 if (!m_beginTime) { 183 if (!m_beginTime) {
172 m_presetStartTime = time.value(); 184 m_presetStartTime = time.value();
173 return; 185 return;
174 } 186 }
175 187
176 if (m_beginTime) 188 m_animationClock->unfreeze();
177 cancelAnimationFrame();
178 189
179 double now = currentTime(); 190 cancelAnimationFrame();
191
192 double now = m_animationClock->currentTime();
180 m_beginTime = now - time.value(); 193 m_beginTime = now - time.value();
181 m_resumeTime = 0; 194 m_resumeTime = 0;
182 if (m_pauseTime) { 195 if (m_pauseTime) {
183 m_pauseTime = now; 196 m_pauseTime = now;
184 m_accumulatedActiveTime = time.value(); 197 m_accumulatedActiveTime = time.value();
185 } else { 198 } else {
186 m_accumulatedActiveTime = 0; 199 m_accumulatedActiveTime = 0;
187 } 200 }
188 201
189 #ifndef NDEBUG 202 #ifndef NDEBUG
190 m_preventScheduledAnimationsChanges = true; 203 m_preventScheduledAnimationsChanges = true;
191 #endif 204 #endif
192 GroupedAnimationsMap::iterator end = m_scheduledAnimations.end(); 205 GroupedAnimationsMap::iterator end = m_scheduledAnimations.end();
193 for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it ! = end; ++it) { 206 for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it ! = end; ++it) {
194 AnimationsVector* scheduled = it->value.get(); 207 AnimationsVector* scheduled = it->value.get();
195 unsigned size = scheduled->size(); 208 unsigned size = scheduled->size();
196 for (unsigned n = 0; n < size; n++) 209 for (unsigned n = 0; n < size; n++)
197 scheduled->at(n)->reset(); 210 scheduled->at(n)->reset();
198 } 211 }
199 #ifndef NDEBUG 212 #ifndef NDEBUG
200 m_preventScheduledAnimationsChanges = false; 213 m_preventScheduledAnimationsChanges = false;
201 #endif 214 #endif
202 215
203 updateAnimations(time, true); 216 updateAnimations(time, true);
217 // Latch the clock to wait for this frame to be sampled by the frame interva l.
218 m_animationClock->updateTime(now);
204 } 219 }
205 220
206 bool SMILTimeContainer::isTimelineRunning() const 221 bool SMILTimeContainer::isTimelineRunning() const
207 { 222 {
208 return m_beginTime && !isPaused(); 223 return m_beginTime && !isPaused();
209 } 224 }
210 225
211 void SMILTimeContainer::scheduleAnimationFrame(SMILTime fireTime) 226 void SMILTimeContainer::scheduleAnimationFrame(SMILTime fireTime)
212 { 227 {
213 if (!isTimelineRunning()) 228 if (!isTimelineRunning())
214 return; 229 return;
215 230
216 if (!fireTime.isFinite()) 231 if (!fireTime.isFinite())
217 return; 232 return;
218 233
219 SMILTime delay = max(fireTime - elapsed(), SMILTime(animationFrameDelay)); 234 SMILTime delay = fireTime - elapsed();
220 m_timer.startOneShot(delay.value()); 235 if (delay.value() < DocumentTimeline::s_minimumDelay)
236 serviceOnNextFrame();
237 else
238 m_wakeupTimer.startOneShot(delay.value() - DocumentTimeline::s_minimumDe lay);
221 } 239 }
222 240
223 void SMILTimeContainer::scheduleAnimationFrame() 241 void SMILTimeContainer::scheduleAnimationFrame()
224 { 242 {
225 if (!isTimelineRunning()) 243 if (!isTimelineRunning())
226 return; 244 return;
227 245
228 m_timer.startOneShot(0); 246 // Could also schedule a wakeup at +0 seconds, but that could still
247 // potentially race with the servicing of the next frame.
248 serviceOnNextFrame();
229 } 249 }
230 250
231 void SMILTimeContainer::cancelAnimationFrame() 251 void SMILTimeContainer::cancelAnimationFrame()
232 { 252 {
233 m_timer.stop(); 253 m_framePending = false;
254 m_wakeupTimer.stop();
234 } 255 }
235 256
236 void SMILTimeContainer::timerFired(Timer<SMILTimeContainer>*) 257 void SMILTimeContainer::wakeupTimerFired(Timer<SMILTimeContainer>*)
237 { 258 {
238 ASSERT(isTimelineRunning()); 259 ASSERT(isTimelineRunning());
239 updateAnimations(elapsed()); 260 serviceOnNextFrame();
240 } 261 }
241 262
242 void SMILTimeContainer::updateDocumentOrderIndexes() 263 void SMILTimeContainer::updateDocumentOrderIndexes()
243 { 264 {
244 unsigned timingElementCount = 0; 265 unsigned timingElementCount = 0;
245 for (Element* element = m_ownerSVGElement; element; element = ElementTravers al::next(*element, m_ownerSVGElement)) { 266 for (Element* element = m_ownerSVGElement; element; element = ElementTravers al::next(*element, m_ownerSVGElement)) {
246 if (isSVGSMILElement(*element)) 267 if (isSVGSMILElement(*element))
247 toSVGSMILElement(element)->setDocumentOrderIndex(timingElementCount+ +); 268 toSVGSMILElement(element)->setDocumentOrderIndex(timingElementCount+ +);
248 } 269 }
249 m_documentOrderIndexesDirty = false; 270 m_documentOrderIndexesDirty = false;
250 } 271 }
251 272
252 struct PriorityCompare { 273 struct PriorityCompare {
253 PriorityCompare(SMILTime elapsed) : m_elapsed(elapsed) {} 274 PriorityCompare(SMILTime elapsed) : m_elapsed(elapsed) {}
254 bool operator()(const RefPtr<SVGSMILElement>& a, const RefPtr<SVGSMILElement >& b) 275 bool operator()(const RefPtr<SVGSMILElement>& a, const RefPtr<SVGSMILElement >& b)
255 { 276 {
256 // FIXME: This should also consider possible timing relations between th e elements. 277 // FIXME: This should also consider possible timing relations between th e elements.
257 SMILTime aBegin = a->intervalBegin(); 278 SMILTime aBegin = a->intervalBegin();
258 SMILTime bBegin = b->intervalBegin(); 279 SMILTime bBegin = b->intervalBegin();
259 // Frozen elements need to be prioritized based on their previous interv al. 280 // Frozen elements need to be prioritized based on their previous interv al.
260 aBegin = a->isFrozen() && m_elapsed < aBegin ? a->previousIntervalBegin( ) : aBegin; 281 aBegin = a->isFrozen() && m_elapsed < aBegin ? a->previousIntervalBegin( ) : aBegin;
261 bBegin = b->isFrozen() && m_elapsed < bBegin ? b->previousIntervalBegin( ) : bBegin; 282 bBegin = b->isFrozen() && m_elapsed < bBegin ? b->previousIntervalBegin( ) : bBegin;
262 if (aBegin == bBegin) 283 if (aBegin == bBegin)
263 return a->documentOrderIndex() < b->documentOrderIndex(); 284 return a->documentOrderIndex() < b->documentOrderIndex();
264 return aBegin < bBegin; 285 return aBegin < bBegin;
265 } 286 }
266 SMILTime m_elapsed; 287 SMILTime m_elapsed;
267 }; 288 };
268 289
290 Document& SMILTimeContainer::document() const
291 {
292 ASSERT(m_ownerSVGElement);
293 return m_ownerSVGElement->document();
294 }
295
296 void SMILTimeContainer::serviceOnNextFrame()
297 {
298 if (document().view()) {
299 document().view()->scheduleAnimation();
300 m_framePending = true;
301 }
302 }
303
304 void SMILTimeContainer::serviceAnimations(double monotonicAnimationStartTime)
305 {
306 if (!m_framePending)
307 return;
308
309 m_framePending = false;
310 // If the clock is frozen at this point, it means the timeline has been
311 // started, but the first animation frame hasn't yet been serviced. If so,
312 // then just keep the clock frozen for this update.
313 if (!m_animationClock->isFrozen())
314 m_animationClock->updateTime(monotonicAnimationStartTime);
315 updateAnimations(elapsed());
316 m_animationClock->unfreeze();
317 }
318
269 void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) 319 void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime)
270 { 320 {
271 SMILTime earliestFireTime = SMILTime::unresolved(); 321 SMILTime earliestFireTime = SMILTime::unresolved();
272 322
273 #ifndef NDEBUG 323 #ifndef NDEBUG
274 // This boolean will catch any attempts to schedule/unschedule scheduledAnim ations during this critical section. 324 // This boolean will catch any attempts to schedule/unschedule scheduledAnim ations during this critical section.
275 // Similarly, any elements removed will unschedule themselves, so this will catch modification of animationsToApply. 325 // Similarly, any elements removed will unschedule themselves, so this will catch modification of animationsToApply.
276 m_preventScheduledAnimationsChanges = true; 326 m_preventScheduledAnimationsChanges = true;
277 #endif 327 #endif
278 328
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
351 401
352 if (animDiscard->inDocument()) { 402 if (animDiscard->inDocument()) {
353 animDiscard->remove(IGNORE_EXCEPTION); 403 animDiscard->remove(IGNORE_EXCEPTION);
354 ASSERT(!animDiscard->inDocument()); 404 ASSERT(!animDiscard->inDocument());
355 } 405 }
356 } 406 }
357 } 407 }
358 } 408 }
359 409
360 } 410 }
OLDNEW
« no previous file with comments | « Source/core/svg/animation/SMILTimeContainer.h ('k') | Source/core/svg/graphics/SVGImage.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698