| 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 19 matching lines...) Expand all Loading... |
| 30 #include "core/animation/DocumentTimeline.h" | 30 #include "core/animation/DocumentTimeline.h" |
| 31 #include "core/dom/ElementTraversal.h" | 31 #include "core/dom/ElementTraversal.h" |
| 32 #include "core/frame/FrameView.h" | 32 #include "core/frame/FrameView.h" |
| 33 #include "core/svg/SVGSVGElement.h" | 33 #include "core/svg/SVGSVGElement.h" |
| 34 #include "core/svg/animation/SVGSMILElement.h" | 34 #include "core/svg/animation/SVGSMILElement.h" |
| 35 | 35 |
| 36 using namespace std; | 36 using namespace std; |
| 37 | 37 |
| 38 namespace WebCore { | 38 namespace WebCore { |
| 39 | 39 |
| 40 static const double initialFrameDelay = 0.025; |
| 41 |
| 40 // Every entry-point that calls updateAnimations() should instantiate a | 42 // Every entry-point that calls updateAnimations() should instantiate a |
| 41 // DiscardScope to prevent deletion of the ownerElement (and hence itself.) | 43 // DiscardScope to prevent deletion of the ownerElement (and hence itself.) |
| 42 class DiscardScope { | 44 class DiscardScope { |
| 43 public: | 45 public: |
| 44 explicit DiscardScope(SVGSVGElement& timeContainerOwner) : m_discardScopeEle
ment(&timeContainerOwner) { } | 46 explicit DiscardScope(SVGSVGElement& timeContainerOwner) : m_discardScopeEle
ment(&timeContainerOwner) { } |
| 45 | 47 |
| 46 private: | 48 private: |
| 47 RefPtr<SVGSVGElement> m_discardScopeElement; | 49 RefPtr<SVGSVGElement> m_discardScopeElement; |
| 48 }; | 50 }; |
| 49 | 51 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 size_t idx = scheduled->find(animation); | 111 size_t idx = scheduled->find(animation); |
| 110 ASSERT(idx != kNotFound); | 112 ASSERT(idx != kNotFound); |
| 111 scheduled->remove(idx); | 113 scheduled->remove(idx); |
| 112 } | 114 } |
| 113 | 115 |
| 114 bool SMILTimeContainer::hasAnimations() const | 116 bool SMILTimeContainer::hasAnimations() const |
| 115 { | 117 { |
| 116 return !m_scheduledAnimations.isEmpty(); | 118 return !m_scheduledAnimations.isEmpty(); |
| 117 } | 119 } |
| 118 | 120 |
| 121 bool SMILTimeContainer::hasPendingSynchronization() const |
| 122 { |
| 123 return m_frameSchedulingState == SynchronizeAnimations && m_wakeupTimer.isAc
tive() && !m_wakeupTimer.nextFireInterval(); |
| 124 } |
| 125 |
| 119 void SMILTimeContainer::notifyIntervalsChanged() | 126 void SMILTimeContainer::notifyIntervalsChanged() |
| 120 { | 127 { |
| 121 if (!isStarted()) | 128 if (!isStarted()) |
| 122 return; | 129 return; |
| 123 // Schedule updateAnimations() to be called asynchronously so multiple inter
vals | 130 // Schedule updateAnimations() to be called asynchronously so multiple inter
vals |
| 124 // can change with updateAnimations() only called once at the end. | 131 // can change with updateAnimations() only called once at the end. |
| 125 if (m_frameSchedulingState == SynchronizeAnimations && m_wakeupTimer.isActiv
e() && !m_wakeupTimer.nextFireInterval()) | 132 if (hasPendingSynchronization()) |
| 126 return; | 133 return; |
| 127 cancelAnimationFrame(); | 134 cancelAnimationFrame(); |
| 128 scheduleWakeUp(0, SynchronizeAnimations); | 135 scheduleWakeUp(0, SynchronizeAnimations); |
| 129 } | 136 } |
| 130 | 137 |
| 131 SMILTime SMILTimeContainer::elapsed() const | 138 SMILTime SMILTimeContainer::elapsed() const |
| 132 { | 139 { |
| 133 if (!m_beginTime) | 140 if (!m_beginTime) |
| 134 return 0; | 141 return 0; |
| 135 | 142 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 156 | 163 |
| 157 // If 'm_presetStartTime' is set, the timeline was modified via setElapsed()
before the document began. | 164 // If 'm_presetStartTime' is set, the timeline was modified via setElapsed()
before the document began. |
| 158 // In this case pass on 'seekToTime=true' to updateAnimations(). | 165 // In this case pass on 'seekToTime=true' to updateAnimations(). |
| 159 m_beginTime = now - m_presetStartTime; | 166 m_beginTime = now - m_presetStartTime; |
| 160 DiscardScope discardScope(m_ownerSVGElement); | 167 DiscardScope discardScope(m_ownerSVGElement); |
| 161 SMILTime earliestFireTime = updateAnimations(SMILTime(m_presetStartTime), m_
presetStartTime ? true : false); | 168 SMILTime earliestFireTime = updateAnimations(SMILTime(m_presetStartTime), m_
presetStartTime ? true : false); |
| 162 m_presetStartTime = 0; | 169 m_presetStartTime = 0; |
| 163 | 170 |
| 164 if (m_pauseTime) { | 171 if (m_pauseTime) { |
| 165 m_pauseTime = now; | 172 m_pauseTime = now; |
| 166 cancelAnimationFrame(); | 173 // If updateAnimations() caused new syncbase instance to be generated, |
| 167 } else { | 174 // we don't want to cancel those. Excepting that, no frame should've |
| 175 // been scheduled at this point. |
| 176 ASSERT(m_frameSchedulingState == Idle || m_frameSchedulingState == Synch
ronizeAnimations); |
| 177 } else if (!hasPendingSynchronization()) { |
| 168 ASSERT(isTimelineRunning()); | 178 ASSERT(isTimelineRunning()); |
| 169 // If the timeline is running, and there's pending animation updates, | 179 // If the timeline is running, and there's pending animation updates, |
| 170 // always perform the first update after the timeline was started using | 180 // always perform the first update after the timeline was started using |
| 171 // the wake-up mechanism. | 181 // the wake-up mechanism. |
| 172 if (earliestFireTime.isFinite()) { | 182 if (earliestFireTime.isFinite()) { |
| 173 scheduleWakeUp(DocumentTimeline::s_minimumDelay, SynchronizeAnimatio
ns); | 183 SMILTime delay = earliestFireTime - elapsed(); |
| 184 scheduleWakeUp(std::max(initialFrameDelay, delay.value()), Synchroni
zeAnimations); |
| 174 } | 185 } |
| 175 } | 186 } |
| 176 } | 187 } |
| 177 | 188 |
| 178 void SMILTimeContainer::pause() | 189 void SMILTimeContainer::pause() |
| 179 { | 190 { |
| 180 ASSERT(!isPaused()); | 191 ASSERT(!isPaused()); |
| 181 m_pauseTime = currentTime(); | 192 m_pauseTime = currentTime(); |
| 182 | 193 |
| 183 if (m_beginTime) { | 194 if (m_beginTime) { |
| 184 m_accumulatedActiveTime += m_pauseTime - lastResumeTime(); | 195 m_accumulatedActiveTime += m_pauseTime - lastResumeTime(); |
| 185 cancelAnimationFrame(); | 196 cancelAnimationFrame(); |
| 186 } | 197 } |
| 187 m_resumeTime = 0; | 198 m_resumeTime = 0; |
| 188 } | 199 } |
| 189 | 200 |
| 190 void SMILTimeContainer::resume() | 201 void SMILTimeContainer::resume() |
| 191 { | 202 { |
| 192 ASSERT(isPaused()); | 203 ASSERT(isPaused()); |
| 193 m_resumeTime = currentTime(); | 204 m_resumeTime = currentTime(); |
| 194 | 205 |
| 195 m_pauseTime = 0; | 206 m_pauseTime = 0; |
| 196 serviceOnNextFrame(); | 207 scheduleWakeUp(0, SynchronizeAnimations); |
| 197 } | 208 } |
| 198 | 209 |
| 199 void SMILTimeContainer::setElapsed(SMILTime time) | 210 void SMILTimeContainer::setElapsed(SMILTime time) |
| 200 { | 211 { |
| 201 // If the documment didn't begin yet, record a new start time, we'll seek to
once its possible. | 212 // If the documment didn't begin yet, record a new start time, we'll seek to
once its possible. |
| 202 if (!m_beginTime) { | 213 if (!m_beginTime) { |
| 203 m_presetStartTime = time.value(); | 214 m_presetStartTime = time.value(); |
| 204 return; | 215 return; |
| 205 } | 216 } |
| 206 | 217 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 235 } | 246 } |
| 236 | 247 |
| 237 bool SMILTimeContainer::isTimelineRunning() const | 248 bool SMILTimeContainer::isTimelineRunning() const |
| 238 { | 249 { |
| 239 return m_beginTime && !isPaused(); | 250 return m_beginTime && !isPaused(); |
| 240 } | 251 } |
| 241 | 252 |
| 242 void SMILTimeContainer::scheduleAnimationFrame(SMILTime fireTime) | 253 void SMILTimeContainer::scheduleAnimationFrame(SMILTime fireTime) |
| 243 { | 254 { |
| 244 ASSERT(isTimelineRunning() && fireTime.isFinite()); | 255 ASSERT(isTimelineRunning() && fireTime.isFinite()); |
| 256 ASSERT(!m_wakeupTimer.isActive()); |
| 245 | 257 |
| 246 SMILTime delay = fireTime - elapsed(); | 258 SMILTime delay = fireTime - elapsed(); |
| 247 if (delay.value() < DocumentTimeline::s_minimumDelay) { | 259 if (delay.value() < DocumentTimeline::s_minimumDelay) { |
| 248 serviceOnNextFrame(); | 260 serviceOnNextFrame(); |
| 249 } else { | 261 } else { |
| 250 scheduleWakeUp(delay.value() - DocumentTimeline::s_minimumDelay, Animati
onFrame); | 262 scheduleWakeUp(delay.value() - DocumentTimeline::s_minimumDelay, FutureA
nimationFrame); |
| 251 } | 263 } |
| 252 } | 264 } |
| 253 | 265 |
| 254 void SMILTimeContainer::cancelAnimationFrame() | 266 void SMILTimeContainer::cancelAnimationFrame() |
| 255 { | 267 { |
| 256 m_frameSchedulingState = Idle; | 268 m_frameSchedulingState = Idle; |
| 257 m_wakeupTimer.stop(); | 269 m_wakeupTimer.stop(); |
| 258 } | 270 } |
| 259 | 271 |
| 260 void SMILTimeContainer::scheduleWakeUp(double delayTime, FrameSchedulingState fr
ameSchedulingState) | 272 void SMILTimeContainer::scheduleWakeUp(double delayTime, FrameSchedulingState fr
ameSchedulingState) |
| 261 { | 273 { |
| 262 ASSERT(frameSchedulingState != Idle); | 274 ASSERT(frameSchedulingState == SynchronizeAnimations || frameSchedulingState
== FutureAnimationFrame); |
| 263 m_wakeupTimer.startOneShot(delayTime, FROM_HERE); | 275 m_wakeupTimer.startOneShot(delayTime, FROM_HERE); |
| 264 m_frameSchedulingState = frameSchedulingState; | 276 m_frameSchedulingState = frameSchedulingState; |
| 265 } | 277 } |
| 266 | 278 |
| 267 void SMILTimeContainer::wakeupTimerFired(Timer<SMILTimeContainer>*) | 279 void SMILTimeContainer::wakeupTimerFired(Timer<SMILTimeContainer>*) |
| 268 { | 280 { |
| 269 if (m_frameSchedulingState == AnimationFrame) { | 281 ASSERT(m_frameSchedulingState == SynchronizeAnimations || m_frameSchedulingS
tate == FutureAnimationFrame); |
| 282 if (m_frameSchedulingState == FutureAnimationFrame) { |
| 270 ASSERT(isTimelineRunning()); | 283 ASSERT(isTimelineRunning()); |
| 271 m_frameSchedulingState = Idle; | 284 m_frameSchedulingState = Idle; |
| 272 serviceOnNextFrame(); | 285 serviceOnNextFrame(); |
| 273 } else { | 286 } else { |
| 274 ASSERT(m_frameSchedulingState == SynchronizeAnimations); | |
| 275 m_frameSchedulingState = Idle; | 287 m_frameSchedulingState = Idle; |
| 276 DiscardScope discardScope(m_ownerSVGElement); | 288 DiscardScope discardScope(m_ownerSVGElement); |
| 277 updateAnimationsAndScheduleFrameIfNeeded(elapsed()); | 289 updateAnimationsAndScheduleFrameIfNeeded(elapsed()); |
| 278 } | 290 } |
| 279 } | 291 } |
| 280 | 292 |
| 281 void SMILTimeContainer::updateDocumentOrderIndexes() | 293 void SMILTimeContainer::updateDocumentOrderIndexes() |
| 282 { | 294 { |
| 283 unsigned timingElementCount = 0; | 295 unsigned timingElementCount = 0; |
| 284 for (SVGSMILElement* element = Traversal<SVGSMILElement>::firstWithin(m_owne
rSVGElement); element; element = Traversal<SVGSMILElement>::next(*element, &m_ow
nerSVGElement)) | 296 for (SVGSMILElement* element = Traversal<SVGSMILElement>::firstWithin(m_owne
rSVGElement); element; element = Traversal<SVGSMILElement>::next(*element, &m_ow
nerSVGElement)) |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 m_frameSchedulingState = Idle; | 347 m_frameSchedulingState = Idle; |
| 336 animationClock().updateTime(monotonicAnimationStartTime); | 348 animationClock().updateTime(monotonicAnimationStartTime); |
| 337 DiscardScope discardScope(m_ownerSVGElement); | 349 DiscardScope discardScope(m_ownerSVGElement); |
| 338 updateAnimationsAndScheduleFrameIfNeeded(elapsed()); | 350 updateAnimationsAndScheduleFrameIfNeeded(elapsed()); |
| 339 animationClock().unfreeze(); | 351 animationClock().unfreeze(); |
| 340 } | 352 } |
| 341 | 353 |
| 342 void SMILTimeContainer::updateAnimationsAndScheduleFrameIfNeeded(SMILTime elapse
d, bool seekToTime) | 354 void SMILTimeContainer::updateAnimationsAndScheduleFrameIfNeeded(SMILTime elapse
d, bool seekToTime) |
| 343 { | 355 { |
| 344 SMILTime earliestFireTime = updateAnimations(elapsed, seekToTime); | 356 SMILTime earliestFireTime = updateAnimations(elapsed, seekToTime); |
| 357 // If updateAnimations() ended up triggering a synchronization (most likely |
| 358 // via syncbases), then give that priority. |
| 359 if (hasPendingSynchronization()) |
| 360 return; |
| 361 |
| 345 if (!isTimelineRunning()) | 362 if (!isTimelineRunning()) |
| 346 return; | 363 return; |
| 347 | 364 |
| 348 if (!earliestFireTime.isFinite()) | 365 if (!earliestFireTime.isFinite()) |
| 349 return; | 366 return; |
| 350 | 367 |
| 351 scheduleAnimationFrame(earliestFireTime); | 368 scheduleAnimationFrame(earliestFireTime); |
| 352 } | 369 } |
| 353 | 370 |
| 354 SMILTime SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) | 371 SMILTime SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 if (animDiscard->inDocument()) { | 451 if (animDiscard->inDocument()) { |
| 435 animDiscard->remove(IGNORE_EXCEPTION); | 452 animDiscard->remove(IGNORE_EXCEPTION); |
| 436 ASSERT(!animDiscard->inDocument()); | 453 ASSERT(!animDiscard->inDocument()); |
| 437 } | 454 } |
| 438 } | 455 } |
| 439 } | 456 } |
| 440 return earliestFireTime; | 457 return earliestFireTime; |
| 441 } | 458 } |
| 442 | 459 |
| 443 } | 460 } |
| OLD | NEW |