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
authorHiroyuki Ikezoe <hiikezoe@mozilla-japan.org>
Mon, 27 Jun 2016 12:52:53 +0900
changeset 304239 ef21ce58421ed02e0669f25c4822e6f8a2f8b344
parent 304238 8d9e9c2f25e831e7c101d24a3594db4ddbad35e1
child 304240 18cbc19266b4e6f60a35b21d748dbb88c3f03d64
push id79280
push userkwierso@gmail.com
push dateFri, 08 Jul 2016 22:04:28 +0000
treeherdermozilla-inbound@14b16ac38991 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles, mattwoodrow
bugs1278136, 1279403
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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>