Bug 1510486 - Set WillChangeBits::TRANSFORM for individual transform. r=hiro
authorBoris Chiou <boris.chiou@gmail.com>
Mon, 30 Sep 2019 21:52:30 +0000
changeset 495759 83d5c614484033e41dfbf35f3f05f01836aa405f
parent 495758 041568c2454936a139db057b80ae2465452224bd
child 495760 40de8675c53c4593ae201c261406a79a5e8c0adb
push id114140
push userdvarga@mozilla.com
push dateWed, 02 Oct 2019 18:04:51 +0000
treeherdermozilla-inbound@32eb0ea893f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershiro
bugs1510486
milestone71.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 1510486 - Set WillChangeBits::TRANSFORM for individual transform. r=hiro We always check StyleWillChangeBits_TRANSFORM bit together with a transform-like property set, so using WillChangeBits::TRANSFORM bit to represent all transform-like properties is ok. However, it seems the new test case works well even if we don't have this patch. I still add it for individual transform properties to make sure the test coverage is enough anyway. Differential Revision: https://phabricator.services.mozilla.com/D47509
layout/base/tests/chrome/chrome.ini
layout/base/tests/chrome/test_will_change.html
servo/components/style/values/specified/box.rs
--- a/layout/base/tests/chrome/chrome.ini
+++ b/layout/base/tests/chrome/chrome.ini
@@ -1,10 +1,11 @@
 [DEFAULT]
 prefs =
+  layout.css.individual-transform.enabled=true
   plugin.load_flash_only=false
 skip-if = os == 'android'
 support-files =
   animated.gif
   blue-32x32.png
   bug551434_childframe.html
   chrome_content_integration_window.xul
   default_background_window.xul
--- a/layout/base/tests/chrome/test_will_change.html
+++ b/layout/base/tests/chrome/test_will_change.html
@@ -6,16 +6,19 @@
   <script src="chrome://mochikit/content/tests/SimpleTest/paint_listener.js"></script>
   <style>
     #checkOpacityRepaint {
       will-change: opacity;
     }
     #checkTransformRepaint {
       will-change: transform;
     }
+    #checkTranslateRepaint {
+      will-change: translate;
+    }
     div {
       width: 100px;
       height: 100px;
       background: radial-gradient(ellipse at center, #87e0fd 0%,#53cbf1 40%,#05abe0 100%);
     }
   </style>
 </head>
 <body>
@@ -23,76 +26,95 @@
     Check repaint without will-change
   </div>
   <div id="checkOpacityRepaint">
     Check repaint with will-change
   </div>
   <div id="checkTransformRepaint">
     Check repaint with will-change
   </div>
+  <div id="checkTranslateRepaint">
+    Check repaint with will-change
+  </div>
 </body>
 <script>
 
 var utils = window.windowUtils;
 
-var initialPaintCount = 0;
-
-function test_checkRepaint(next) {
-  var element = document.getElementById("checkRepaint");
-  waitForAllPaintsFlushed(function () {
-    utils.checkAndClearPaintedState(element);
-    element.style.opacity = "0.5";
-    waitForAllPaintsFlushed(function () {
-      var painted = utils.checkAndClearPaintedState(element);
-      // *** We check that this repaints because the test is relying
-      //     on this property. If this is broken then this test wont
-      //     be reliable check for will-change.
-      is(painted, true, "element should have been painted");
-      next();
-    });
+function waitForPaints() {
+  return new Promise(function(resolve, reject) {
+    waitForAllPaintsFlushed(resolve);
   });
 }
 
-function test_checkOpacityRepaint(next) {
+add_task(async () => {
+  var element = document.getElementById("checkRepaint");
+
+  await waitForPaints();
+
+  utils.checkAndClearPaintedState(element);
+  element.style.opacity = "0.5";
+
+  await waitForPaints();
+
+  var painted = utils.checkAndClearPaintedState(element);
+  // *** We check that this repaints because the test is relying
+  //     on this property. If this is broken then this test wont
+  //     be reliable check for will-change.
+  is(painted, true, "element should have been painted");
+});
+
+add_task(async () => {
   var element = document.getElementById("checkOpacityRepaint");
-  waitForAllPaintsFlushed(function () {
-    utils.checkAndClearPaintedState(element);
-    element.style.opacity = "0.5";
-    waitForAllPaintsFlushed(function () {
-      var painted = utils.checkAndClearPaintedState(element);
-      // BasicLayers' heuristics are so that even with will-change:opacity,
-      // we can still have repaints.
-      if (utils.layerManagerType != "Basic") {
-        is(painted, false, "will-change checkOpacityRepaint element should not have been painted");
-      }
-      next();
-    });
-  });
-}
+
+  await waitForPaints();
+
+  utils.checkAndClearPaintedState(element);
+  element.style.opacity = "0.5";
+
+  await waitForPaints();
 
-function test_checkTransformRepaint(next) {
+  var painted = utils.checkAndClearPaintedState(element);
+  // BasicLayers' heuristics are so that even with will-change:opacity,
+  // we can still have repaints.
+  if (utils.layerManagerType != "Basic") {
+    is(painted, false, "will-change checkOpacityRepaint element should not have been painted");
+  }
+});
+
+add_task(async () => {
   var element = document.getElementById("checkTransformRepaint");
-  waitForAllPaintsFlushed(function () {
-    utils.checkAndClearPaintedState(element);
-    element.style.transform = "translateY(-5px)";
-    waitForAllPaintsFlushed(function () {
-      var painted = utils.checkAndClearPaintedState(element);
-      // BasicLayers' heuristics are so that even with will-change:transform,
-      // we can still have repaints.
-      if (utils.layerManagerType != "Basic") {
-        is(painted, false, "will-change checkTransformRepaint element should not have been painted");
-      }
-      next();
-    });
-  });
-}
+
+  await waitForPaints();
+
+  utils.checkAndClearPaintedState(element);
+  element.style.transform = "translateY(-5px)";
+
+  await waitForPaints();
+
+  var painted = utils.checkAndClearPaintedState(element);
+  // BasicLayers' heuristics are so that even with will-change:transform,
+  // we can still have repaints.
+  if (utils.layerManagerType != "Basic") {
+    is(painted, false, "will-change checkTransformRepaint element should not have been painted");
+  }
+});
 
-SimpleTest.waitForExplicitFinish();
-test_checkRepaint(function(){
-  test_checkOpacityRepaint(function(){
-    test_checkTransformRepaint(function(){
-      SimpleTest.finish();
-    });
-  });
+add_task(async () => {
+  var element = document.getElementById("checkTranslateRepaint");
+
+  await waitForPaints();
+
+  utils.checkAndClearPaintedState(element);
+  element.style.translate = "5px";
+
+  await waitForPaints();
+
+  var painted = utils.checkAndClearPaintedState(element);
+  // BasicLayers' heuristics are so that even with will-change:translate,
+  // we can still have repaints.
+  if (utils.layerManagerType != "Basic") {
+    is(painted, false, "will-change checkTranslateRepaint element should not have been painted");
+  }
 });
 
 </script>
 </html>
--- a/servo/components/style/values/specified/box.rs
+++ b/servo/components/style/values/specified/box.rs
@@ -1148,17 +1148,19 @@ bitflags! {
         /// Abs pos containing block.
         const ABSPOS_CB = 1 << 5;
     }
 }
 
 fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
     let mut flags = match longhand {
         LonghandId::Opacity => WillChangeBits::OPACITY,
-        LonghandId::Transform => WillChangeBits::TRANSFORM,
+        LonghandId::Transform | LonghandId::Translate | LonghandId::Rotate | LonghandId::Scale => {
+            WillChangeBits::TRANSFORM
+        }
         _ => WillChangeBits::empty(),
     };
 
     let property_flags = longhand.flags();
     if property_flags.contains(PropertyFlags::CREATES_STACKING_CONTEXT) {
         flags |= WillChangeBits::STACKING_CONTEXT;
     }
     if property_flags.contains(PropertyFlags::FIXPOS_CB) {