Bug 1260335 - On perspective ContainerLayers, the clip deferred from their child layer needs to be affected by the perspective layer's async transforms. r?botond draft
authorMarkus Stange <mstange@themasta.com>
Wed, 30 Mar 2016 15:35:32 -0400
changeset 346023 188ec4ff29553c1e88196148d7e4532e4fce53ae
parent 346022 0b19c783ec5095578c0983b96f34fb09525ee75d
child 517304 175eefbb36908e8fa91d372abdd4140ad2773b6b
push id14215
push usermstange@themasta.com
push dateWed, 30 Mar 2016 19:39:23 +0000
reviewersbotond
bugs1260335
milestone48.0a1
Bug 1260335 - On perspective ContainerLayers, the clip deferred from their child layer needs to be affected by the perspective layer's async transforms. r?botond MozReview-Commit-ID: EEgsdFXGI1E
gfx/layers/composite/AsyncCompositionManager.cpp
layout/reftests/async-scrolling/perspective-scrolling-4-ref.html
layout/reftests/async-scrolling/perspective-scrolling-4.html
layout/reftests/async-scrolling/reftest.list
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -819,16 +819,21 @@ AsyncCompositionManager::ApplyAsyncConte
   // Each layer has multiple clips. Its local clip, which must move with async
   // transforms, and its scrollframe clips, which are the clips between each
   // scrollframe and its ancestor scrollframe. Scrollframe clips include the
   // composition bounds and any other clips induced by layout.
   //
   // The final clip for the layer is the intersection of these clips.
   Maybe<ParentLayerIntRect> asyncClip = aLayer->GetClipRect();
 
+  // If we are a perspective transform ContainerLayer, apply the clip deferred
+  // from our child (if there is any) before we iterate over our frame metrics,
+  // because this clip is subject to all async transforms of this layer.
+  asyncClip = IntersectMaybeRects(asyncClip, clipDeferredFromChildren);
+
   // The transform of a mask layer is relative to the masked layer's parent
   // layer. So whenever we apply an async transform to a layer, we need to
   // apply that same transform to the layer's own mask layer.
   // A layer can also have "ancestor" mask layers for any rounded clips from
   // its ancestor scroll frames. A scroll frame mask layer only needs to be
   // async transformed for async scrolls of this scroll frame's ancestor
   // scroll frames, not for async scrolls of this scroll frame itself.
   // In the loop below, we iterate over scroll frames from inside to outside.
@@ -970,18 +975,17 @@ AsyncCompositionManager::ApplyAsyncConte
     if (metrics.GetMaskLayerIndex()) {
       size_t maskLayerIndex = metrics.GetMaskLayerIndex().value();
       Layer* ancestorMaskLayer = aLayer->GetAncestorMaskLayerAt(maskLayerIndex);
       ancestorMaskLayers.AppendElement(ancestorMaskLayer);
     }
   }
 
   if (hasAsyncTransform || clipDeferredFromChildren) {
-    aLayer->AsLayerComposite()->SetShadowClipRect(
-        IntersectMaybeRects(asyncClip, clipDeferredFromChildren));
+    aLayer->AsLayerComposite()->SetShadowClipRect(asyncClip);
   }
 
   if (hasAsyncTransform) {
     // Apply the APZ transform on top of GetLocalTransform() here (rather than
     // GetTransform()) in case the OMTA code in SampleAnimations already set a
     // shadow transform; in that case we want to apply ours on top of that one
     // rather than clobber it.
     SetShadowTransform(aLayer,
new file mode 100644
--- /dev/null
+++ b/layout/reftests/async-scrolling/perspective-scrolling-4-ref.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html lang="en"
+     reftest-async-scroll
+     reftest-displayport-x="0" reftest-displayport-y="0"
+     reftest-displayport-w="800" reftest-displayport-h="1000"
+     reftest-async-scroll-x="0" reftest-async-scroll-y="0">
+<meta charset="utf-8">
+<title>Reference: Perspective scrolling with nested clips</title>
+
+<style>
+
+html {
+  padding: 50px 0 3000px;
+}
+
+body {
+  margin: 0;
+}
+
+.scrollbox {
+  width: 600px;
+  height: 500px;
+  perspective: 1px;
+  overflow: auto;
+}
+
+.transformed {
+  will-change: transform;
+  width: 200px;
+  height: 200px;
+  margin: 200px 100px;
+  border: 10px solid black;
+}
+
+.spacer {
+  height: 4000px;
+}
+
+</style>
+
+<div class="scrollbox"
+     reftest-displayport-x="0" reftest-displayport-y="0"
+     reftest-displayport-w="600" reftest-displayport-h="2000"
+     reftest-async-scroll-x="0" reftest-async-scroll-y="0">
+
+<div class="transformed"></div>
+<div class="spacer"></div>
+
+<script>
+
+document.scrollingElement.scrollTop = 250;
+
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/async-scrolling/perspective-scrolling-4.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html lang="en"
+     reftest-async-scroll
+     reftest-displayport-x="0" reftest-displayport-y="0"
+     reftest-displayport-w="800" reftest-displayport-h="1000"
+     reftest-async-scroll-x="0" reftest-async-scroll-y="250">
+<meta charset="utf-8">
+<title>Perspective scrolling with nested clips</title>
+
+<style>
+
+html {
+  padding: 50px 0 3000px;
+}
+
+body {
+  margin: 0;
+}
+
+.scrollbox {
+  width: 600px;
+  height: 500px;
+  perspective: 1px;
+  overflow: auto;
+}
+
+.transformed {
+  will-change: transform;
+  width: 200px;
+  height: 200px;
+  margin: 200px 100px;
+  border: 10px solid black;
+}
+
+.spacer {
+  height: 4000px;
+}
+
+</style>
+
+<div class="scrollbox"
+     reftest-displayport-x="0" reftest-displayport-y="0"
+     reftest-displayport-w="600" reftest-displayport-h="2000"
+     reftest-async-scroll-x="0" reftest-async-scroll-y="0">
+
+<div class="transformed"></div>
+<div class="spacer"></div>
+
+<script>
+// document.scrollingElement.scrollTop = 250;
+// document.querySelector(".scrollbox").scrollTop = 0;
+</script>
--- a/layout/reftests/async-scrolling/reftest.list
+++ b/layout/reftests/async-scrolling/reftest.list
@@ -34,16 +34,17 @@ skip-if(!asyncPan) == position-sticky-tr
 skip-if(!asyncPan) == offscreen-prerendered-active-opacity.html offscreen-prerendered-active-opacity-ref.html
 fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-1.html offscreen-clipped-blendmode-ref.html
 fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-2.html offscreen-clipped-blendmode-ref.html
 fuzzy-if(Android,6,4) skip == offscreen-clipped-blendmode-3.html offscreen-clipped-blendmode-ref.html # bug 1251588 - wrong AGR on mix-blend-mode item
 fuzzy-if(Android,6,4) skip-if(!asyncPan) == offscreen-clipped-blendmode-4.html offscreen-clipped-blendmode-ref.html
 fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-1.html perspective-scrolling-1-ref.html
 fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-2.html perspective-scrolling-2-ref.html
 fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-3.html perspective-scrolling-3-ref.html
+fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-4.html perspective-scrolling-4-ref.html
 skip-if(!asyncPan) == background-blend-mode-1.html background-blend-mode-1-ref.html
 
 # for the following tests, we want to disable the low-precision buffer
 # as it will expand the displayport beyond what the test specifies in
 # its reftest-displayport attributes, and interfere with where we expect
 # checkerboarding to occur
 default-preferences pref(layers.low-precision-buffer,false)
 skip-if(!asyncPan) == checkerboard-1.html checkerboard-1-ref.html