summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Stockwell <dstockwell@chromium.org>2016-01-04 10:28:25 +1100
committerDouglas Stockwell <dstockwell@chromium.org>2016-01-03 23:30:13 +0000
commit19e6a44082f36d5ac3a76bc61734b859abee4dee (patch)
treeb01ca8b3002525e4fe235c0a4e8cc943502519e5
parent76792445d764ed2d34fd0a6af99e489628ff4885 (diff)
downloadchromium_src-19e6a44082f36d5ac3a76bc61734b859abee4dee.zip
chromium_src-19e6a44082f36d5ac3a76bc61734b859abee4dee.tar.gz
chromium_src-19e6a44082f36d5ac3a76bc61734b859abee4dee.tar.bz2
Web Animations: Fix scheduling loop in race between visibility and start time notification
After r202085[1] the change in an underlying value could delay the restart of a compositor animation until the previous start time was known. If this raced with the page visibility state becoming hidden we could get into a tight scheduling loop. This case handles this case explicitly and adds additional guarding asserts. BUG=560459 Review URL: https://codereview.chromium.org/1500383002 Cr-Commit-Position: refs/heads/master@{#363420} (cherry picked from commit 047977b0a464789957a6680972647c8e07cb2065) Review URL: https://codereview.chromium.org/1554023002 . Cr-Commit-Position: refs/branch-heads/2526@{#540} Cr-Branched-From: cb947c0153db0ec02a8abbcb3ca086d88bf6006f-refs/heads/master@{#352221}
-rw-r--r--third_party/WebKit/LayoutTests/animations/restart-not-visible.html31
-rw-r--r--third_party/WebKit/Source/core/animation/Animation.cpp2
-rw-r--r--third_party/WebKit/Source/core/animation/CompositorPendingAnimations.cpp8
3 files changed, 36 insertions, 5 deletions
diff --git a/third_party/WebKit/LayoutTests/animations/restart-not-visible.html b/third_party/WebKit/LayoutTests/animations/restart-not-visible.html
new file mode 100644
index 0000000..f8c094b7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/restart-not-visible.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<style>
+.run {
+ animation: foo 1s infinite alternate;
+}
+
+@keyframes foo {
+ 100% {
+ transform: translateX(100px)
+ }
+}
+</style>
+<div id="target"></div>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+var test = async_test('Race between visibility and set compositor pending should not crash');
+requestAnimationFrame(t => {
+ requestAnimationFrame(t => {
+ target.classList.add('run');
+ setTimeout(() => {
+ testRunner.setPageVisibility("hidden");
+ target.style.transform = 'translateX(50px)';
+ target.offsetTop;
+ setTimeout(() => {
+ test.done();
+ }, 0);
+ }, 0);
+ });
+});
+</script>
diff --git a/third_party/WebKit/Source/core/animation/Animation.cpp b/third_party/WebKit/Source/core/animation/Animation.cpp
index dc4aeca..60008e2 100644
--- a/third_party/WebKit/Source/core/animation/Animation.cpp
+++ b/third_party/WebKit/Source/core/animation/Animation.cpp
@@ -251,7 +251,7 @@ bool Animation::preCommit(int compositorGroup, bool startOnCompositor)
bool shouldCancel = (!playing() && m_compositorState) || changed;
bool shouldStart = playing() && (!m_compositorState || changed);
- if (shouldCancel && shouldStart && m_compositorState && m_compositorState->pendingAction == Start) {
+ if (startOnCompositor && shouldCancel && shouldStart && m_compositorState && m_compositorState->pendingAction == Start) {
// Restarting but still waiting for a start time.
return false;
}
diff --git a/third_party/WebKit/Source/core/animation/CompositorPendingAnimations.cpp b/third_party/WebKit/Source/core/animation/CompositorPendingAnimations.cpp
index 28ee306..2ad466c8 100644
--- a/third_party/WebKit/Source/core/animation/CompositorPendingAnimations.cpp
+++ b/third_party/WebKit/Source/core/animation/CompositorPendingAnimations.cpp
@@ -77,6 +77,7 @@ bool CompositorPendingAnimations::update(bool startOnCompositor)
// Animations with a start time do not participate in compositor start-time grouping.
if (animation->preCommit(animation->hasStartTime() ? 1 : compositorGroup, startOnCompositor)) {
if (animation->hasActiveAnimationsOnCompositor() && !hadCompositorAnimation) {
+
startedSynchronizedOnCompositor = true;
}
@@ -110,11 +111,10 @@ bool CompositorPendingAnimations::update(bool startOnCompositor)
animation->postCommit(animation->timeline()->currentTimeInternal());
ASSERT(m_pending.isEmpty());
+ ASSERT(startOnCompositor || deferred.isEmpty());
for (auto& animation : deferred)
animation->setCompositorPending();
-#if ENABLE(ASSERT)
- size_t pendingSize = m_pending.size();
-#endif
+ ASSERT(m_pending.size() == deferred.size());
if (startedSynchronizedOnCompositor)
return true;
@@ -131,7 +131,7 @@ bool CompositorPendingAnimations::update(bool startOnCompositor)
// If not, go ahead and start any animations that were waiting.
notifyCompositorAnimationStarted(monotonicallyIncreasingTime());
- ASSERT(pendingSize == m_pending.size());
+ ASSERT(m_pending.size() == deferred.size());
return false;
}