| 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 |