Bug 1278136 - Part 2: We should not check whether the animation can run on the compositor or it's paused when determining if we should create a stacking context. r?birtles,mattwoodrow draft
authorHiroyuki Ikezoe <hiikezoe@mozilla-japan.org>
Mon, 27 Jun 2016 12:52:53 +0900
changeset 385379 0ee465a584fa495614b976884f9731d93e0e0554
parent 385378 c0151cced957502b5241614eb0290b182631c6bf
child 385380 b5a27330f00bc6e49506988c233033f73f7f18a0
push id22495
push userhiikezoe@mozilla-japan.org
push dateFri, 08 Jul 2016 08:38:44 +0000
reviewersbirtles, mattwoodrow
bugs1278136, 1279403
milestone50.0a1
Bug 1278136 - Part 2: We should not check whether the animation can run on the compositor or it's paused when determining if we should create a stacking context. r?birtles,mattwoodrow We should create a stacking context for any transform or opacity animations that are either "in effect" (what we currently do) OR "current", i.e. scheduled to run or running. *BUT* for now, we don't create any stacking context in before phase without fill:backwards or fill:both because the property never wins in cascade until the animation gets "in effect". This restriction will be removed in a subsequent patch in this bug after landing bug 1279403. MozReview-Commit-ID: 8RyLJNPtoKI
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/reftests/css-animations/no-stacking-context-animation-ref.html
layout/reftests/css-animations/reftest.list
layout/reftests/css-animations/stacking-context-animation-ref.html
layout/reftests/css-animations/stacking-context-lose-opacity-1.html
layout/reftests/css-animations/stacking-context-lose-transform-none.html
layout/reftests/css-animations/stacking-context-opacity-1-animation.html
layout/reftests/css-animations/stacking-context-opacity-1-in-delay.html
layout/reftests/css-animations/stacking-context-opacity-1-with-fill-backwards.html
layout/reftests/css-animations/stacking-context-opacity-1-with-fill-forwards.html
layout/reftests/css-animations/stacking-context-paused-on-opacity-1.html
layout/reftests/css-animations/stacking-context-paused-on-transform-none.html
layout/reftests/css-animations/stacking-context-transform-animation-ref.html
layout/reftests/css-animations/stacking-context-transform-none-animation-with-backface-visibility.html
layout/reftests/css-animations/stacking-context-transform-none-animation.html
layout/reftests/css-animations/stacking-context-transform-none-in-delay.html
layout/reftests/css-animations/stacking-context-transform-none-with-fill-backwards.html
layout/reftests/css-animations/stacking-context-transform-none-with-fill-forwards.html
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -554,18 +554,18 @@ nsFrame::Init(nsIContent*       aContent
 
     if (HasAnyStateBits(NS_FRAME_IN_POPUP) && TrackingVisibility()) {
       // Assume all frames in popups are visible.
       IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
     }
   }
   const nsStyleDisplay *disp = StyleDisplay();
   if (disp->HasTransform(this) ||
-      nsLayoutUtils::HasCurrentAnimationOfProperty(this,
-                                                   eCSSProperty_transform)) {
+      nsLayoutUtils::HasRelevantAnimationOfProperty(this,
+                                                    eCSSProperty_transform)) {
     // The frame gets reconstructed if we toggle the -moz-transform
     // property, so we can set this bit here and then ignore it.
     mState |= NS_FRAME_MAY_BE_TRANSFORMED;
   }
   if (disp->mPosition == NS_STYLE_POSITION_STICKY &&
       !aPrevInFlow &&
       !(mState & NS_FRAME_IS_NONDISPLAY) &&
       !disp->IsInnerTableStyle()) {
@@ -1145,30 +1145,30 @@ nsIFrame::GetMarginRectRelativeToSelf() 
 
 bool
 nsIFrame::IsTransformed() const
 {
   return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
           (StyleDisplay()->HasTransform(this) ||
            IsSVGTransformed() ||
            (mContent &&
-            EffectCompositor::HasAnimationsForCompositor(
+            nsLayoutUtils::HasRelevantAnimationOfProperty(
               this, eCSSProperty_transform) &&
             IsFrameOfType(eSupportsCSSTransforms) &&
             mContent->GetPrimaryFrame() == this)));
 }
 
 bool
 nsIFrame::HasOpacityInternal(float aThreshold) const
 {
   MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
   return StyleEffects()->mOpacity < aThreshold ||
          (StyleDisplay()->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) ||
          (mContent &&
-           EffectCompositor::HasAnimationsForCompositor(
+           nsLayoutUtils::HasRelevantAnimationOfProperty(
              this, eCSSProperty_opacity) &&
            mContent->GetPrimaryFrame() == this);
 }
 
 bool
 nsIFrame::IsSVGTransformed(gfx::Matrix *aOwnTransforms,
                            gfx::Matrix *aFromParentTransforms) const
 {
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1356,23 +1356,24 @@ public:
   bool RefusedAsyncAnimation() const
   {
     return Properties().Get(RefusedAsyncAnimationProperty());
   }
 
   /**
    * Returns true if this frame is transformed (e.g. has CSS or SVG transforms)
    * or if its parent is an SVG frame that has children-only transforms (e.g.
-   * an SVG viewBox attribute) or if its transform-style is preserve-3d.
+   * an SVG viewBox attribute) or if its transform-style is preserve-3d or
+   * the frame has transform animations.
    */
   bool IsTransformed() const;
 
   /**
-   * Returns true if the frame is translucent for the purposes of creating a
-   * stacking context.
+   * Returns true if the frame is translucent or the frame has opacity
+   * animations for the purposes of creating a stacking context.
    */
   bool HasOpacity() const
   {
     return HasOpacityInternal(1.0f);
   }
   /**
    * Returns true if the frame is translucent for display purposes.
    */
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/no-stacking-context-animation-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>
+Reference of testcases which don't create a stacking context for bug 1278136
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  background: green;
+  position: fixed;
+  top: 50px;
+}
+#test {
+  height: 100px;
+  width: 100px;
+  background: blue;
+}
+</style>
+<span></span>
+<div id="test"></div>
--- a/layout/reftests/css-animations/reftest.list
+++ b/layout/reftests/css-animations/reftest.list
@@ -3,11 +3,27 @@
 fails == print-no-animations.html print-no-animations-ref.html # reftest harness doesn't actually make pres context non-dynamic for reftest-print tests
 fails != print-no-animations.html print-no-animations-notref.html # reftest harness doesn't actually make pres context non-dynamic for reftest-print tests
 == animate-opacity.html animate-opacity-ref.html
 == animate-preserves3d.html animate-preserves3d-ref.html
 == in-visibility-hidden-animation.html in-visibility-hidden-animation-ref.html
 == in-visibility-hidden-animation-pseudo-element.html in-visibility-hidden-animation-pseudo-element-ref.html
 == partially-out-of-view-animation.html partially-out-of-view-animation-ref.html
 == animate-display-table-opacity.html animate-display-table-opacity-ref.html
-== stacking-context-transform-none-animation.html  stacking-context-transform-animation-ref.html
-== stacking-context-transform-none-animation-on-svg.html  stacking-context-transform-animation-ref.html
-== stacking-context-transform-none-animation-with-preserve-3d.html  stacking-context-transform-animation-ref.html
+# We need to run 100% opacity test case when OMTA is disabled to check that the animation creates a stacking context even if the animation is not running on the compositor
+test-pref(layers.offmainthreadcomposition.async-animations,false) == stacking-context-opacity-1-animation.html stacking-context-animation-ref.html
+# We need to run transform:none test case when OMTA is disabled to check that the animation creates a stacking context even if the animation is not running on the compositor
+test-pref(layers.offmainthreadcomposition.async-animations,false) == stacking-context-transform-none-animation.html stacking-context-animation-ref.html
+== stacking-context-lose-opacity-1.html no-stacking-context-animation-ref.html
+== stacking-context-lose-transform-none.html no-stacking-context-animation-ref.html
+== stacking-context-opacity-1-animation.html stacking-context-animation-ref.html
+== stacking-context-opacity-1-with-fill-backwards.html stacking-context-animation-ref.html
+== stacking-context-opacity-1-with-fill-forwards.html stacking-context-animation-ref.html
+== stacking-context-paused-on-opacity-1.html stacking-context-animation-ref.html
+== stacking-context-paused-on-transform-none.html stacking-context-animation-ref.html
+== stacking-context-transform-none-animation.html stacking-context-animation-ref.html
+== stacking-context-transform-none-animation-on-svg.html  stacking-context-animation-ref.html
+== stacking-context-transform-none-animation-with-backface-visibility.html stacking-context-animation-ref.html
+== stacking-context-transform-none-animation-with-preserve-3d.html stacking-context-animation-ref.html
+== stacking-context-transform-none-with-fill-backwards.html stacking-context-animation-ref.html
+== stacking-context-transform-none-with-fill-forwards.html stacking-context-animation-ref.html
+fails == stacking-context-opacity-1-in-delay.html stacking-context-animation-ref.html # bug 1278136 and bug 1279403
+fails == stacking-context-transform-none-in-delay.html stacking-context-animation-ref.html # bug 1278136 and bug 1279403
rename from layout/reftests/css-animations/stacking-context-transform-animation-ref.html
rename to layout/reftests/css-animations/stacking-context-animation-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/stacking-context-lose-opacity-1.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>
+Opacity animation losing in cascade doesn't create stacking context
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  position: fixed;
+  background: green;
+  top: 50px;
+}
+@keyframes Opaque {
+  from, to { opacity: 1 }
+}
+#test {
+  width: 100px; height: 100px;
+  background: blue;
+  animation: Opaque 100s;
+  opacity: 1 !important;
+}
+</style>
+<span></span>
+<div id="test"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/stacking-context-lose-transform-none.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>
+Transform animation losing in cascade doesn't create stacking context
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  position: fixed;
+  background: green;
+  top: 50px;
+}
+@keyframes TransformNone {
+  from, to { transform: none; }
+}
+#test {
+  width: 100px; height: 100px;
+  background: blue;
+  animation: TransformNone 100s infinite;
+  transform: none !important;
+}
+</style>
+<span></span>
+<div id="test"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/stacking-context-opacity-1-animation.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>
+Opacity animation creates a stacking context even if it has only 100% opacity
+in its keyframes
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  position: fixed;
+  background: green;
+  top: 50px;
+}
+@keyframes Opaque {
+  from, to { opacity: 1; }
+}
+#test {
+  width: 100px; height: 100px;
+  background: blue;
+  animation: Opaque 100s infinite;
+}
+</style>
+<span></span>
+<div id="test"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/stacking-context-opacity-1-in-delay.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>
+Opacity animation creates stacking context in delay phase
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  position: fixed;
+  background: green;
+  top: 50px;
+}
+@keyframes Opaque {
+  from, to { opacity: 1 }
+}
+#test {
+  width: 100px; height: 100px;
+  background: blue;
+  animation: Opaque 100s 100s;
+}
+</style>
+<span></span>
+<div id="test"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/stacking-context-opacity-1-with-fill-backwards.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>
+Opacity animation does not destroy stacking context when the animation
+has finished but has fill:backwards
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  position: fixed;
+  background: green;
+  top: 50px;
+}
+@keyframes Opaque {
+  from, to { opacity: 1 }
+}
+#test {
+  width: 100px; height: 100px;
+  background: blue;
+  animation: Opaque 100s 100s backwards;
+}
+</style>
+<span></span>
+<div id="test"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/stacking-context-opacity-1-with-fill-forwards.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>
+Opacity animation does not destroy stacking context when the animation
+has finished but has fill:forwards
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  position: fixed;
+  background: green;
+  top: 50px;
+}
+@keyframes Opaque {
+  from, to { opacity: 1 }
+}
+#test {
+  width: 100px; height: 100px;
+  background: blue;
+  animation: Opaque 0s forwards;
+}
+</style>
+<span></span>
+<div id="test"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/stacking-context-paused-on-opacity-1.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>
+Transform animation creates a stacking context even though it's paused on
+a 100% opacity keyframe
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  position: fixed;
+  background: green;
+  top: 50px;
+}
+@keyframes Opaque {
+  from, to { opacity: 1 }
+}
+#test {
+  width: 100px; height: 100px;
+  background: blue;
+  animation: Opaque 100s paused;
+}
+</style>
+<span></span>
+<div id="test"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/stacking-context-paused-on-transform-none.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>
+Transform animation creates a stacking context even though it's paused on
+a 'transform:none' keyframe
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  position: fixed;
+  background: green;
+  top: 50px;
+}
+@keyframes TransformNone {
+  from, to { transform: none }
+}
+#test {
+  width: 100px; height: 100px;
+  background: blue;
+  animation: TransformNone 100s paused;
+}
+</style>
+<span></span>
+<div id="test"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/stacking-context-transform-none-animation-with-backface-visibility.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>
+Transform animation creates a stacking context even though it has only
+'transform:none' keyframes and with a style which prevents performning
+the animation on the compositor.
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  position: fixed;
+  background: green;
+  top: 50px;
+}
+@keyframes TransformNone {
+  from, to { transform: none }
+}
+#test {
+  width: 100px; height: 100px;
+  background: blue;
+  backface-visibility: hidden;
+  animation: TransformNone 100s infinite;
+}
+</style>
+<span></span>
+<div id="test"></div>
--- a/layout/reftests/css-animations/stacking-context-transform-none-animation.html
+++ b/layout/reftests/css-animations/stacking-context-transform-none-animation.html
@@ -1,10 +1,13 @@
 <!DOCTYPE html>
-<title>Transform animation creates a stacking context even though it has only 'transform:none' keyframes</title>
+<title>
+Transform animation creates a stacking context even though it has only
+'transform:none' keyframes
+</title>
 <style>
 span {
   height: 100px;
   width: 100px;
   position: fixed;
   background: green;
   top: 50px;
 }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/stacking-context-transform-none-in-delay.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>
+Transform animation creates stacking context in delay phase
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  position: fixed;
+  background: green;
+  top: 50px;
+}
+@keyframes TransformNone {
+  from, to { transform: none }
+}
+#test {
+  width: 100px; height: 100px;
+  background: blue;
+  animation: TransformNone 100s 100s;
+}
+</style>
+<span></span>
+<div id="test"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/stacking-context-transform-none-with-fill-backwards.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>
+Transform animation does not destroy stacking context when the animation
+has finished but has fill:backwards
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  position: fixed;
+  background: green;
+  top: 50px;
+}
+@keyframes TransformNone {
+  from, to { transform: none }
+}
+#test {
+  width: 100px; height: 100px;
+  background: blue;
+  animation: TransformNone 100s 100s backwards;
+}
+</style>
+<span></span>
+<div id="test"></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/stacking-context-transform-none-with-fill-forwards.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>
+Transform animation does not destroy stacking context when the animation
+has finished but has fill:forwards
+</title>
+<style>
+span {
+  height: 100px;
+  width: 100px;
+  position: fixed;
+  background: green;
+  top: 50px;
+}
+@keyframes TransformNone {
+  from, to { transform: none }
+}
+#test {
+  width: 100px; height: 100px;
+  background: blue;
+  animation: TransformNone 0s forwards;
+}
+</style>
+<span></span>
+<div id="test"></div>