|
Lines 33-39
a/Source/WebCore/animation/DocumentTimeline.cpp_sec1
|
| 33 |
#include "DOMWindow.h" |
33 |
#include "DOMWindow.h" |
| 34 |
#include "DeclarativeAnimation.h" |
34 |
#include "DeclarativeAnimation.h" |
| 35 |
#include "Document.h" |
35 |
#include "Document.h" |
| 36 |
#include "DocumentAnimationScheduler.h" |
|
|
| 37 |
#include "GraphicsLayer.h" |
36 |
#include "GraphicsLayer.h" |
| 38 |
#include "KeyframeEffect.h" |
37 |
#include "KeyframeEffect.h" |
| 39 |
#include "Microtasks.h" |
38 |
#include "Microtasks.h" |
|
Lines 61-70
Ref<DocumentTimeline> DocumentTimeline::create(Document& document, DocumentTimel
a/Source/WebCore/animation/DocumentTimeline.cpp_sec2
|
| 61 |
|
60 |
|
| 62 |
DocumentTimeline::DocumentTimeline(Document& document, Seconds originTime) |
61 |
DocumentTimeline::DocumentTimeline(Document& document, Seconds originTime) |
| 63 |
: AnimationTimeline() |
62 |
: AnimationTimeline() |
| 64 |
#if !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) |
63 |
, m_tickScheduleTimer(*this, &DocumentTimeline::scheduleAnimationResolution) |
| 65 |
, m_animationResolutionTimer(*this, &DocumentTimeline::animationResolutionTimerFired) |
|
|
| 66 |
#endif |
| 67 |
, m_tickScheduleTimer(*this, &DocumentTimeline::scheduleAnimationResolutionIfNeeded) |
| 68 |
, m_document(&document) |
64 |
, m_document(&document) |
| 69 |
, m_originTime(originTime) |
65 |
, m_originTime(originTime) |
| 70 |
{ |
66 |
{ |
|
Lines 194-200
Vector<RefPtr<WebAnimation>> DocumentTimeline::getAnimations() const
a/Source/WebCore/animation/DocumentTimeline.cpp_sec3
|
| 194 |
|
190 |
|
| 195 |
void DocumentTimeline::updateThrottlingState() |
191 |
void DocumentTimeline::updateThrottlingState() |
| 196 |
{ |
192 |
{ |
| 197 |
scheduleAnimationResolutionIfNeeded(); |
193 |
scheduleAnimationResolution(); |
| 198 |
} |
194 |
} |
| 199 |
|
195 |
|
| 200 |
Seconds DocumentTimeline::animationInterval() const |
196 |
Seconds DocumentTimeline::animationInterval() const |
|
Lines 210-222
void DocumentTimeline::suspendAnimations()
a/Source/WebCore/animation/DocumentTimeline.cpp_sec4
|
| 210 |
return; |
206 |
return; |
| 211 |
|
207 |
|
| 212 |
if (!m_cachedCurrentTime) |
208 |
if (!m_cachedCurrentTime) |
| 213 |
m_cachedCurrentTime = liveCurrentTime(); |
209 |
m_cachedCurrentTime = Seconds(liveCurrentTime()); |
| 214 |
|
210 |
|
| 215 |
for (const auto& animation : m_animations) |
211 |
for (const auto& animation : m_animations) |
| 216 |
animation->setSuspended(true); |
212 |
animation->setSuspended(true); |
| 217 |
|
213 |
|
| 218 |
m_isSuspended = true; |
214 |
m_isSuspended = true; |
| 219 |
|
215 |
|
|
|
216 |
fprintf(stderr, "In DocumentTimeline::updateAnimationsAndSendEvents(), Animation was suspended: this = %p, liveCurrentTime = %f\n", this, liveCurrentTime()); |
| 217 |
|
| 220 |
applyPendingAcceleratedAnimations(); |
218 |
applyPendingAcceleratedAnimations(); |
| 221 |
|
219 |
|
| 222 |
unscheduleAnimationResolution(); |
220 |
unscheduleAnimationResolution(); |
|
Lines 230-240
void DocumentTimeline::resumeAnimations()
a/Source/WebCore/animation/DocumentTimeline.cpp_sec5
|
| 230 |
m_cachedCurrentTime = WTF::nullopt; |
228 |
m_cachedCurrentTime = WTF::nullopt; |
| 231 |
|
229 |
|
| 232 |
m_isSuspended = false; |
230 |
m_isSuspended = false; |
|
|
231 |
|
| 232 |
fprintf(stderr, "In DocumentTimeline::updateAnimationsAndSendEvents(), Animation was resumed: this = %p, liveCurrentTime = %f\n", this, liveCurrentTime()); |
| 233 |
|
233 |
|
| 234 |
for (const auto& animation : m_animations) |
234 |
for (const auto& animation : m_animations) |
| 235 |
animation->setSuspended(false); |
235 |
animation->setSuspended(false); |
| 236 |
|
236 |
|
| 237 |
scheduleAnimationResolutionIfNeeded(); |
237 |
scheduleAnimationResolution(); |
| 238 |
} |
238 |
} |
| 239 |
|
239 |
|
| 240 |
bool DocumentTimeline::animationsAreSuspended() |
240 |
bool DocumentTimeline::animationsAreSuspended() |
|
Lines 252-264
unsigned DocumentTimeline::numberOfActiveAnimationsForTesting() const
a/Source/WebCore/animation/DocumentTimeline.cpp_sec6
|
| 252 |
return count; |
252 |
return count; |
| 253 |
} |
253 |
} |
| 254 |
|
254 |
|
| 255 |
Seconds DocumentTimeline::liveCurrentTime() const |
255 |
DOMHighResTimeStamp DocumentTimeline::liveCurrentTime() const |
| 256 |
{ |
256 |
{ |
| 257 |
#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) |
257 |
return m_document->domWindow()->nowTimestamp(); |
| 258 |
return m_document->animationScheduler().lastTimestamp(); |
|
|
| 259 |
#else |
| 260 |
return Seconds(m_document->domWindow()->nowTimestamp()); |
| 261 |
#endif |
| 262 |
} |
258 |
} |
| 263 |
|
259 |
|
| 264 |
Optional<Seconds> DocumentTimeline::currentTime() |
260 |
Optional<Seconds> DocumentTimeline::currentTime() |
|
Lines 274-309
Optional<Seconds> DocumentTimeline::currentTime()
a/Source/WebCore/animation/DocumentTimeline.cpp_sec7
|
| 274 |
} |
270 |
} |
| 275 |
} |
271 |
} |
| 276 |
|
272 |
|
| 277 |
auto currentTime = liveCurrentTime(); |
273 |
if (!m_cachedCurrentTime) |
| 278 |
|
274 |
cacheCurrentTime(liveCurrentTime()); |
| 279 |
#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) |
275 |
|
| 280 |
// If we're in the middle of firing a frame, either due to a requestAnimationFrame callback |
|
|
| 281 |
// or scheduling an animation update, we want to ensure we use the same time we're using as |
| 282 |
// the timestamp for requestAnimationFrame() callbacks. |
| 283 |
if (m_document->animationScheduler().isFiring()) |
| 284 |
cacheCurrentTime(currentTime); |
| 285 |
#endif |
| 286 |
|
| 287 |
if (!m_cachedCurrentTime) { |
| 288 |
#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) |
| 289 |
// If we're not in the middle of firing a frame, let's make our best guess at what the currentTime should |
| 290 |
// be since the last time a frame fired by increment of our update interval. This way code using something |
| 291 |
// like setTimeout() or handling events will get a time that's only updating at around 60fps, or less if |
| 292 |
// we're throttled. |
| 293 |
auto lastAnimationSchedulerTimestamp = currentTime; |
| 294 |
auto delta = Seconds(m_document->domWindow()->nowTimestamp()) - lastAnimationSchedulerTimestamp; |
| 295 |
int frames = std::floor(delta.seconds() / animationInterval().seconds()); |
| 296 |
cacheCurrentTime(lastAnimationSchedulerTimestamp + Seconds(frames * animationInterval().seconds())); |
| 297 |
#else |
| 298 |
cacheCurrentTime(currentTime); |
| 299 |
#endif |
| 300 |
} |
| 301 |
return m_cachedCurrentTime.value() - m_originTime; |
276 |
return m_cachedCurrentTime.value() - m_originTime; |
| 302 |
} |
277 |
} |
| 303 |
|
278 |
|
| 304 |
void DocumentTimeline::cacheCurrentTime(Seconds newCurrentTime) |
279 |
void DocumentTimeline::cacheCurrentTime(DOMHighResTimeStamp newCurrentTime) |
| 305 |
{ |
280 |
{ |
| 306 |
m_cachedCurrentTime = newCurrentTime; |
281 |
m_cachedCurrentTime = Seconds(newCurrentTime); |
| 307 |
// We want to be sure to keep this time cached until we've both finished running JS and finished updating |
282 |
// We want to be sure to keep this time cached until we've both finished running JS and finished updating |
| 308 |
// animations, so we schedule the invalidation task and register a whenIdle callback on the VM, which will |
283 |
// animations, so we schedule the invalidation task and register a whenIdle callback on the VM, which will |
| 309 |
// fire syncronously if no JS is running. |
284 |
// fire syncronously if no JS is running. |
|
Lines 326-341
void DocumentTimeline::maybeClearCachedCurrentTime()
a/Source/WebCore/animation/DocumentTimeline.cpp_sec8
|
| 326 |
m_cachedCurrentTime = WTF::nullopt; |
301 |
m_cachedCurrentTime = WTF::nullopt; |
| 327 |
} |
302 |
} |
| 328 |
|
303 |
|
| 329 |
void DocumentTimeline::scheduleAnimationResolutionIfNeeded() |
|
|
| 330 |
{ |
| 331 |
if (!m_isUpdatingAnimations && !m_isSuspended && !m_animations.isEmpty()) |
| 332 |
scheduleAnimationResolution(); |
| 333 |
} |
| 334 |
|
| 335 |
void DocumentTimeline::animationTimingDidChange(WebAnimation& animation) |
304 |
void DocumentTimeline::animationTimingDidChange(WebAnimation& animation) |
| 336 |
{ |
305 |
{ |
| 337 |
AnimationTimeline::animationTimingDidChange(animation); |
306 |
AnimationTimeline::animationTimingDidChange(animation); |
| 338 |
scheduleAnimationResolutionIfNeeded(); |
307 |
scheduleAnimationResolution(); |
| 339 |
} |
308 |
} |
| 340 |
|
309 |
|
| 341 |
void DocumentTimeline::removeAnimation(WebAnimation& animation) |
310 |
void DocumentTimeline::removeAnimation(WebAnimation& animation) |
|
Lines 348-391
void DocumentTimeline::removeAnimation(WebAnimation& animation)
a/Source/WebCore/animation/DocumentTimeline.cpp_sec9
|
| 348 |
|
317 |
|
| 349 |
void DocumentTimeline::scheduleAnimationResolution() |
318 |
void DocumentTimeline::scheduleAnimationResolution() |
| 350 |
{ |
319 |
{ |
| 351 |
#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) |
320 |
if (m_isSuspended || m_animations.isEmpty() || m_animationResolutionScheduled) |
| 352 |
m_document->animationScheduler().scheduleWebAnimationsResolution(); |
321 |
return; |
| 353 |
#else |
322 |
|
| 354 |
// FIXME: We need to use the same logic as ScriptedAnimationController here, |
323 |
if (!m_document || !m_document->page()) |
| 355 |
// which will be addressed by the refactor tracked by webkit.org/b/179293. |
324 |
return; |
| 356 |
m_animationResolutionTimer.startOneShot(animationInterval()); |
325 |
|
| 357 |
#endif |
326 |
m_document->page()->renderingUpdateScheduler().scheduleRenderingUpdate(); |
|
|
327 |
m_animationResolutionScheduled = true; |
| 328 |
|
| 329 |
fprintf(stderr, "In DocumentTimeline::updateAnimationsAndSendEvents(), RenderingUpdate was scheduled : this = %p, liveCurrentTime = %f\n", this, liveCurrentTime()); |
| 358 |
} |
330 |
} |
| 359 |
|
331 |
|
| 360 |
void DocumentTimeline::unscheduleAnimationResolution() |
332 |
void DocumentTimeline::unscheduleAnimationResolution() |
| 361 |
{ |
333 |
{ |
| 362 |
m_tickScheduleTimer.stop(); |
334 |
m_tickScheduleTimer.stop(); |
| 363 |
#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) |
335 |
m_animationResolutionScheduled = false; |
| 364 |
m_document->animationScheduler().unscheduleWebAnimationsResolution(); |
336 |
} |
| 365 |
#else |
337 |
|
| 366 |
// FIXME: We need to use the same logic as ScriptedAnimationController here, |
338 |
void DocumentTimeline::updateAnimationsAndSendEvents(DOMHighResTimeStamp timestamp) |
| 367 |
// which will be addressed by the refactor tracked by webkit.org/b/179293. |
339 |
{ |
| 368 |
m_animationResolutionTimer.stop(); |
340 |
// We need to freeze the current time even if no animation is running. |
| 369 |
#endif |
341 |
// document.timeline.currentTime may be called from a rAF callback and |
| 370 |
} |
342 |
// it has to match the rAF timestamp. |
| 371 |
|
343 |
if (!m_isSuspended) |
| 372 |
#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) |
344 |
cacheCurrentTime(timestamp); |
| 373 |
void DocumentTimeline::documentAnimationSchedulerDidFire() |
345 |
|
| 374 |
#else |
346 |
if (m_isSuspended || m_animations.isEmpty() || !m_animationResolutionScheduled) |
| 375 |
void DocumentTimeline::animationResolutionTimerFired() |
347 |
return; |
| 376 |
#endif |
348 |
|
| 377 |
{ |
349 |
internalUpdateAnimationsAndSendEvents(); |
| 378 |
updateAnimationsAndSendEvents(); |
|
|
| 379 |
applyPendingAcceleratedAnimations(); |
350 |
applyPendingAcceleratedAnimations(); |
|
|
351 |
|
| 352 |
m_animationResolutionScheduled = false; |
| 353 |
|
| 354 |
fprintf(stderr, "In DocumentTimeline::updateAnimationsAndSendEvents(), Events were sent : this = %p, liveCurrentTime = %f\n", this, liveCurrentTime()); |
| 355 |
|
| 380 |
scheduleNextTick(); |
356 |
scheduleNextTick(); |
| 381 |
} |
357 |
} |
| 382 |
|
358 |
|
| 383 |
void DocumentTimeline::updateAnimationsAndSendEvents() |
359 |
void DocumentTimeline::internalUpdateAnimationsAndSendEvents() |
| 384 |
{ |
360 |
{ |
| 385 |
m_numberOfAnimationTimelineInvalidationsForTesting++; |
361 |
m_numberOfAnimationTimelineInvalidationsForTesting++; |
| 386 |
|
362 |
|
| 387 |
m_isUpdatingAnimations = true; |
|
|
| 388 |
|
| 389 |
// https://drafts.csswg.org/web-animations/#update-animations-and-send-events |
363 |
// https://drafts.csswg.org/web-animations/#update-animations-and-send-events |
| 390 |
|
364 |
|
| 391 |
// 1. Update the current time of all timelines associated with doc passing now as the timestamp. |
365 |
// 1. Update the current time of all timelines associated with doc passing now as the timestamp. |
|
Lines 448-455
void DocumentTimeline::updateAnimationsAndSendEvents()
a/Source/WebCore/animation/DocumentTimeline.cpp_sec10
|
| 448 |
// removed from the list of completed transitions otherwise. |
422 |
// removed from the list of completed transitions otherwise. |
| 449 |
for (auto& completedTransition : completedTransitions) |
423 |
for (auto& completedTransition : completedTransitions) |
| 450 |
transitionDidComplete(completedTransition); |
424 |
transitionDidComplete(completedTransition); |
| 451 |
|
|
|
| 452 |
m_isUpdatingAnimations = false; |
| 453 |
} |
425 |
} |
| 454 |
|
426 |
|
| 455 |
void DocumentTimeline::transitionDidComplete(RefPtr<CSSTransition> transition) |
427 |
void DocumentTimeline::transitionDidComplete(RefPtr<CSSTransition> transition) |
|
Lines 473-479
void DocumentTimeline::scheduleNextTick()
a/Source/WebCore/animation/DocumentTimeline.cpp_sec11
|
| 473 |
|
445 |
|
| 474 |
for (const auto& animation : m_animations) { |
446 |
for (const auto& animation : m_animations) { |
| 475 |
if (!animation->isRunningAccelerated()) { |
447 |
if (!animation->isRunningAccelerated()) { |
| 476 |
scheduleAnimationResolutionIfNeeded(); |
448 |
scheduleAnimationResolution(); |
| 477 |
return; |
449 |
return; |
| 478 |
} |
450 |
} |
| 479 |
} |
451 |
} |
|
Lines 483-489
void DocumentTimeline::scheduleNextTick()
a/Source/WebCore/animation/DocumentTimeline.cpp_sec12
|
| 483 |
for (const auto& animation : m_animations) { |
455 |
for (const auto& animation : m_animations) { |
| 484 |
auto animationTimeToNextRequiredTick = animation->timeToNextTick(); |
456 |
auto animationTimeToNextRequiredTick = animation->timeToNextTick(); |
| 485 |
if (animationTimeToNextRequiredTick < animationInterval()) { |
457 |
if (animationTimeToNextRequiredTick < animationInterval()) { |
| 486 |
scheduleAnimationResolutionIfNeeded(); |
458 |
scheduleAnimationResolution(); |
| 487 |
return; |
459 |
return; |
| 488 |
} |
460 |
} |
| 489 |
scheduleDelay = std::min(scheduleDelay, animationTimeToNextRequiredTick); |
461 |
scheduleDelay = std::min(scheduleDelay, animationTimeToNextRequiredTick); |
|
Lines 593-610
void DocumentTimeline::animationAcceleratedRunningStateDidChange(WebAnimation& a
a/Source/WebCore/animation/DocumentTimeline.cpp_sec13
|
| 593 |
void DocumentTimeline::updateListOfElementsWithRunningAcceleratedAnimationsForElement(Element& element) |
565 |
void DocumentTimeline::updateListOfElementsWithRunningAcceleratedAnimationsForElement(Element& element) |
| 594 |
{ |
566 |
{ |
| 595 |
auto animations = animationsForElement(element); |
567 |
auto animations = animationsForElement(element); |
| 596 |
bool runningAnimationsForElementAreAllAccelerated = !animations.isEmpty(); |
568 |
|
|
|
569 |
if (animations.isEmpty()) { |
| 570 |
m_elementsWithRunningAcceleratedAnimations.remove(&element); |
| 571 |
return; |
| 572 |
} |
| 573 |
|
| 597 |
for (const auto& animation : animations) { |
574 |
for (const auto& animation : animations) { |
| 598 |
if (!animation->isRunningAccelerated()) { |
575 |
if (!animation->isRunningAccelerated()) { |
| 599 |
runningAnimationsForElementAreAllAccelerated = false; |
576 |
m_elementsWithRunningAcceleratedAnimations.remove(&element); |
| 600 |
break; |
577 |
return; |
| 601 |
} |
578 |
} |
| 602 |
} |
579 |
} |
| 603 |
|
580 |
|
| 604 |
if (runningAnimationsForElementAreAllAccelerated) |
581 |
m_elementsWithRunningAcceleratedAnimations.add(&element); |
| 605 |
m_elementsWithRunningAcceleratedAnimations.add(&element); |
|
|
| 606 |
else |
| 607 |
m_elementsWithRunningAcceleratedAnimations.remove(&element); |
| 608 |
} |
582 |
} |
| 609 |
|
583 |
|
| 610 |
void DocumentTimeline::applyPendingAcceleratedAnimations() |
584 |
void DocumentTimeline::applyPendingAcceleratedAnimations() |
|
Lines 625-654
void DocumentTimeline::applyPendingAcceleratedAnimations()
a/Source/WebCore/animation/DocumentTimeline.cpp_sec14
|
| 625 |
|
599 |
|
| 626 |
bool DocumentTimeline::resolveAnimationsForElement(Element& element, RenderStyle& targetStyle) |
600 |
bool DocumentTimeline::resolveAnimationsForElement(Element& element, RenderStyle& targetStyle) |
| 627 |
{ |
601 |
{ |
| 628 |
bool hasNonAcceleratedAnimations = false; |
602 |
bool hasNonAcceleratedAnimationProperty = false; |
| 629 |
bool hasPendingAcceleratedAnimations = true; |
603 |
|
| 630 |
for (const auto& animation : animationsForElement(element)) { |
604 |
for (const auto& animation : animationsForElement(element)) { |
| 631 |
animation->resolve(targetStyle); |
605 |
animation->resolve(targetStyle); |
| 632 |
if (!hasNonAcceleratedAnimations) { |
606 |
|
| 633 |
if (auto* effect = animation->effect()) { |
607 |
if (hasNonAcceleratedAnimationProperty) |
| 634 |
if (is<KeyframeEffect>(effect)) { |
608 |
continue; |
| 635 |
auto* keyframeEffect = downcast<KeyframeEffect>(effect); |
609 |
|
| 636 |
for (auto cssPropertyId : keyframeEffect->animatedProperties()) { |
610 |
auto* effect = animation->effect(); |
| 637 |
if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(cssPropertyId)) { |
611 |
if (!effect || !is<KeyframeEffect>(effect)) |
| 638 |
hasNonAcceleratedAnimations = true; |
612 |
continue; |
| 639 |
continue; |
613 |
|
| 640 |
} |
614 |
auto* keyframeEffect = downcast<KeyframeEffect>(effect); |
| 641 |
if (!hasPendingAcceleratedAnimations) |
615 |
for (auto cssPropertyId : keyframeEffect->animatedProperties()) { |
| 642 |
hasPendingAcceleratedAnimations = keyframeEffect->hasPendingAcceleratedAction(); |
616 |
if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(cssPropertyId)) { |
| 643 |
} |
617 |
hasNonAcceleratedAnimationProperty = true; |
| 644 |
} |
618 |
break; |
| 645 |
} |
619 |
} |
| 646 |
} |
620 |
} |
| 647 |
} |
621 |
} |
| 648 |
|
622 |
|
| 649 |
// If there are no non-accelerated animations and we've encountered at least one pending |
623 |
return !hasNonAcceleratedAnimationProperty; |
| 650 |
// accelerated animation, we should recomposite this element's layer for animation purposes. |
|
|
| 651 |
return !hasNonAcceleratedAnimations && hasPendingAcceleratedAnimations; |
| 652 |
} |
624 |
} |
| 653 |
|
625 |
|
| 654 |
bool DocumentTimeline::runningAnimationsForElementAreAllAccelerated(Element& element) const |
626 |
bool DocumentTimeline::runningAnimationsForElementAreAllAccelerated(Element& element) const |