Bug 1168263 - Propagate the scroll-clip of a descendant of a layer with a perspective transform up to the layer itself. r=kats,mstange
authorBotond Ballo <botond@mozilla.com>
Wed, 18 Nov 2015 14:21:37 -0500
changeset 308449 47c793c9547bda74452c0b0f3f255f1cee490090
parent 308448 f225e5b0663e80d121fe60c416adf47bf0d213af
child 308450 afd640a20e2c888abc0616093301d5eefa824776
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats, mstange
bugs1168263
milestone45.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 1168263 - Propagate the scroll-clip of a descendant of a layer with a perspective transform up to the layer itself. r=kats,mstange
gfx/layers/composite/AsyncCompositionManager.cpp
gfx/layers/composite/AsyncCompositionManager.h
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -782,23 +782,26 @@ IntersectMaybeRects(const Maybe<IntRectT
     return a;
   } else {
     return Some(a->Intersect(*b));
   }
 }
 
 bool
 AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
-                                                          bool* aOutFoundRoot)
+                                                          bool* aOutFoundRoot,
+                                                          Maybe<ParentLayerIntRect>& aClipDeferredToParent)
 {
+  Maybe<ParentLayerIntRect> clipDeferredFromChildren;
   bool appliedTransform = false;
   for (Layer* child = aLayer->GetFirstChild();
       child; child = child->GetNextSibling()) {
     appliedTransform |=
-      ApplyAsyncContentTransformToTree(child, aOutFoundRoot);
+      ApplyAsyncContentTransformToTree(child, aOutFoundRoot,
+          clipDeferredFromChildren);
   }
 
   Matrix4x4 oldTransform = aLayer->GetTransform();
 
   Matrix4x4 combinedAsyncTransform;
   bool hasAsyncTransform = false;
   ScreenMargin fixedLayerMargins;
 
@@ -895,17 +898,26 @@ AsyncCompositionManager::ApplyAsyncConte
       asyncClip = Some(TransformTo<ParentLayerPixel>(asyncTransform, *asyncClip));
     }
 
     // Combine the local clip with the ancestor scrollframe clip. This is not
     // included in the async transform above, since the ancestor clip should not
     // move with this APZC.
     if (metrics.HasClipRect()) {
       ParentLayerIntRect clip = metrics.ClipRect();
-      asyncClip = IntersectMaybeRects(Some(clip), asyncClip);
+      if (aLayer->GetParent() && aLayer->GetParent()->GetTransformIsPerspective()) {
+        // If our parent layer has a perspective transform, we want to apply
+        // our scroll clip to it instead of to this layer (see bug 1168263).
+        // A layer with a perspective transform shouldn't have multiple
+        // children with FrameMetrics, nor a child with multiple FrameMetrics.
+        MOZ_ASSERT(!aClipDeferredToParent);
+        aClipDeferredToParent = Some(clip);
+      } else {
+        asyncClip = IntersectMaybeRects(Some(clip), asyncClip);
+      }
     }
 
     // Do the same for the ancestor mask layers: ancestorMaskLayers contains
     // the ancestor mask layers for scroll frames *inside* the current scroll
     // frame, so these are the ones we need to shift by our async transform.
     for (Layer* ancestorMaskLayer : ancestorMaskLayers) {
       SetShadowTransform(ancestorMaskLayer,
           ancestorMaskLayer->GetLocalTransform() * asyncTransform);
@@ -931,21 +943,22 @@ AsyncCompositionManager::ApplyAsyncConte
         AdjustForClip(asyncTransformWithoutOverscroll, aLayer);
 
     // Since fixed/sticky layers are relative to their nearest scrolling ancestor,
     // we use the ViewID from the bottommost scrollable metrics here.
     AlignFixedAndStickyLayers(aLayer, aLayer, metrics.GetScrollId(), oldTransform,
                               transformWithoutOverscrollOrOmta, fixedLayerMargins);
   }
 
+  if (hasAsyncTransform || clipDeferredFromChildren) {
+    aLayer->AsLayerComposite()->SetShadowClipRect(
+        IntersectMaybeRects(asyncClip, clipDeferredFromChildren));
+  }
+
   if (hasAsyncTransform) {
-    if (asyncClip) {
-      aLayer->AsLayerComposite()->SetShadowClipRect(asyncClip);
-    }
-
     // 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,
         aLayer->GetLocalTransform() * AdjustForClip(combinedAsyncTransform, aLayer));
 
     // Do the same for the layer's own mask layer, if it has one.
@@ -1353,17 +1366,18 @@ AsyncCompositionManager::TransformShadow
     // async using Gecko). If this fails, fall back to transforming the
     // primary scrollable layer.  "Failing" here means that we don't
     // find a frame that is async scrollable.  Note that the fallback
     // code also includes Fennec which is rendered async.  Fennec uses
     // its own platform-specific async rendering that is done partially
     // in Gecko and partially in Java.
     wantNextFrame |= SampleAPZAnimations(LayerMetricsWrapper(root), aCurrentFrame);
     bool foundRoot = false;
-    if (ApplyAsyncContentTransformToTree(root, &foundRoot)) {
+    Maybe<ParentLayerIntRect> clipDeferredFromChildren;
+    if (ApplyAsyncContentTransformToTree(root, &foundRoot, clipDeferredFromChildren)) {
 #if defined(MOZ_ANDROID_APZ)
       MOZ_ASSERT(foundRoot);
       if (foundRoot && mFixedLayerMargins != ScreenMargin()) {
         MoveScrollbarForLayerMargin(root, mRootScrollableId, mFixedLayerMargins);
       }
 #endif
     } else {
       nsAutoTArray<Layer*,1> scrollableLayers;
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -127,18 +127,21 @@ public:
   void GetFrameUniformity(FrameUniformityData* aFrameUniformityData);
 
 private:
   void TransformScrollableLayer(Layer* aLayer);
   // Return true if an AsyncPanZoomController content transform was
   // applied for |aLayer|. |*aOutFoundRoot| is set to true on Android only, if
   // one of the metrics on one of the layers was determined to be the "root"
   // and its state was synced to the Java front-end. |aOutFoundRoot| must be
-  // non-null.
-  bool ApplyAsyncContentTransformToTree(Layer* aLayer, bool* aOutFoundRoot);
+  // non-null. As the function recurses over the layer tree, a layer may
+  // populate |aClipDeferredToParent| a clip rect it wants to set on its parent.
+  bool ApplyAsyncContentTransformToTree(Layer* aLayer,
+                                        bool* aOutFoundRoot,
+                                        Maybe<ParentLayerIntRect>& aClipDeferredToParent);
   /**
    * Update the shadow transform for aLayer assuming that is a scrollbar,
    * so that it stays in sync with the content that is being scrolled by APZ.
    */
   void ApplyAsyncTransformToScrollbar(Layer* aLayer);
 
   void SetFirstPaintViewport(const LayerIntPoint& aOffset,
                              const CSSToLayerScale& aZoom,