haikuwebkit/LayoutTests/webanimations/no-scheduling-while-filling...

46 lines
1.2 KiB
HTML
Raw Permalink Normal View History

[Web Animations] Forward-filling animations should not schedule updates while filling https://bugs.webkit.org/show_bug.cgi?id=204697 <rdar://problem/57534005> Reviewed by Dean Jackson. Source/WebCore: Tests: webanimations/no-scheduling-while-filling-accelerated.html webanimations/no-scheduling-while-filling-non-accelerated.html For two different reasons, we would continuously schedule updates for animations in their "after" phase, ie. when they would have "fill: forwards" and be finished. In the case of non-accelerated animations, that was because we would also schedule an immedate update in DocumentTimeline::scheduleNextTick() provided we had relevant animations that weren't accelerated. But since animations in their "after" phase are still considered relevant, which means that they would override the base style with an animated value, this caused the unnecessary scheduled updates. To address this, we run WebAnimation::timeToNextTick() in DocumentTimeline::scheduleNextTick() for all relevant animations and we teach that function to schedule an immediate update only during the "active" phase, and to schedule a timed update only in the "before" phase computing the delay until the animation enters the "active" phase. While performing this work, we found a couple of other issues that weren't apparent until we had this more efficient scheduling in place. First, we would not allow any additional calls to DocumentTimeline::scheduleAnimationResolution() to actually schedule an update while we were in the process of updating animations. While this wasn't a problem before because the mere presence of relevant animations would cause an upadte, we now had to allow any animation changing timing properties as promises would resolve and events would be dispatched during the animation update to cause further animation updates to be scheduled. So we moved the "m_animationResolutionScheduled" flag reset earlier in DocumentTimeline::updateAnimationsAndSendEvents() before we actually run the animation update procedure. Following that change, we also had to make sure that timing changes made through the evaluation of the pending play and pause tasks would _not_ cause animations to be scheduled, which meant that an animation that became non-pending (ie. its first tick occured) would always schedule one immediate animation update. So now we have an extra "silent" flag to WebAnimation::timingDidChange() which is only set to true when called from either WebAnimation::runPendingPlayTask() or WebAnimation::runPendingPauseTask(). Finally, one existing test showed that calling KeyframeEffect::setKeyframes() while running animations didn't cause an animation update to be scheduled since a call to WebAnimation::effectTimingDidChange() was lacking. This is now addressed. As for accelerated animations, the extraneous animation scheduling occured because we would get in a state where we would record an "accelerated action" to stop the accelerated animation but the accelerated animation had already completed and the renderer for the target element was no longer composited. This meant that KeyframeEffect::applyPendingAcceleratedActions() would not perform any work and the pending accelerated action would remain in the DocumentTimeline queue and cause an update to be scheduled to try again, endlessly. To address that, we first check in KeyframeEffect::addPendingAcceleratedAction() if the recorded action differs from the last recorded action, avoiding unnecessary work, and in KeyframeEffect::applyPendingAcceleratedActions(), if our last recorded action was "Stop" and the renderer was not composited, we discard all pending accelerated actions. * animation/DocumentTimeline.cpp: (WebCore::DocumentTimeline::updateAnimationsAndSendEvents): (WebCore::DocumentTimeline::scheduleNextTick): * animation/KeyframeEffect.cpp: (WebCore::KeyframeEffect::setKeyframes): (WebCore::KeyframeEffect::addPendingAcceleratedAction): (WebCore::KeyframeEffect::applyPendingAcceleratedActions): * animation/WebAnimation.cpp: (WebCore::WebAnimation::timingDidChange): (WebCore::WebAnimation::runPendingPlayTask): (WebCore::WebAnimation::runPendingPauseTask): (WebCore::WebAnimation::timeToNextTick const): * animation/WebAnimation.h: LayoutTests: Adding tests checking that we don't schedule animation updates while filling for accelerated and non-accelerated animations alike. * webanimations/no-scheduling-while-filling-accelerated-expected.txt: Added. * webanimations/no-scheduling-while-filling-accelerated.html: Added. * webanimations/no-scheduling-while-filling-non-accelerated-expected.txt: Added. * webanimations/no-scheduling-while-filling-non-accelerated.html: Added. Canonical link: https://commits.webkit.org/217930@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@252957 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-11-30 13:15:48 +00:00
<!DOCTYPE html>
<html>
<head>
<style>
#target {
width: 100px;
height: 100px;
background-color: black;
}
</style>
</head>
<body>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<div id="target"></div>
<script>
function waitNFrames(numberOfFrames, continuation)
{
let elapsedFrames = 0;
(function rAFCallback() {
if (elapsedFrames++ >= numberOfFrames)
continuation();
else
requestAnimationFrame(rAFCallback);
})();
}
async_test(t => {
const keyframes = { marginLeft: ["50px", "100px"] };
const timing = { duration: 50, fill: "forwards" };
document.getElementById("target").animate(keyframes, timing).addEventListener("finish", event => {
const numberOfTimelineInvalidationsWhenFinished = internals.numberOfAnimationTimelineInvalidations();
waitNFrames(2, () => {
assert_equals(internals.numberOfAnimationTimelineInvalidations(), numberOfTimelineInvalidationsWhenFinished);
t.done();
});
});
}, "There should not be any updates made to the timeline after a forward-filling animation completes.");
</script>
</body>
</html>