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 23 matching lines...) Expand all Loading... |
34 #include "core/svg/SVGSVGElement.h" | 34 #include "core/svg/SVGSVGElement.h" |
35 #include "core/svg/animation/SVGSMILElement.h" | 35 #include "core/svg/animation/SVGSMILElement.h" |
36 #include <algorithm> | 36 #include <algorithm> |
37 | 37 |
38 namespace blink { | 38 namespace blink { |
39 | 39 |
40 static const double initialFrameDelay = 0.025; | 40 static const double initialFrameDelay = 0.025; |
41 static const double animationPolicyOnceDuration = 3.000; | 41 static const double animationPolicyOnceDuration = 3.000; |
42 | 42 |
43 SMILTimeContainer::SMILTimeContainer(SVGSVGElement& owner) | 43 SMILTimeContainer::SMILTimeContainer(SVGSVGElement& owner) |
44 : m_beginTime(0) | 44 : m_presentationTime(0) |
45 , m_pauseTime(0) | 45 , m_referenceTime(0) |
46 , m_resumeTime(0) | |
47 , m_accumulatedActiveTime(0) | |
48 , m_presetStartTime(0) | |
49 , m_frameSchedulingState(Idle) | 46 , m_frameSchedulingState(Idle) |
| 47 , m_started(false) |
| 48 , m_paused(false) |
50 , m_documentOrderIndexesDirty(false) | 49 , m_documentOrderIndexesDirty(false) |
51 , m_wakeupTimer(this, &SMILTimeContainer::wakeupTimerFired) | 50 , m_wakeupTimer(this, &SMILTimeContainer::wakeupTimerFired) |
52 , m_animationPolicyOnceTimer(this, &SMILTimeContainer::animationPolicyTimerF
ired) | 51 , m_animationPolicyOnceTimer(this, &SMILTimeContainer::animationPolicyTimerF
ired) |
53 , m_ownerSVGElement(&owner) | 52 , m_ownerSVGElement(&owner) |
54 #if ENABLE(ASSERT) | 53 #if ENABLE(ASSERT) |
55 , m_preventScheduledAnimationsChanges(false) | 54 , m_preventScheduledAnimationsChanges(false) |
56 #endif | 55 #endif |
57 { | 56 { |
58 } | 57 } |
59 | 58 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
129 // Schedule updateAnimations() to be called asynchronously so multiple inter
vals | 128 // Schedule updateAnimations() to be called asynchronously so multiple inter
vals |
130 // can change with updateAnimations() only called once at the end. | 129 // can change with updateAnimations() only called once at the end. |
131 if (hasPendingSynchronization()) | 130 if (hasPendingSynchronization()) |
132 return; | 131 return; |
133 cancelAnimationFrame(); | 132 cancelAnimationFrame(); |
134 scheduleWakeUp(0, SynchronizeAnimations); | 133 scheduleWakeUp(0, SynchronizeAnimations); |
135 } | 134 } |
136 | 135 |
137 SMILTime SMILTimeContainer::elapsed() const | 136 SMILTime SMILTimeContainer::elapsed() const |
138 { | 137 { |
139 if (!m_beginTime) | 138 if (!isStarted()) |
140 return 0; | 139 return 0; |
141 | 140 |
142 if (isPaused()) | 141 if (isPaused()) |
143 return m_accumulatedActiveTime; | 142 return m_presentationTime; |
144 | 143 |
145 return currentTime() + m_accumulatedActiveTime - lastResumeTime(); | 144 return m_presentationTime + (document().timeline().currentTimeInternal() - m
_referenceTime); |
| 145 } |
| 146 |
| 147 void SMILTimeContainer::synchronizeToDocumentTimeline() |
| 148 { |
| 149 m_referenceTime = document().timeline().currentTimeInternal(); |
146 } | 150 } |
147 | 151 |
148 bool SMILTimeContainer::isPaused() const | 152 bool SMILTimeContainer::isPaused() const |
149 { | 153 { |
150 // If animation policy is "none", it is always paused. | 154 // If animation policy is "none", the timeline is always paused. |
151 return m_pauseTime || animationPolicy() == ImageAnimationPolicyNoAnimation; | 155 return m_paused || animationPolicy() == ImageAnimationPolicyNoAnimation; |
152 } | 156 } |
153 | 157 |
154 bool SMILTimeContainer::isStarted() const | 158 bool SMILTimeContainer::isStarted() const |
155 { | 159 { |
156 return m_beginTime; | 160 return m_started; |
157 } | 161 } |
158 | 162 |
159 void SMILTimeContainer::begin() | 163 bool SMILTimeContainer::isTimelineRunning() const |
160 { | 164 { |
161 RELEASE_ASSERT(!m_beginTime); | 165 return isStarted() && !isPaused(); |
| 166 } |
| 167 |
| 168 void SMILTimeContainer::start() |
| 169 { |
| 170 RELEASE_ASSERT(!isStarted()); |
162 | 171 |
163 if (!document().isActive()) | 172 if (!document().isActive()) |
164 return; | 173 return; |
165 | 174 |
166 if (!handleAnimationPolicy(RestartOnceTimerIfNotPaused)) | 175 if (!handleAnimationPolicy(RestartOnceTimerIfNotPaused)) |
167 return; | 176 return; |
168 | 177 |
169 double now = currentTime(); | 178 // Sample the document timeline to get a time reference for the "presentatio
n time". |
| 179 synchronizeToDocumentTimeline(); |
| 180 m_started = true; |
170 | 181 |
171 // If 'm_presetStartTime' is set, the timeline was modified via setElapsed()
before the document began. | 182 // If the "presentation time" is non-zero, the timeline was modified via |
172 // In this case pass on 'seekToTime=true' to updateAnimations(). | 183 // setElapsed() before the document began. |
173 m_beginTime = now - m_presetStartTime; | 184 // In this case pass on 'seekToTime=true' to updateAnimations() to issue a s
eek. |
174 SMILTime earliestFireTime = updateAnimations(SMILTime(m_presetStartTime), m_
presetStartTime ? true : false); | 185 SMILTime earliestFireTime = updateAnimations(SMILTime(m_presentationTime), m
_presentationTime ? true : false); |
175 m_presetStartTime = 0; | |
176 | 186 |
177 if (m_pauseTime) { | 187 if (isPaused()) { |
178 m_pauseTime = now; | 188 // If updateAnimations() caused new syncbase instances to be generated, |
179 // If updateAnimations() caused new syncbase instance to be generated, | |
180 // we don't want to cancel those. Excepting that, no frame should've | 189 // we don't want to cancel those. Excepting that, no frame should've |
181 // been scheduled at this point. | 190 // been scheduled at this point. |
182 ASSERT(m_frameSchedulingState == Idle || m_frameSchedulingState == Synch
ronizeAnimations); | 191 DCHECK(m_frameSchedulingState == Idle || m_frameSchedulingState == Synch
ronizeAnimations); |
183 } else if (!hasPendingSynchronization()) { | 192 return; |
184 ASSERT(isTimelineRunning()); | |
185 // If the timeline is running, and there's pending animation updates, | |
186 // always perform the first update after the timeline was started using | |
187 // the wake-up mechanism. | |
188 if (earliestFireTime.isFinite()) { | |
189 SMILTime delay = earliestFireTime - elapsed(); | |
190 scheduleWakeUp(std::max(initialFrameDelay, delay.value()), Synchroni
zeAnimations); | |
191 } | |
192 } | 193 } |
| 194 // If synchronizations are pending, those will in turn schedule additional |
| 195 // frames. |
| 196 if (hasPendingSynchronization()) |
| 197 return; |
| 198 DCHECK(isTimelineRunning()); |
| 199 if (!earliestFireTime.isFinite()) |
| 200 return; |
| 201 // If the timeline is running, and there are pending animation updates, |
| 202 // always perform the first update after the timeline was started using |
| 203 // the wake-up mechanism. |
| 204 SMILTime delay = earliestFireTime - m_presentationTime; |
| 205 scheduleWakeUp(std::max(initialFrameDelay, delay.value()), SynchronizeAnimat
ions); |
193 } | 206 } |
194 | 207 |
195 void SMILTimeContainer::pause() | 208 void SMILTimeContainer::pause() |
196 { | 209 { |
197 if (!handleAnimationPolicy(CancelOnceTimer)) | 210 if (!handleAnimationPolicy(CancelOnceTimer)) |
198 return; | 211 return; |
| 212 DCHECK(!isPaused()); |
199 | 213 |
200 ASSERT(!isPaused()); | 214 if (isStarted()) { |
201 m_pauseTime = currentTime(); | 215 m_presentationTime = elapsed().value(); |
202 | |
203 if (m_beginTime) { | |
204 m_accumulatedActiveTime += m_pauseTime - lastResumeTime(); | |
205 cancelAnimationFrame(); | 216 cancelAnimationFrame(); |
206 } | 217 } |
207 m_resumeTime = 0; | 218 // Update the flag after sampling elapsed(). |
| 219 m_paused = true; |
208 } | 220 } |
209 | 221 |
210 void SMILTimeContainer::resume() | 222 void SMILTimeContainer::resume() |
211 { | 223 { |
212 if (!handleAnimationPolicy(RestartOnceTimer)) | 224 if (!handleAnimationPolicy(RestartOnceTimer)) |
213 return; | 225 return; |
| 226 DCHECK(isPaused()); |
214 | 227 |
215 ASSERT(isPaused()); | 228 m_paused = false; |
216 m_resumeTime = currentTime(); | |
217 | 229 |
218 m_pauseTime = 0; | 230 if (isStarted()) |
| 231 synchronizeToDocumentTimeline(); |
| 232 |
219 scheduleWakeUp(0, SynchronizeAnimations); | 233 scheduleWakeUp(0, SynchronizeAnimations); |
220 } | 234 } |
221 | 235 |
222 void SMILTimeContainer::setElapsed(SMILTime time) | 236 void SMILTimeContainer::setElapsed(SMILTime time) |
223 { | 237 { |
224 // If the documment didn't begin yet, record a new start time, we'll seek to
once its possible. | 238 m_presentationTime = time.value(); |
225 if (!m_beginTime) { | 239 |
226 m_presetStartTime = time.value(); | 240 // If the document hasn't finished loading, |m_presentationTime| will be |
| 241 // used as the start time to seek to once it's possible. |
| 242 if (!isStarted()) |
227 return; | 243 return; |
228 } | |
229 | 244 |
230 if (!handleAnimationPolicy(RestartOnceTimerIfNotPaused)) | 245 if (!handleAnimationPolicy(RestartOnceTimerIfNotPaused)) |
231 return; | 246 return; |
232 | 247 |
233 cancelAnimationFrame(); | 248 cancelAnimationFrame(); |
234 | 249 |
235 double now = currentTime(); | 250 if (!isPaused()) |
236 m_beginTime = now - time.value(); | 251 synchronizeToDocumentTimeline(); |
237 m_resumeTime = 0; | |
238 if (m_pauseTime) { | |
239 m_pauseTime = now; | |
240 m_accumulatedActiveTime = time.value(); | |
241 } else { | |
242 m_accumulatedActiveTime = 0; | |
243 } | |
244 | 252 |
245 #if ENABLE(ASSERT) | 253 #if ENABLE(ASSERT) |
246 m_preventScheduledAnimationsChanges = true; | 254 m_preventScheduledAnimationsChanges = true; |
247 #endif | 255 #endif |
248 for (const auto& entry : m_scheduledAnimations) { | 256 for (const auto& entry : m_scheduledAnimations) { |
249 if (!entry.key.first) | 257 if (!entry.key.first) |
250 continue; | 258 continue; |
251 | 259 |
252 AnimationsLinkedHashSet* scheduled = entry.value.get(); | 260 AnimationsLinkedHashSet* scheduled = entry.value.get(); |
253 for (SVGSMILElement* element : *scheduled) | 261 for (SVGSMILElement* element : *scheduled) |
254 element->reset(); | 262 element->reset(); |
255 } | 263 } |
256 #if ENABLE(ASSERT) | 264 #if ENABLE(ASSERT) |
257 m_preventScheduledAnimationsChanges = false; | 265 m_preventScheduledAnimationsChanges = false; |
258 #endif | 266 #endif |
259 | 267 |
260 updateAnimationsAndScheduleFrameIfNeeded(time, true); | 268 updateAnimationsAndScheduleFrameIfNeeded(time, true); |
261 } | 269 } |
262 | 270 |
263 bool SMILTimeContainer::isTimelineRunning() const | 271 void SMILTimeContainer::scheduleAnimationFrame(double delayTime) |
264 { | 272 { |
265 return m_beginTime && !isPaused(); | 273 DCHECK(std::isfinite(delayTime)); |
266 } | 274 DCHECK(isTimelineRunning()); |
| 275 DCHECK(!m_wakeupTimer.isActive()); |
267 | 276 |
268 void SMILTimeContainer::scheduleAnimationFrame(SMILTime fireTime) | 277 if (delayTime < AnimationTimeline::s_minimumDelay) { |
269 { | |
270 ASSERT(isTimelineRunning() && fireTime.isFinite()); | |
271 ASSERT(!m_wakeupTimer.isActive()); | |
272 | |
273 SMILTime delay = fireTime - elapsed(); | |
274 if (delay.value() < AnimationTimeline::s_minimumDelay) { | |
275 serviceOnNextFrame(); | 278 serviceOnNextFrame(); |
276 } else { | 279 } else { |
277 scheduleWakeUp(delay.value() - AnimationTimeline::s_minimumDelay, Future
AnimationFrame); | 280 scheduleWakeUp(delayTime - AnimationTimeline::s_minimumDelay, FutureAnim
ationFrame); |
278 } | 281 } |
279 } | 282 } |
280 | 283 |
281 void SMILTimeContainer::cancelAnimationFrame() | 284 void SMILTimeContainer::cancelAnimationFrame() |
282 { | 285 { |
283 m_frameSchedulingState = Idle; | 286 m_frameSchedulingState = Idle; |
284 m_wakeupTimer.stop(); | 287 m_wakeupTimer.stop(); |
285 } | 288 } |
286 | 289 |
287 void SMILTimeContainer::scheduleWakeUp(double delayTime, FrameSchedulingState fr
ameSchedulingState) | 290 void SMILTimeContainer::scheduleWakeUp(double delayTime, FrameSchedulingState fr
ameSchedulingState) |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 SVGSVGElement& SMILTimeContainer::ownerSVGElement() const | 393 SVGSVGElement& SMILTimeContainer::ownerSVGElement() const |
391 { | 394 { |
392 return *m_ownerSVGElement; | 395 return *m_ownerSVGElement; |
393 } | 396 } |
394 | 397 |
395 Document& SMILTimeContainer::document() const | 398 Document& SMILTimeContainer::document() const |
396 { | 399 { |
397 return ownerSVGElement().document(); | 400 return ownerSVGElement().document(); |
398 } | 401 } |
399 | 402 |
400 double SMILTimeContainer::currentTime() const | |
401 { | |
402 return document().timeline().currentTimeInternal(); | |
403 } | |
404 | |
405 void SMILTimeContainer::serviceOnNextFrame() | 403 void SMILTimeContainer::serviceOnNextFrame() |
406 { | 404 { |
407 if (document().view()) { | 405 if (document().view()) { |
408 document().view()->scheduleAnimation(); | 406 document().view()->scheduleAnimation(); |
409 m_frameSchedulingState = AnimationFrame; | 407 m_frameSchedulingState = AnimationFrame; |
410 } | 408 } |
411 } | 409 } |
412 | 410 |
413 void SMILTimeContainer::serviceAnimations() | 411 void SMILTimeContainer::serviceAnimations() |
414 { | 412 { |
(...skipping 14 matching lines...) Expand all Loading... |
429 // via syncbases), then give that priority. | 427 // via syncbases), then give that priority. |
430 if (hasPendingSynchronization()) | 428 if (hasPendingSynchronization()) |
431 return; | 429 return; |
432 | 430 |
433 if (!isTimelineRunning()) | 431 if (!isTimelineRunning()) |
434 return; | 432 return; |
435 | 433 |
436 if (!earliestFireTime.isFinite()) | 434 if (!earliestFireTime.isFinite()) |
437 return; | 435 return; |
438 | 436 |
439 scheduleAnimationFrame(earliestFireTime); | 437 SMILTime delay = earliestFireTime - elapsed; |
| 438 scheduleAnimationFrame(delay.value()); |
440 } | 439 } |
441 | 440 |
442 SMILTime SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) | 441 SMILTime SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) |
443 { | 442 { |
444 ASSERT(document().isActive()); | 443 ASSERT(document().isActive()); |
445 SMILTime earliestFireTime = SMILTime::unresolved(); | 444 SMILTime earliestFireTime = SMILTime::unresolved(); |
446 | 445 |
447 #if ENABLE(ASSERT) | 446 #if ENABLE(ASSERT) |
448 // This boolean will catch any attempts to schedule/unschedule scheduledAnim
ations during this critical section. | 447 // This boolean will catch any attempts to schedule/unschedule scheduledAnim
ations during this critical section. |
449 // Similarly, any elements removed will unschedule themselves, so this will
catch modification of animationsToApply. | 448 // Similarly, any elements removed will unschedule themselves, so this will
catch modification of animationsToApply. |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 setElapsed(elapsed().value() + initialFrameDelay); | 545 setElapsed(elapsed().value() + initialFrameDelay); |
547 } | 546 } |
548 | 547 |
549 DEFINE_TRACE(SMILTimeContainer) | 548 DEFINE_TRACE(SMILTimeContainer) |
550 { | 549 { |
551 visitor->trace(m_scheduledAnimations); | 550 visitor->trace(m_scheduledAnimations); |
552 visitor->trace(m_ownerSVGElement); | 551 visitor->trace(m_ownerSVGElement); |
553 } | 552 } |
554 | 553 |
555 } // namespace blink | 554 } // namespace blink |
OLD | NEW |