Bug 1384120 - Replace old pseudo style context with a new style context including animations. r?emilio
When a reframe happens on the parent of a pseudo element which has animations,
we need to grab style for the pseudo element that includes the animations'
style and also *replace* old style context (that does not include animations'
style) with it. Otherwise, we will use the old style context that has *no*
animations style, as a result, we will see a flicker right after the reframe.
Two reftests in this patch fail without this fix. One is for CSS transitions,
the other one is for CSS animations.
MozReview-Commit-ID: 6pCdnQ1DGUY
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1978,18 +1978,22 @@ nsCSSFrameConstructor::CreateGeneratedCo
}
}
}
// We may need to do a synchronous servo traversal in various uncommon cases.
if (servoStyle) {
if (hasServoAnimations) {
// If animations are involved, we avoid the SetExplicitStyle optimization
- // above.
+ // above. We need to grab style with animations from the pseudo element
+ // and replace old one.
mPresShell->StyleSet()->AsServo()->StyleNewSubtree(container);
+ pseudoStyleContext =
+ styleSet->AsServo()->ResolveServoStyle(container,
+ ServoTraversalFlags::Empty);
} else if (createdChildElement) {
// If we created any children elements, Servo needs to traverse them, but
// the root is already set up.
mPresShell->StyleSet()->AsServo()->StyleNewChildren(container);
}
}
AddFrameConstructionItemsInternal(aState, container, aParentFrame, elemName,
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/reframe-and-animation-starts-at-the-same-time-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<style>
+#target::before {
+ content: '';
+ background-color: rgb(255, 255, 255);
+ height: 100px;
+ width: 100px;
+ position: absolute;
+}
+</style>
+<div id="target"></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/reframe-and-animation-starts-at-the-same-time.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<style>
+@keyframes anim {
+ from { background-color: rgb(255, 255, 255); }
+ to { background-color: rgb(255, 255, 255); }
+}
+#target::before {
+ content: 'initial';
+ background-color: rgb(0, 0, 0);
+ height: 100px;
+ width: 100px;
+ position: absolute;
+}
+#target.hover::before{
+ content: '';
+ animation: anim 100s steps(1, start);
+}
+</style>
+<div id="target"></div>
+<script>
+window.addEventListener("load", () => {
+ target.className = 'hover';
+ target.addEventListener('animationstart', () => {
+ document.documentElement.classList.remove('reftest-wait');
+ });
+});
+</script>
+</html>
--- a/layout/reftests/css-animations/reftest.list
+++ b/layout/reftests/css-animations/reftest.list
@@ -49,8 +49,9 @@ fails == background-position-important.h
== mask-size-after-finish-1a.html mask-anim-ref.html
== mask-size-after-finish-1b.html mask-anim-ref.html
== mask-size-in-delay-1a.html mask-anim-ref.html
== mask-size-in-delay-1b.html mask-anim-ref.html
== stop-animation-on-discarded-pseudo-element.html about:blank
== updating-animation-on-pseudo-element.html updating-animation-on-pseudo-element-ref.html
+== reframe-and-animation-starts-at-the-same-time.html reframe-and-animation-starts-at-the-same-time-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-transitions/reframe-and-transition-starts-at-the-same-time-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<style>
+#target::before {
+ content: '';
+ background-color: rgb(255, 255, 255);
+ height: 100px;
+ width: 100px;
+ position: absolute;
+}
+</style>
+<div id="target"></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-transitions/reframe-and-transition-starts-at-the-same-time.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<style>
+#target::before {
+ transition: background-color 100s steps(1, end);
+ content: 'initial';
+ background-color: rgb(255, 255, 255);
+ height: 100px;
+ width: 100px;
+ position: absolute;
+}
+#target.hover::before{
+ background-color: rgb(0, 0, 0);
+ content: '';
+}
+</style>
+<div id="target"></div>
+<script>
+window.addEventListener("load", () => {
+ target.className = 'hover';
+ target.addEventListener('transitionstart', () => {
+ document.documentElement.classList.remove('reftest-wait');
+ });
+});
+</script>
+</html>
--- a/layout/reftests/css-transitions/reftest.list
+++ b/layout/reftests/css-transitions/reftest.list
@@ -2,9 +2,10 @@
== transitions-inline-already-wrapped-2.html transitions-inline-ref.html
== transitions-inline-rewrap-1.html transitions-inline-ref.html
== transitions-inline-rewrap-2.html transitions-inline-ref.html
== stacking-context-opacity-lose-to-animation.html stacking-context-transition-ref.html
== stacking-context-transform-lose-to-animation.html stacking-context-transition-ref.html
== stacking-context-opacity-wins-over-important-style.html stacking-context-transition-ref.html
== stacking-context-transform-wins-over-important-style.html stacking-context-transition-ref.html
== transition-and-animation-with-different-durations.html transition-and-animation-with-different-durations-ref.html
+== reframe-and-transition-starts-at-the-same-time.html reframe-and-transition-starts-at-the-same-time-ref.html
== style-change-during-transition.html style-change-during-transition-ref.html