Bug 1464568 - Set the shadow base transform value for the case where opacity animations' calculation was skipped. r=kats
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Tue, 05 Jun 2018 12:50:39 +0900
changeset 421331 9ea461e4570bcba029a34d77e862e5e9688be9a3
parent 421330 b8c1542514b56cc87728b1358153033cce1fbd7d
child 421332 9acec00d049242f4f9b17de389782c2ae29cbf90
push id34091
push userbtara@mozilla.com
push dateTue, 05 Jun 2018 13:52:34 +0000
treeherdermozilla-central@752465b44c79 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1464568
milestone62.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 1464568 - Set the shadow base transform value for the case where opacity animations' calculation was skipped. r=kats And make DOMWindowUtils.getOMTCTransform work for opacity animations' layer. MozReview-Commit-ID: 7P99WjYqPr0
dom/base/nsDOMWindowUtils.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
gfx/layers/apz/test/mochitest/helper_bug1464568_opacity.html
gfx/layers/apz/test/mochitest/mochitest.ini
gfx/layers/apz/test/mochitest/test_bug1464568.html
gfx/layers/composite/AsyncCompositionManager.cpp
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3764,19 +3764,23 @@ nsDOMWindowUtils::GetOMTCTransform(Eleme
   }
 
   nsIFrame* frame = frameOrError.unwrap();
   aResult.Truncate();
   if (!frame) {
     return NS_OK;
   }
 
-  Layer* layer =
-    FrameLayerBuilder::GetDedicatedLayer(frame,
-                                         DisplayItemType::TYPE_TRANSFORM);
+  DisplayItemType itemType = DisplayItemType::TYPE_TRANSFORM;
+  if (nsLayoutUtils::HasEffectiveAnimation(frame, eCSSProperty_opacity) &&
+      !frame->IsTransformed()) {
+    itemType = DisplayItemType::TYPE_OPACITY;
+  }
+
+  Layer* layer = FrameLayerBuilder::GetDedicatedLayer(frame, itemType);
   if (!layer) {
     return NS_OK;
   }
 
   ShadowLayerForwarder* forwarder = layer->Manager()->AsShadowForwarder();
   if (!forwarder || !forwarder->HasShadowManager()) {
     return NS_OK;
   }
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -1696,17 +1696,18 @@ interface nsIDOMWindowUtils : nsISupport
    */
   AString getOMTAStyle(in Element aElement, in AString aProperty,
                        [optional] in AString aPseudoElement);
 
   /*
    * Returns the value of the transform value on the compositor thread.
    * Unlike the above getOMTAStyle, the transform value returned by this
    * includes both of animating and APZ values.
-   * Note: This function doesn't work on WebRender at all.
+   * Note: This function doesn't work on WebRender at all.  Also this function
+   * does work only for transform layer and opacity layer with animations.
    */
   AString getOMTCTransform(in Element aElement,
                            [optional] in AString aPseudoElement);
 
   /**
    * If aHandlingInput is true, this informs the event state manager that
    * we're handling user input. Otherwise, this is a no-op (as by default
    * we're not handling user input).
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/mochitest/helper_bug1464568_opacity.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test that opacity animation is correctly placed during asynchronous scrolling</title>
+  <script src="apz_test_utils.js"></script>
+  <script src="/tests/SimpleTest/paint_listener.js"></script>
+  <meta name="viewport" content="width=device-width"/>
+  <style>
+    #anim {
+      background: green;
+      width: 100px;
+      height: 100px;
+      animation: anim 100s step-start;
+    }
+    @keyframes anim {
+      from { opacity: 0; }
+      to { opacity: 1; }
+    }
+  </style>
+</head>
+<body>
+ <!--
+  This height should be smaller than window height, otherwise the animation
+  followed by this element will be out of view, thus the animation doesn't run
+  on the compositor.
+  -->
+ <div style="height: 500px"></div>
+ <div id="anim"></div>
+</body>
+<script>
+'use strict';
+
+const utils = SpecialPowers.getDOMWindowUtils(window);
+
+async function test_opacity() {
+  utils.setDisplayPortForElement(0, 0, 300, 1000, document.documentElement, 1);
+  await promiseAllPaintsDone();
+
+  let transform = utils.getOMTCTransform(anim);
+  is(transform, "matrix(1, 0, 0, 1, 0, 0)",
+     "The element shouldn't be moved before scrolling");
+
+  utils.setAsyncScrollOffset(document.documentElement, 0, 300);
+
+  await new Promise(resolve => waitForApzFlushedRepaints(resolve));
+
+  transform = utils.getOMTCTransform(anim);
+  is(transform, "matrix(1, 0, 0, 1, 0, -300)",
+     "Element should have been moved by the offset");
+}
+
+if (utils.layerManagerType == 'WebRender') {
+  ok(true, "This test doesn't need to run on WebRender");
+  subtestDone();
+} else {
+  waitUntilApzStable().then(test_opacity).then(subtestDone);
+}
+
+</script>
+</html>
--- a/gfx/layers/apz/test/mochitest/mochitest.ini
+++ b/gfx/layers/apz/test/mochitest/mochitest.ini
@@ -10,16 +10,17 @@
     helper_bug1162771.html
     helper_bug1271432.html
     helper_bug1280013.html
     helper_bug1285070.html
     helper_bug1299195.html
     helper_bug1346632.html
     helper_bug1414336.html
     helper_bug1464568_transform.html
+    helper_bug1464568_opacity.html
     helper_click.html
     helper_div_pan.html
     helper_drag_click.html
     helper_drag_scroll.html
     helper_iframe_pan.html
     helper_iframe1.html
     helper_iframe2.html
     helper_hittest_backface_hidden.html
--- a/gfx/layers/apz/test/mochitest/test_bug1464568.html
+++ b/gfx/layers/apz/test/mochitest/test_bug1464568.html
@@ -7,16 +7,18 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript">
     if (isApzEnabled()) {
       SimpleTest.waitForExplicitFinish();
 
       const subtests = [
         { file: 'helper_bug1464568_transform.html',
           prefs: [["apz.test.logging_enabled", true]] },
+        { file: 'helper_bug1464568_opacity.html',
+          prefs: [["apz.test.logging_enabled", true]] },
       ];
       // Run the actual test in its own window, because it requires that the
       // root APZC be scrollable. Mochitest pages themselves often run
       // inside an iframe which means we have no control over the root APZC.
       window.onload = () => {
         runSubtestsSeriallyInFreshWindows(subtests)
         .then(SimpleTest.finish, SimpleTest.finish);
       };
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -705,27 +705,35 @@ SampleAnimations(Layer* aLayer,
                                aStorage,
                                animation.property(),
                                animation.data(),
                                animationValue);
             break;
           }
           case AnimationHelper::SampleResult::Skipped:
             switch (animations[0].property()) {
-              case eCSSProperty_opacity:
+              case eCSSProperty_opacity: {
                 MOZ_ASSERT(
                   layer->AsHostLayer()->GetShadowOpacitySetByAnimation());
 #ifdef DEBUG
                 // Disable this assertion until the root cause is fixed in bug
                 // 1459775.
                 // MOZ_ASSERT(FuzzyEqualsMultiplicative(
                 //   Servo_AnimationValue_GetOpacity(animationValue),
                 //   *(aStorage->GetAnimationOpacity(layer->GetCompositorAnimationsId()))));
 #endif
+                // Even if opacity animation value has unchanged, we have to set
+                // the shadow base transform value here since the value might
+                // have been changed by APZC.
+                HostLayer* layerCompositor = layer->AsHostLayer();
+                layerCompositor->SetShadowBaseTransform(
+                  layer->GetBaseTransform());
+                layerCompositor->SetShadowTransformSetByAnimation(false);
                 break;
+              }
               case eCSSProperty_transform: {
                 MOZ_ASSERT(
                   layer->AsHostLayer()->GetShadowTransformSetByAnimation());
                 MOZ_ASSERT(previousValue);
 #ifdef DEBUG
                 const TransformData& transformData =
                   animations[0].data().get_TransformData();
                 Matrix4x4 frameTransform =