Bug 1000167 - Choose the right animated geometry root for inactive layer contents. r=roc
authorMarkus Stange <mstange@themasta.com>
Thu, 24 Apr 2014 10:18:11 +0200
changeset 180257 36dcdf8ec0855a19c89ec5729315025beb21ecb8
parent 180256 e2514d232f9058d06ca6065b93c145a72f3dfe14
child 180258 a26c8f53a22365985eabcf3b5120fbb26f11fd96
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersroc
bugs1000167
milestone31.0a1
Bug 1000167 - Choose the right animated geometry root for inactive layer contents. r=roc Choosing a frame that is scrolled along with the inactive layer results in a fixed offset between the two, so the transform that we set on the thebes layer in the basic layer manager of the inactive layer doesn't change when the page is scrolled.
layout/base/FrameLayerBuilder.cpp
layout/reftests/invalidation/reftest.list
layout/reftests/invalidation/scroll-inactive-layers.html
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -495,16 +495,19 @@ public:
     mContainerLayer(aContainerLayer),
     mParameters(aParameters),
     mNextFreeRecycledThebesLayer(0)
   {
     nsPresContext* presContext = aContainerFrame->PresContext();
     mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
     mContainerReferenceFrame = aContainerItem ? aContainerItem->ReferenceFrameForChildren() :
       mBuilder->FindReferenceFrameFor(mContainerFrame);
+    mContainerAnimatedGeometryRoot = aContainerItem
+      ? nsLayoutUtils::GetAnimatedGeometryRootFor(aContainerItem, aBuilder)
+      : mContainerReferenceFrame;
     // When AllowResidualTranslation is false, display items will be drawn
     // scaled with a translation by integer pixels, so we know how the snapping
     // will work.
     mSnappingEnabled = aManager->IsSnappingEffectiveTransforms() &&
       !mParameters.AllowResidualTranslation();
     CollectOldLayers();
   }
 
@@ -700,16 +703,17 @@ protected:
   bool ChooseAnimatedGeometryRoot(const nsDisplayList& aList,
                                   const nsIFrame **aAnimatedGeometryRoot);
 
   nsDisplayListBuilder*            mBuilder;
   LayerManager*                    mManager;
   FrameLayerBuilder*               mLayerBuilder;
   nsIFrame*                        mContainerFrame;
   const nsIFrame*                  mContainerReferenceFrame;
+  const nsIFrame*                  mContainerAnimatedGeometryRoot;
   ContainerLayer*                  mContainerLayer;
   ContainerLayerParameters         mParameters;
   /**
    * The region of ThebesLayers that should be invalidated every time
    * we recycle one.
    */
   nsIntRegion                      mInvalidThebesContent;
   nsRect                           mBounds;
@@ -2447,17 +2451,17 @@ ContainerState::ProcessDisplayItems(cons
     } else {
       forceInactive = false;
       if (mManager->IsWidgetLayerManager()) {
         animatedGeometryRoot = nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder);
       } else {
         // For inactive layer subtrees, splitting content into ThebesLayers
         // based on animated geometry roots is pointless. It's more efficient
         // to build the minimum number of layers.
-        animatedGeometryRoot = mContainerReferenceFrame;
+        animatedGeometryRoot = mContainerAnimatedGeometryRoot;
       }
       if (animatedGeometryRoot != lastAnimatedGeometryRoot) {
         lastAnimatedGeometryRoot = animatedGeometryRoot;
         topLeft = animatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame);
       }
     }
     bool shouldFixToViewport = !animatedGeometryRoot->GetParent() &&
       item->ShouldFixToViewport(mBuilder);
--- a/layout/reftests/invalidation/reftest.list
+++ b/layout/reftests/invalidation/reftest.list
@@ -33,8 +33,9 @@ pref(layout.animated-image-layers.enable
 == filter-userspace-offset.svg?offsetContainer=innerSVG&mask=boundingBox filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=foreignObject&mask=boundingBox filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=rect&mask=userSpace-at100 filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=use&mask=userSpace-atZero filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=innerSVG&mask=userSpace-atZero filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=foreignObject&mask=userSpace-at100 filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=rect&filter=matrix-fillPaint-boundingBox filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=rect&filter=matrix-fillPaint-userSpace-at100 filter-userspace-offset.svg
+== scroll-inactive-layers.html scroll-inactive-layers.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/invalidation/scroll-inactive-layers.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Scrolling over inactive layers shouldn't repaint their contents</title>
+
+<style>
+
+.outer {
+  border: 1px solid black;
+  width: 100px;
+  height: 2000px;
+  margin-top: 200px;
+  margin-right: 20px;
+  padding-top: 100px;
+  float: left;
+}
+
+.opacity {
+  opacity: 0.5;
+}
+
+.transform {
+  transform: translateX(1px);
+}
+
+.filter {
+  filter: url(#filter);
+}
+
+.mask {
+  mask: url(#mask);
+}
+
+.reftest-no-paint {
+  height: 50px;
+  border: 1px solid lime;
+}
+
+</style>
+
+<svg height="0">
+  <defs>
+    <filter id="filter" filterUnits="objectBoundingBox"
+            x="0%" y="0%" width="100%" height="100%"
+            color-interpolation-filters="sRGB">
+      <feMerge><feMergeNode/><feMerge>
+    </filter>
+    <mask id="mask" maskContentUnits="objectBoundingBox">
+      <rect x="0" y="0" width="1" height="1" fill="white"/>
+    </mask>
+  </defs>
+</svg>
+
+<div class="outer opacity">
+  <div class="reftest-no-paint"></div>
+</div>
+
+<div class="outer transform">
+  <div class="reftest-no-paint"></div>
+</div>
+
+<div class="outer filter">
+  <div class="reftest-no-paint"></div>
+</div>
+
+<div class="outer mask">
+  <div class="reftest-no-paint"></div>
+</div>
+
+<script>
+
+function doTest() {
+  document.documentElement.scrollTop = 100;
+  document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest, false);
+
+</script>