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 |
(...skipping 14 matching lines...) Expand all Loading... |
25 | 25 |
26 #include "core/svg/animation/SMILTimeContainer.h" | 26 #include "core/svg/animation/SMILTimeContainer.h" |
27 | 27 |
28 #include "core/animation/AnimationClock.h" | 28 #include "core/animation/AnimationClock.h" |
29 #include "core/animation/DocumentTimeline.h" | 29 #include "core/animation/DocumentTimeline.h" |
30 #include "core/dom/ElementTraversal.h" | 30 #include "core/dom/ElementTraversal.h" |
31 #include "core/frame/FrameView.h" | 31 #include "core/frame/FrameView.h" |
32 #include "core/frame/Settings.h" | 32 #include "core/frame/Settings.h" |
33 #include "core/frame/UseCounter.h" | 33 #include "core/frame/UseCounter.h" |
34 #include "core/svg/SVGSVGElement.h" | 34 #include "core/svg/SVGSVGElement.h" |
| 35 #include "core/svg/animation/SMILTime.h" |
35 #include "core/svg/animation/SVGSMILElement.h" | 36 #include "core/svg/animation/SVGSMILElement.h" |
36 #include <algorithm> | 37 #include <algorithm> |
37 | 38 |
38 namespace blink { | 39 namespace blink { |
39 | 40 |
40 static const double initialFrameDelay = 0.025; | 41 static const double initialFrameDelay = 0.025; |
41 static const double animationPolicyOnceDuration = 3.000; | 42 static const double animationPolicyOnceDuration = 3.000; |
42 | 43 |
43 SMILTimeContainer::SMILTimeContainer(SVGSVGElement& owner) | 44 SMILTimeContainer::SMILTimeContainer(SVGSVGElement& owner) |
44 : m_presentationTime(0) | 45 : m_presentationTime(0) |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 if (!isStarted()) | 127 if (!isStarted()) |
127 return; | 128 return; |
128 // Schedule updateAnimations() to be called asynchronously so multiple inter
vals | 129 // Schedule updateAnimations() to be called asynchronously so multiple inter
vals |
129 // can change with updateAnimations() only called once at the end. | 130 // can change with updateAnimations() only called once at the end. |
130 if (hasPendingSynchronization()) | 131 if (hasPendingSynchronization()) |
131 return; | 132 return; |
132 cancelAnimationFrame(); | 133 cancelAnimationFrame(); |
133 scheduleWakeUp(0, SynchronizeAnimations); | 134 scheduleWakeUp(0, SynchronizeAnimations); |
134 } | 135 } |
135 | 136 |
136 SMILTime SMILTimeContainer::elapsed() const | 137 double SMILTimeContainer::elapsed() const |
137 { | 138 { |
138 if (!isStarted()) | 139 if (!isStarted()) |
139 return 0; | 140 return 0; |
140 | 141 |
141 if (isPaused()) | 142 if (isPaused()) |
142 return m_presentationTime; | 143 return m_presentationTime; |
143 | 144 |
144 return m_presentationTime + (document().timeline().currentTimeInternal() - m
_referenceTime); | 145 return m_presentationTime + (document().timeline().currentTimeInternal() - m
_referenceTime); |
145 } | 146 } |
146 | 147 |
(...skipping 28 matching lines...) Expand all Loading... |
175 if (!handleAnimationPolicy(RestartOnceTimerIfNotPaused)) | 176 if (!handleAnimationPolicy(RestartOnceTimerIfNotPaused)) |
176 return; | 177 return; |
177 | 178 |
178 // Sample the document timeline to get a time reference for the "presentatio
n time". | 179 // Sample the document timeline to get a time reference for the "presentatio
n time". |
179 synchronizeToDocumentTimeline(); | 180 synchronizeToDocumentTimeline(); |
180 m_started = true; | 181 m_started = true; |
181 | 182 |
182 // If the "presentation time" is non-zero, the timeline was modified via | 183 // If the "presentation time" is non-zero, the timeline was modified via |
183 // setElapsed() before the document began. | 184 // setElapsed() before the document began. |
184 // In this case pass on 'seekToTime=true' to updateAnimations() to issue a s
eek. | 185 // In this case pass on 'seekToTime=true' to updateAnimations() to issue a s
eek. |
185 SMILTime earliestFireTime = updateAnimations(SMILTime(m_presentationTime), m
_presentationTime ? true : false); | 186 SMILTime earliestFireTime = updateAnimations(m_presentationTime, m_presentat
ionTime ? true : false); |
186 if (!canScheduleFrame(earliestFireTime)) | 187 if (!canScheduleFrame(earliestFireTime)) |
187 return; | 188 return; |
188 // If the timeline is running, and there are pending animation updates, | 189 // If the timeline is running, and there are pending animation updates, |
189 // always perform the first update after the timeline was started using | 190 // always perform the first update after the timeline was started using |
190 // the wake-up mechanism. | 191 // the wake-up mechanism. |
191 SMILTime delay = earliestFireTime - m_presentationTime; | 192 double delayTime = earliestFireTime.value() - m_presentationTime; |
192 scheduleWakeUp(std::max(initialFrameDelay, delay.value()), SynchronizeAnimat
ions); | 193 scheduleWakeUp(std::max(initialFrameDelay, delayTime), SynchronizeAnimations
); |
193 } | 194 } |
194 | 195 |
195 void SMILTimeContainer::pause() | 196 void SMILTimeContainer::pause() |
196 { | 197 { |
197 if (!handleAnimationPolicy(CancelOnceTimer)) | 198 if (!handleAnimationPolicy(CancelOnceTimer)) |
198 return; | 199 return; |
199 DCHECK(!isPaused()); | 200 DCHECK(!isPaused()); |
200 | 201 |
201 if (isStarted()) { | 202 if (isStarted()) { |
202 m_presentationTime = elapsed().value(); | 203 m_presentationTime = elapsed(); |
203 cancelAnimationFrame(); | 204 cancelAnimationFrame(); |
204 } | 205 } |
205 // Update the flag after sampling elapsed(). | 206 // Update the flag after sampling elapsed(). |
206 m_paused = true; | 207 m_paused = true; |
207 } | 208 } |
208 | 209 |
209 void SMILTimeContainer::resume() | 210 void SMILTimeContainer::resume() |
210 { | 211 { |
211 if (!handleAnimationPolicy(RestartOnceTimer)) | 212 if (!handleAnimationPolicy(RestartOnceTimer)) |
212 return; | 213 return; |
213 DCHECK(isPaused()); | 214 DCHECK(isPaused()); |
214 | 215 |
215 m_paused = false; | 216 m_paused = false; |
216 | 217 |
217 if (isStarted()) | 218 if (isStarted()) |
218 synchronizeToDocumentTimeline(); | 219 synchronizeToDocumentTimeline(); |
219 | 220 |
220 scheduleWakeUp(0, SynchronizeAnimations); | 221 scheduleWakeUp(0, SynchronizeAnimations); |
221 } | 222 } |
222 | 223 |
223 void SMILTimeContainer::setElapsed(SMILTime time) | 224 void SMILTimeContainer::setElapsed(double elapsed) |
224 { | 225 { |
225 m_presentationTime = time.value(); | 226 m_presentationTime = elapsed; |
226 | 227 |
227 // If the document hasn't finished loading, |m_presentationTime| will be | 228 // If the document hasn't finished loading, |m_presentationTime| will be |
228 // used as the start time to seek to once it's possible. | 229 // used as the start time to seek to once it's possible. |
229 if (!isStarted()) | 230 if (!isStarted()) |
230 return; | 231 return; |
231 | 232 |
232 if (!handleAnimationPolicy(RestartOnceTimerIfNotPaused)) | 233 if (!handleAnimationPolicy(RestartOnceTimerIfNotPaused)) |
233 return; | 234 return; |
234 | 235 |
235 cancelAnimationFrame(); | 236 cancelAnimationFrame(); |
236 | 237 |
237 if (!isPaused()) | 238 if (!isPaused()) |
238 synchronizeToDocumentTimeline(); | 239 synchronizeToDocumentTimeline(); |
239 | 240 |
240 #if ENABLE(ASSERT) | 241 #if ENABLE(ASSERT) |
241 m_preventScheduledAnimationsChanges = true; | 242 m_preventScheduledAnimationsChanges = true; |
242 #endif | 243 #endif |
243 for (const auto& entry : m_scheduledAnimations) { | 244 for (const auto& entry : m_scheduledAnimations) { |
244 if (!entry.key.first) | 245 if (!entry.key.first) |
245 continue; | 246 continue; |
246 | 247 |
247 AnimationsLinkedHashSet* scheduled = entry.value.get(); | 248 AnimationsLinkedHashSet* scheduled = entry.value.get(); |
248 for (SVGSMILElement* element : *scheduled) | 249 for (SVGSMILElement* element : *scheduled) |
249 element->reset(); | 250 element->reset(); |
250 } | 251 } |
251 #if ENABLE(ASSERT) | 252 #if ENABLE(ASSERT) |
252 m_preventScheduledAnimationsChanges = false; | 253 m_preventScheduledAnimationsChanges = false; |
253 #endif | 254 #endif |
254 | 255 |
255 updateAnimationsAndScheduleFrameIfNeeded(time, true); | 256 updateAnimationsAndScheduleFrameIfNeeded(elapsed, true); |
256 } | 257 } |
257 | 258 |
258 void SMILTimeContainer::scheduleAnimationFrame(double delayTime) | 259 void SMILTimeContainer::scheduleAnimationFrame(double delayTime) |
259 { | 260 { |
260 DCHECK(std::isfinite(delayTime)); | 261 DCHECK(std::isfinite(delayTime)); |
261 DCHECK(isTimelineRunning()); | 262 DCHECK(isTimelineRunning()); |
262 DCHECK(!m_wakeupTimer.isActive()); | 263 DCHECK(!m_wakeupTimer.isActive()); |
263 | 264 |
264 if (delayTime < AnimationTimeline::s_minimumDelay) { | 265 if (delayTime < AnimationTimeline::s_minimumDelay) { |
265 serviceOnNextFrame(); | 266 serviceOnNextFrame(); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
354 | 355 |
355 void SMILTimeContainer::updateDocumentOrderIndexes() | 356 void SMILTimeContainer::updateDocumentOrderIndexes() |
356 { | 357 { |
357 unsigned timingElementCount = 0; | 358 unsigned timingElementCount = 0; |
358 for (SVGSMILElement& element : Traversal<SVGSMILElement>::descendantsOf(owne
rSVGElement())) | 359 for (SVGSMILElement& element : Traversal<SVGSMILElement>::descendantsOf(owne
rSVGElement())) |
359 element.setDocumentOrderIndex(timingElementCount++); | 360 element.setDocumentOrderIndex(timingElementCount++); |
360 m_documentOrderIndexesDirty = false; | 361 m_documentOrderIndexesDirty = false; |
361 } | 362 } |
362 | 363 |
363 struct PriorityCompare { | 364 struct PriorityCompare { |
364 PriorityCompare(SMILTime elapsed) : m_elapsed(elapsed) {} | 365 PriorityCompare(double elapsed) : m_elapsed(elapsed) {} |
365 bool operator()(const Member<SVGSMILElement>& a, const Member<SVGSMILElement
>& b) | 366 bool operator()(const Member<SVGSMILElement>& a, const Member<SVGSMILElement
>& b) |
366 { | 367 { |
367 // FIXME: This should also consider possible timing relations between th
e elements. | 368 // FIXME: This should also consider possible timing relations between th
e elements. |
368 SMILTime aBegin = a->intervalBegin(); | 369 SMILTime aBegin = a->intervalBegin(); |
369 SMILTime bBegin = b->intervalBegin(); | 370 SMILTime bBegin = b->intervalBegin(); |
370 // Frozen elements need to be prioritized based on their previous interv
al. | 371 // Frozen elements need to be prioritized based on their previous interv
al. |
371 aBegin = a->isFrozen() && m_elapsed < aBegin ? a->previousIntervalBegin(
) : aBegin; | 372 aBegin = a->isFrozen() && m_elapsed < aBegin ? a->previousIntervalBegin(
) : aBegin; |
372 bBegin = b->isFrozen() && m_elapsed < bBegin ? b->previousIntervalBegin(
) : bBegin; | 373 bBegin = b->isFrozen() && m_elapsed < bBegin ? b->previousIntervalBegin(
) : bBegin; |
373 if (aBegin == bBegin) | 374 if (aBegin == bBegin) |
374 return a->documentOrderIndex() < b->documentOrderIndex(); | 375 return a->documentOrderIndex() < b->documentOrderIndex(); |
375 return aBegin < bBegin; | 376 return aBegin < bBegin; |
376 } | 377 } |
377 SMILTime m_elapsed; | 378 double m_elapsed; |
378 }; | 379 }; |
379 | 380 |
380 SVGSVGElement& SMILTimeContainer::ownerSVGElement() const | 381 SVGSVGElement& SMILTimeContainer::ownerSVGElement() const |
381 { | 382 { |
382 return *m_ownerSVGElement; | 383 return *m_ownerSVGElement; |
383 } | 384 } |
384 | 385 |
385 Document& SMILTimeContainer::document() const | 386 Document& SMILTimeContainer::document() const |
386 { | 387 { |
387 return ownerSVGElement().document(); | 388 return ownerSVGElement().document(); |
(...skipping 20 matching lines...) Expand all Loading... |
408 { | 409 { |
409 // If there's synchronization pending (most likely due to syncbases), then | 410 // If there's synchronization pending (most likely due to syncbases), then |
410 // let that complete first before attempting to schedule a frame. | 411 // let that complete first before attempting to schedule a frame. |
411 if (hasPendingSynchronization()) | 412 if (hasPendingSynchronization()) |
412 return false; | 413 return false; |
413 if (!isTimelineRunning()) | 414 if (!isTimelineRunning()) |
414 return false; | 415 return false; |
415 return earliestFireTime.isFinite(); | 416 return earliestFireTime.isFinite(); |
416 } | 417 } |
417 | 418 |
418 void SMILTimeContainer::updateAnimationsAndScheduleFrameIfNeeded(SMILTime elapse
d, bool seekToTime) | 419 void SMILTimeContainer::updateAnimationsAndScheduleFrameIfNeeded(double elapsed,
bool seekToTime) |
419 { | 420 { |
420 if (!document().isActive()) | 421 if (!document().isActive()) |
421 return; | 422 return; |
422 | 423 |
423 SMILTime earliestFireTime = updateAnimations(elapsed, seekToTime); | 424 SMILTime earliestFireTime = updateAnimations(elapsed, seekToTime); |
424 if (!canScheduleFrame(earliestFireTime)) | 425 if (!canScheduleFrame(earliestFireTime)) |
425 return; | 426 return; |
426 SMILTime delay = earliestFireTime - elapsed; | 427 double delayTime = earliestFireTime.value() - elapsed; |
427 scheduleAnimationFrame(delay.value()); | 428 scheduleAnimationFrame(delayTime); |
428 } | 429 } |
429 | 430 |
430 SMILTime SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) | 431 SMILTime SMILTimeContainer::updateAnimations(double elapsed, bool seekToTime) |
431 { | 432 { |
432 ASSERT(document().isActive()); | 433 ASSERT(document().isActive()); |
433 SMILTime earliestFireTime = SMILTime::unresolved(); | 434 SMILTime earliestFireTime = SMILTime::unresolved(); |
434 | 435 |
435 #if ENABLE(ASSERT) | 436 #if ENABLE(ASSERT) |
436 // This boolean will catch any attempts to schedule/unschedule scheduledAnim
ations during this critical section. | 437 // This boolean will catch any attempts to schedule/unschedule scheduledAnim
ations during this critical section. |
437 // Similarly, any elements removed will unschedule themselves, so this will
catch modification of animationsToApply. | 438 // Similarly, any elements removed will unschedule themselves, so this will
catch modification of animationsToApply. |
438 m_preventScheduledAnimationsChanges = true; | 439 m_preventScheduledAnimationsChanges = true; |
439 #endif | 440 #endif |
440 | 441 |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 animDiscard->remove(IGNORE_EXCEPTION); | 525 animDiscard->remove(IGNORE_EXCEPTION); |
525 ASSERT(!animDiscard->isConnected()); | 526 ASSERT(!animDiscard->isConnected()); |
526 } | 527 } |
527 } | 528 } |
528 } | 529 } |
529 return earliestFireTime; | 530 return earliestFireTime; |
530 } | 531 } |
531 | 532 |
532 void SMILTimeContainer::advanceFrameForTesting() | 533 void SMILTimeContainer::advanceFrameForTesting() |
533 { | 534 { |
534 setElapsed(elapsed().value() + initialFrameDelay); | 535 setElapsed(elapsed() + initialFrameDelay); |
535 } | 536 } |
536 | 537 |
537 DEFINE_TRACE(SMILTimeContainer) | 538 DEFINE_TRACE(SMILTimeContainer) |
538 { | 539 { |
539 visitor->trace(m_scheduledAnimations); | 540 visitor->trace(m_scheduledAnimations); |
540 visitor->trace(m_ownerSVGElement); | 541 visitor->trace(m_ownerSVGElement); |
541 } | 542 } |
542 | 543 |
543 } // namespace blink | 544 } // namespace blink |
OLD | NEW |