Bug 1472465 - Update flattened nsDisplayOpacity geometry despite empty invalidation region draft
authorMiko Mynttinen <mikokm@gmail.com>
Mon, 16 Jul 2018 01:09:23 +0200
changeset 818611 7cd5491ac64d92d3e99b233aa0ff96b96b2911b2
parent 818533 04dd259d71db60341016eccf53ced43742319631
push id116288
push userbmo:mikokm@gmail.com
push dateSun, 15 Jul 2018 23:09:48 +0000
bugs1472465
milestone63.0a1
Bug 1472465 - Update flattened nsDisplayOpacity geometry despite empty invalidation region MozReview-Commit-ID: 7mrTuQ6gEoA
layout/painting/FrameLayerBuilder.cpp
layout/painting/nsDisplayList.h
layout/reftests/bugs/bug1472465-1-ref.html
layout/reftests/bugs/bug1472465-1.html
layout/reftests/bugs/reftest.list
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -4983,17 +4983,18 @@ FrameLayerBuilder::ComputeGeometryChange
     const nsRegion& changedFrameInvalidations = aData->GetChangedFrameInvalidations();
     aData->mGeometry->MoveBy(shift);
     item->ComputeInvalidationRegion(mDisplayListBuilder, aData->mGeometry, &combined);
 
     // Only allocate a new geometry object if something actually changed, otherwise the existing
     // one should be fine. We always reallocate for inactive layers, since these types don't
     // implement ComputeInvalidateRegion (and rely on the ComputeDifferences call in
     // AddPaintedDisplayItem instead).
-    if (!combined.IsEmpty() || aData->mLayerState == LAYER_INACTIVE) {
+    if (!combined.IsEmpty() || aData->mLayerState == LAYER_INACTIVE ||
+        item->NeedsGeometryUpdates()) {
       geometry = item->AllocateGeometry(mDisplayListBuilder);
     }
     aData->mClip.AddOffsetAndComputeDifference(shift, aData->mGeometry->ComputeInvalidationRegion(),
                                                clip, geometry ? geometry->ComputeInvalidationRegion() :
                                                                 aData->mGeometry->ComputeInvalidationRegion(),
                                                &combined);
 
     // Add in any rect that the frame specified
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -2598,16 +2598,25 @@ public:
    * flattening is distinctly different from FlattenTo, which occurs before
    * items are merged together.
    */
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) {
     return false;
   }
 
   /**
+   * Returns true if this item needs to have its geometry updated, despite
+   * returning empty invalidation region.
+   */
+  virtual bool NeedsGeometryUpdates() const
+  {
+    return false;
+  }
+
+  /**
    * Some items such as those calling into the native themed widget machinery
    * have to be painted on the content process. In this case it is best to avoid
    * allocating layers that serializes and forwards the work to the compositor.
    */
   virtual bool MustPaintOnContentSide() const { return false; }
 
   /**
    * If this has a child list where the children are in the same coordinate
@@ -5194,16 +5203,26 @@ public:
     return nsDisplayWrapList::IsInvalid(aRect);
   }
   virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
                             float aOpacity,
                             const DisplayItemClipChain* aClip) override;
   virtual bool CanApplyOpacity() const override;
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
 
+  bool NeedsGeometryUpdates() const override
+  {
+    // For flattened nsDisplayOpacity items, ComputeInvalidationRegion() only
+    // handles invalidation for changed |mOpacity|. In order to keep track of
+    // the current bounds of the item for invalidation, nsDisplayOpacityGeometry
+    // for the corresponding DisplayItemData needs to be updated, even if the
+    // reported invalidation region is empty.
+    return mChildOpacityState == ChildOpacityState::Deferred;
+  }
+
   /**
    * Returns true if ShouldFlattenAway() applied opacity to children.
    */
   bool OpacityAppliedToChildren() const { return mChildOpacityState == ChildOpacityState::Applied; }
 
   static bool NeedsActiveLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
   NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
   virtual void WriteDebugInfo(std::stringstream& aStream) override;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/bug1472465-1-ref.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>Bug 1472465</title>
+<style type="text/css">
+#container {
+  border: 1px solid;
+  width: 500px;
+  height: 500px;
+  overflow: hidden;
+}
+
+#box {
+  opacity: 1.0;
+  position: absolute;
+  top: 100px
+  left: 100px;
+  z-index:1;
+  background-color: green;
+  width: 100px;
+  height: 100px;
+}
+
+#bg {
+  position:relative;
+  width: 2500px;
+  height: 2500px;
+  left: 0px;
+  top: 0px;
+}
+</style>
+
+</head>
+<body>
+<div id="container">
+    <div id="bg">
+        <div id="box">
+          Text to force layer state to inactive, that will get flattened.
+        </div>
+    </div>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/bug1472465-1.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="UTF-8">
+<title>Bug 1472465</title>
+<style type="text/css">
+#container {
+  border: 1px solid;
+  width: 500px;
+  height: 500px;
+  overflow: hidden;
+}
+
+#box {
+  opacity: 0.1;
+  position: absolute;
+  top: 100px
+  left: 100px;
+  z-index:1;
+  background-color: green;
+  width: 100px;
+  height: 100px;
+}
+
+#bg {
+  position:relative;
+  width: 2500px;
+  height: 2500px;
+  left: 300px;
+  top: 300px;
+}
+</style>
+
+<script type="text/javascript">
+function changeOpacity() {
+  var box = document.querySelector("#box");
+  box.style.opacity = "1.0";
+
+  document.documentElement.removeAttribute("class");
+}
+
+function moveBg() {
+  var bg = document.querySelector("#bg");
+  bg.style.top = "0px";
+  bg.style.left = "0px";
+
+  setTimeout(changeOpacity, 200);
+}
+
+function doTest() {
+  moveBg();
+}
+
+window.addEventListener("MozReftestInvalidate", doTest);
+</script>
+
+</head>
+<body>
+<div id="container">
+    <div id="bg">
+        <div id="box">
+          Text to force layer state to inactive, that will get flattened.
+        </div>
+    </div>
+</div>
+
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -2074,8 +2074,9 @@ fuzzy-if(Android,66,574) fuzzy-if(d2d,89
 == 1430869.html 1430869-ref.html
 == 1432541.html 1432541-ref.html
 pref(layout.css.moz-document.url-prefix-hack.enabled,true) == 1446470.html 1035091-ref.html
 pref(layout.css.moz-document.url-prefix-hack.enabled,false) == 1446470-2.html 1035091-ref.html
 test-pref(layout.css.prefixes.gradients,false) == 1451874.html 1451874-ref.html
 == 1456111-1.html about:blank
 test-pref(layout.css.contain.enabled,false) == 1466008.html 1466008-ref.html
 fuzzy(1,625) == 1466638-1.html 1466638-1-ref.html
+== bug1472465-1.html bug1472465-1-ref.html