OLD | NEW |
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_frameSchedulingState(Idle) |
46 , m_documentOrderIndexesDirty(false) | 47 , m_documentOrderIndexesDirty(false) |
47 , m_timer(this, &SMILTimeContainer::timerFired) | 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 Loading... |
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 { |
| 111 if (!isStarted()) |
| 112 return; |
104 // Schedule updateAnimations() to be called asynchronously so multiple inter
vals | 113 // Schedule updateAnimations() to be called asynchronously so multiple inter
vals |
105 // can change with updateAnimations() only called once at the end. | 114 // can change with updateAnimations() only called once at the end. |
106 scheduleAnimationFrame(); | 115 if (m_frameSchedulingState == SynchronizeAnimations && m_wakeupTimer.isActiv
e() && !m_wakeupTimer.nextFireInterval()) |
| 116 return; |
| 117 cancelAnimationFrame(); |
| 118 scheduleWakeUp(0, SynchronizeAnimations); |
107 } | 119 } |
108 | 120 |
109 SMILTime SMILTimeContainer::elapsed() const | 121 SMILTime SMILTimeContainer::elapsed() const |
110 { | 122 { |
111 if (!m_beginTime) | 123 if (!m_beginTime) |
112 return 0; | 124 return 0; |
113 | 125 |
114 if (isPaused()) | 126 if (isPaused()) |
115 return m_accumulatedActiveTime; | 127 return m_accumulatedActiveTime; |
116 | 128 |
(...skipping 11 matching lines...) Expand all Loading... |
128 } | 140 } |
129 | 141 |
130 void SMILTimeContainer::begin() | 142 void SMILTimeContainer::begin() |
131 { | 143 { |
132 ASSERT(!m_beginTime); | 144 ASSERT(!m_beginTime); |
133 double now = currentTime(); | 145 double now = currentTime(); |
134 | 146 |
135 // If 'm_presetStartTime' is set, the timeline was modified via setElapsed()
before the document began. | 147 // 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(). | 148 // In this case pass on 'seekToTime=true' to updateAnimations(). |
137 m_beginTime = now - m_presetStartTime; | 149 m_beginTime = now - m_presetStartTime; |
138 updateAnimations(SMILTime(m_presetStartTime), m_presetStartTime ? true : fal
se); | 150 SMILTime earliestFireTime = updateAnimations(SMILTime(m_presetStartTime), m_
presetStartTime ? true : false); |
139 m_presetStartTime = 0; | 151 m_presetStartTime = 0; |
140 | 152 |
141 if (m_pauseTime) { | 153 if (m_pauseTime) { |
142 m_pauseTime = now; | 154 m_pauseTime = now; |
143 cancelAnimationFrame(); | 155 cancelAnimationFrame(); |
| 156 } else { |
| 157 ASSERT(isTimelineRunning()); |
| 158 // If the timeline is running, and there's pending animation updates, |
| 159 // always perform the first update after the timeline was started using |
| 160 // the wake-up mechanism. |
| 161 if (earliestFireTime.isFinite()) { |
| 162 scheduleWakeUp(DocumentTimeline::s_minimumDelay, SynchronizeAnimatio
ns); |
| 163 } |
144 } | 164 } |
145 } | 165 } |
146 | 166 |
147 void SMILTimeContainer::pause() | 167 void SMILTimeContainer::pause() |
148 { | 168 { |
149 ASSERT(!isPaused()); | 169 ASSERT(!isPaused()); |
150 m_pauseTime = currentTime(); | 170 m_pauseTime = currentTime(); |
151 | 171 |
152 if (m_beginTime) { | 172 if (m_beginTime) { |
153 m_accumulatedActiveTime += m_pauseTime - lastResumeTime(); | 173 m_accumulatedActiveTime += m_pauseTime - lastResumeTime(); |
154 cancelAnimationFrame(); | 174 cancelAnimationFrame(); |
155 } | 175 } |
156 m_resumeTime = 0; | 176 m_resumeTime = 0; |
157 } | 177 } |
158 | 178 |
159 void SMILTimeContainer::resume() | 179 void SMILTimeContainer::resume() |
160 { | 180 { |
161 ASSERT(isPaused()); | 181 ASSERT(isPaused()); |
162 m_resumeTime = currentTime(); | 182 m_resumeTime = currentTime(); |
163 | 183 |
164 m_pauseTime = 0; | 184 m_pauseTime = 0; |
165 scheduleAnimationFrame(); | 185 serviceOnNextFrame(); |
166 } | 186 } |
167 | 187 |
168 void SMILTimeContainer::setElapsed(SMILTime time) | 188 void SMILTimeContainer::setElapsed(SMILTime time) |
169 { | 189 { |
170 // If the documment didn't begin yet, record a new start time, we'll seek to
once its possible. | 190 // If the documment didn't begin yet, record a new start time, we'll seek to
once its possible. |
171 if (!m_beginTime) { | 191 if (!m_beginTime) { |
172 m_presetStartTime = time.value(); | 192 m_presetStartTime = time.value(); |
173 return; | 193 return; |
174 } | 194 } |
175 | 195 |
176 if (m_beginTime) | 196 cancelAnimationFrame(); |
177 cancelAnimationFrame(); | |
178 | 197 |
179 double now = currentTime(); | 198 double now = currentTime(); |
180 m_beginTime = now - time.value(); | 199 m_beginTime = now - time.value(); |
181 m_resumeTime = 0; | 200 m_resumeTime = 0; |
182 if (m_pauseTime) { | 201 if (m_pauseTime) { |
183 m_pauseTime = now; | 202 m_pauseTime = now; |
184 m_accumulatedActiveTime = time.value(); | 203 m_accumulatedActiveTime = time.value(); |
185 } else { | 204 } else { |
186 m_accumulatedActiveTime = 0; | 205 m_accumulatedActiveTime = 0; |
187 } | 206 } |
188 | 207 |
189 #ifndef NDEBUG | 208 #ifndef NDEBUG |
190 m_preventScheduledAnimationsChanges = true; | 209 m_preventScheduledAnimationsChanges = true; |
191 #endif | 210 #endif |
192 GroupedAnimationsMap::iterator end = m_scheduledAnimations.end(); | 211 GroupedAnimationsMap::iterator end = m_scheduledAnimations.end(); |
193 for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it !
= end; ++it) { | 212 for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it !
= end; ++it) { |
194 AnimationsVector* scheduled = it->value.get(); | 213 AnimationsVector* scheduled = it->value.get(); |
195 unsigned size = scheduled->size(); | 214 unsigned size = scheduled->size(); |
196 for (unsigned n = 0; n < size; n++) | 215 for (unsigned n = 0; n < size; n++) |
197 scheduled->at(n)->reset(); | 216 scheduled->at(n)->reset(); |
198 } | 217 } |
199 #ifndef NDEBUG | 218 #ifndef NDEBUG |
200 m_preventScheduledAnimationsChanges = false; | 219 m_preventScheduledAnimationsChanges = false; |
201 #endif | 220 #endif |
202 | 221 |
203 updateAnimations(time, true); | 222 updateAnimationsAndScheduleFrameIfNeeded(time, true); |
204 } | 223 } |
205 | 224 |
206 bool SMILTimeContainer::isTimelineRunning() const | 225 bool SMILTimeContainer::isTimelineRunning() const |
207 { | 226 { |
208 return m_beginTime && !isPaused(); | 227 return m_beginTime && !isPaused(); |
209 } | 228 } |
210 | 229 |
211 void SMILTimeContainer::scheduleAnimationFrame(SMILTime fireTime) | 230 void SMILTimeContainer::scheduleAnimationFrame(SMILTime fireTime) |
212 { | 231 { |
213 if (!isTimelineRunning()) | 232 ASSERT(isTimelineRunning() && fireTime.isFinite()); |
214 return; | |
215 | 233 |
216 if (!fireTime.isFinite()) | 234 SMILTime delay = fireTime - elapsed(); |
217 return; | 235 if (delay.value() < DocumentTimeline::s_minimumDelay) { |
218 | 236 serviceOnNextFrame(); |
219 SMILTime delay = max(fireTime - elapsed(), SMILTime(animationFrameDelay)); | 237 } else { |
220 m_timer.startOneShot(delay.value()); | 238 scheduleWakeUp(delay.value() - DocumentTimeline::s_minimumDelay, Animati
onFrame); |
221 } | 239 } |
222 | |
223 void SMILTimeContainer::scheduleAnimationFrame() | |
224 { | |
225 if (!isTimelineRunning()) | |
226 return; | |
227 | |
228 m_timer.startOneShot(0); | |
229 } | 240 } |
230 | 241 |
231 void SMILTimeContainer::cancelAnimationFrame() | 242 void SMILTimeContainer::cancelAnimationFrame() |
232 { | 243 { |
233 m_timer.stop(); | 244 m_frameSchedulingState = Idle; |
| 245 m_wakeupTimer.stop(); |
234 } | 246 } |
235 | 247 |
236 void SMILTimeContainer::timerFired(Timer<SMILTimeContainer>*) | 248 void SMILTimeContainer::scheduleWakeUp(double delayTime, FrameSchedulingState fr
ameSchedulingState) |
237 { | 249 { |
238 ASSERT(isTimelineRunning()); | 250 ASSERT(frameSchedulingState != Idle); |
239 updateAnimations(elapsed()); | 251 m_wakeupTimer.startOneShot(delayTime); |
| 252 m_frameSchedulingState = frameSchedulingState; |
| 253 } |
| 254 |
| 255 void SMILTimeContainer::wakeupTimerFired(Timer<SMILTimeContainer>*) |
| 256 { |
| 257 if (m_frameSchedulingState == AnimationFrame) { |
| 258 ASSERT(isTimelineRunning()); |
| 259 m_frameSchedulingState = Idle; |
| 260 serviceOnNextFrame(); |
| 261 } else { |
| 262 ASSERT(m_frameSchedulingState == SynchronizeAnimations); |
| 263 m_frameSchedulingState = Idle; |
| 264 updateAnimationsAndScheduleFrameIfNeeded(elapsed()); |
| 265 } |
240 } | 266 } |
241 | 267 |
242 void SMILTimeContainer::updateDocumentOrderIndexes() | 268 void SMILTimeContainer::updateDocumentOrderIndexes() |
243 { | 269 { |
244 unsigned timingElementCount = 0; | 270 unsigned timingElementCount = 0; |
245 for (Element* element = m_ownerSVGElement; element; element = ElementTravers
al::next(*element, m_ownerSVGElement)) { | 271 for (Element* element = m_ownerSVGElement; element; element = ElementTravers
al::next(*element, m_ownerSVGElement)) { |
246 if (isSVGSMILElement(*element)) | 272 if (isSVGSMILElement(*element)) |
247 toSVGSMILElement(element)->setDocumentOrderIndex(timingElementCount+
+); | 273 toSVGSMILElement(element)->setDocumentOrderIndex(timingElementCount+
+); |
248 } | 274 } |
249 m_documentOrderIndexesDirty = false; | 275 m_documentOrderIndexesDirty = false; |
250 } | 276 } |
251 | 277 |
252 struct PriorityCompare { | 278 struct PriorityCompare { |
253 PriorityCompare(SMILTime elapsed) : m_elapsed(elapsed) {} | 279 PriorityCompare(SMILTime elapsed) : m_elapsed(elapsed) {} |
254 bool operator()(const RefPtr<SVGSMILElement>& a, const RefPtr<SVGSMILElement
>& b) | 280 bool operator()(const RefPtr<SVGSMILElement>& a, const RefPtr<SVGSMILElement
>& b) |
255 { | 281 { |
256 // FIXME: This should also consider possible timing relations between th
e elements. | 282 // FIXME: This should also consider possible timing relations between th
e elements. |
257 SMILTime aBegin = a->intervalBegin(); | 283 SMILTime aBegin = a->intervalBegin(); |
258 SMILTime bBegin = b->intervalBegin(); | 284 SMILTime bBegin = b->intervalBegin(); |
259 // Frozen elements need to be prioritized based on their previous interv
al. | 285 // Frozen elements need to be prioritized based on their previous interv
al. |
260 aBegin = a->isFrozen() && m_elapsed < aBegin ? a->previousIntervalBegin(
) : aBegin; | 286 aBegin = a->isFrozen() && m_elapsed < aBegin ? a->previousIntervalBegin(
) : aBegin; |
261 bBegin = b->isFrozen() && m_elapsed < bBegin ? b->previousIntervalBegin(
) : bBegin; | 287 bBegin = b->isFrozen() && m_elapsed < bBegin ? b->previousIntervalBegin(
) : bBegin; |
262 if (aBegin == bBegin) | 288 if (aBegin == bBegin) |
263 return a->documentOrderIndex() < b->documentOrderIndex(); | 289 return a->documentOrderIndex() < b->documentOrderIndex(); |
264 return aBegin < bBegin; | 290 return aBegin < bBegin; |
265 } | 291 } |
266 SMILTime m_elapsed; | 292 SMILTime m_elapsed; |
267 }; | 293 }; |
268 | 294 |
269 void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) | 295 Document& SMILTimeContainer::document() const |
| 296 { |
| 297 ASSERT(m_ownerSVGElement); |
| 298 return m_ownerSVGElement->document(); |
| 299 } |
| 300 |
| 301 AnimationClock& SMILTimeContainer::animationClock() const |
| 302 { |
| 303 ASSERT(m_animationClock); |
| 304 return *m_animationClock; |
| 305 } |
| 306 |
| 307 double SMILTimeContainer::currentTime() const |
| 308 { |
| 309 return animationClock().currentTime(); |
| 310 } |
| 311 |
| 312 void SMILTimeContainer::serviceOnNextFrame() |
| 313 { |
| 314 if (document().view()) { |
| 315 document().view()->scheduleAnimation(); |
| 316 m_frameSchedulingState = AnimationFrame; |
| 317 } |
| 318 } |
| 319 |
| 320 void SMILTimeContainer::serviceAnimations(double monotonicAnimationStartTime) |
| 321 { |
| 322 if (m_frameSchedulingState != AnimationFrame) |
| 323 return; |
| 324 |
| 325 m_frameSchedulingState = Idle; |
| 326 animationClock().updateTime(monotonicAnimationStartTime); |
| 327 updateAnimationsAndScheduleFrameIfNeeded(elapsed()); |
| 328 animationClock().unfreeze(); |
| 329 } |
| 330 |
| 331 void SMILTimeContainer::updateAnimationsAndScheduleFrameIfNeeded(SMILTime elapse
d, bool seekToTime) |
| 332 { |
| 333 SMILTime earliestFireTime = updateAnimations(elapsed, seekToTime); |
| 334 if (!isTimelineRunning()) |
| 335 return; |
| 336 |
| 337 if (!earliestFireTime.isFinite()) |
| 338 return; |
| 339 |
| 340 scheduleAnimationFrame(earliestFireTime); |
| 341 } |
| 342 |
| 343 SMILTime SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) |
270 { | 344 { |
271 SMILTime earliestFireTime = SMILTime::unresolved(); | 345 SMILTime earliestFireTime = SMILTime::unresolved(); |
272 | 346 |
273 #ifndef NDEBUG | 347 #ifndef NDEBUG |
274 // This boolean will catch any attempts to schedule/unschedule scheduledAnim
ations during this critical section. | 348 // 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. | 349 // Similarly, any elements removed will unschedule themselves, so this will
catch modification of animationsToApply. |
276 m_preventScheduledAnimationsChanges = true; | 350 m_preventScheduledAnimationsChanges = true; |
277 #endif | 351 #endif |
278 | 352 |
279 if (m_documentOrderIndexesDirty) | 353 if (m_documentOrderIndexesDirty) |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 animationsToApply.append(resultElement); | 393 animationsToApply.append(resultElement); |
320 } | 394 } |
321 | 395 |
322 std::sort(animationsToApply.begin(), animationsToApply.end(), PriorityCompar
e(elapsed)); | 396 std::sort(animationsToApply.begin(), animationsToApply.end(), PriorityCompar
e(elapsed)); |
323 | 397 |
324 unsigned animationsToApplySize = animationsToApply.size(); | 398 unsigned animationsToApplySize = animationsToApply.size(); |
325 if (!animationsToApplySize) { | 399 if (!animationsToApplySize) { |
326 #ifndef NDEBUG | 400 #ifndef NDEBUG |
327 m_preventScheduledAnimationsChanges = false; | 401 m_preventScheduledAnimationsChanges = false; |
328 #endif | 402 #endif |
329 scheduleAnimationFrame(earliestFireTime); | 403 return earliestFireTime; |
330 return; | |
331 } | 404 } |
332 | 405 |
333 // Apply results to target elements. | 406 // Apply results to target elements. |
334 for (unsigned i = 0; i < animationsToApplySize; ++i) | 407 for (unsigned i = 0; i < animationsToApplySize; ++i) |
335 animationsToApply[i]->applyResultsToTarget(); | 408 animationsToApply[i]->applyResultsToTarget(); |
336 | 409 |
337 #ifndef NDEBUG | 410 #ifndef NDEBUG |
338 m_preventScheduledAnimationsChanges = false; | 411 m_preventScheduledAnimationsChanges = false; |
339 #endif | 412 #endif |
340 | 413 |
341 scheduleAnimationFrame(earliestFireTime); | |
342 | |
343 for (unsigned i = 0; i < animationsToApplySize; ++i) { | 414 for (unsigned i = 0; i < animationsToApplySize; ++i) { |
344 if (animationsToApply[i]->inDocument() && animationsToApply[i]->isSVGDis
cardElement()) { | 415 if (animationsToApply[i]->inDocument() && animationsToApply[i]->isSVGDis
cardElement()) { |
345 RefPtr<SVGSMILElement> animDiscard = animationsToApply[i]; | 416 RefPtr<SVGSMILElement> animDiscard = animationsToApply[i]; |
346 RefPtr<SVGElement> targetElement = animDiscard->targetElement(); | 417 RefPtr<SVGElement> targetElement = animDiscard->targetElement(); |
347 if (targetElement && targetElement->inDocument()) { | 418 if (targetElement && targetElement->inDocument()) { |
348 targetElement->remove(IGNORE_EXCEPTION); | 419 targetElement->remove(IGNORE_EXCEPTION); |
349 ASSERT(!targetElement->inDocument()); | 420 ASSERT(!targetElement->inDocument()); |
350 } | 421 } |
351 | 422 |
352 if (animDiscard->inDocument()) { | 423 if (animDiscard->inDocument()) { |
353 animDiscard->remove(IGNORE_EXCEPTION); | 424 animDiscard->remove(IGNORE_EXCEPTION); |
354 ASSERT(!animDiscard->inDocument()); | 425 ASSERT(!animDiscard->inDocument()); |
355 } | 426 } |
356 } | 427 } |
357 } | 428 } |
| 429 return earliestFireTime; |
358 } | 430 } |
359 | 431 |
360 } | 432 } |
OLD | NEW |