Bug 1280013 - Incorporate the APZ callback transforms when using the root composition bounds to clip the displayport base. r?botond,tnikkel draft
authorKartikaya Gupta <kgupta@mozilla.com>
Sun, 26 Jun 2016 12:32:40 -0400
changeset 381374 a7322858942b856da6c9c73bdac7a06559f0876a
parent 381369 c2da34d96746288b5fee27bf6542a12c9f410988
child 381375 61e97c2632086f2422d3fccb6029dc307879640d
push id21457
push userkgupta@mozilla.com
push dateSun, 26 Jun 2016 16:33:09 +0000
reviewersbotond, tnikkel
bugs1280013
milestone50.0a1
Bug 1280013 - Incorporate the APZ callback transforms when using the root composition bounds to clip the displayport base. r?botond,tnikkel MozReview-Commit-ID: 8N1MUjEjvGC
gfx/layers/apz/util/APZCCallbackHelper.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/generic/nsGfxScrollFrame.cpp
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -395,49 +395,29 @@ APZCCallbackHelper::ApplyCallbackTransfo
     if (nsIPresShell* shell = GetRootDocumentPresShell(content)) {
         input = input / shell->GetResolution();
     }
 
     // This represents any resolution on the Root Content Document (RCD)
     // that's not on the Root Document (RD). That is, on platforms where
     // RCD == RD, it's 1, and on platforms where RCD != RD, it's the RCD
     // resolution. 'input' has this resolution applied, but the scroll
-    // deltas retrieved below do not, so we need to apply them to the
-    // deltas before adding the deltas to 'input'. (Technically, deltas
+    // delta retrieved below do not, so we need to apply them to the
+    // delta before adding the delta to 'input'. (Technically, deltas
     // from scroll frames outside the RCD would already have this
     // resolution applied, but we don't have such scroll frames in
     // practice.)
     float nonRootResolution = 1.0f;
     if (nsIPresShell* shell = GetRootContentDocumentPresShellForContent(content)) {
       nonRootResolution = shell->GetCumulativeNonRootScaleResolution();
     }
-    // Now apply the callback-transform.
-    // XXX: Walk up the frame tree from the frame of this content element
-    // to the root of the frame tree, and apply any apzCallbackTransform
-    // found on the way. This is only approximately correct, as it does
-    // not take into account CSS transforms, nor differences in structure between
-    // the frame tree (which determines the transforms we're applying)
-    // and the layer tree (which determines the transforms we *want* to
-    // apply).
-    nsIFrame* frame = content->GetPrimaryFrame();
-    nsCOMPtr<nsIContent> lastContent;
-    while (frame) {
-        if (content && (content != lastContent)) {
-            void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform);
-            if (property) {
-                CSSPoint delta = (*static_cast<CSSPoint*>(property));
-                delta = delta * nonRootResolution;
-                input += delta;
-            }
-        }
-        frame = frame->GetParent();
-        lastContent = content;
-        content = frame ? frame->GetContent() : nullptr;
-    }
-    return input;
+    // Now apply the callback-transform. This is only approximately correct,
+    // see the comment on GetCumulativeApzCallbackTransform for details.
+    CSSPoint transform = nsLayoutUtils::GetCumulativeApzCallbackTransform(content->GetPrimaryFrame());
+    return input + transform * nonRootResolution;
 }
 
 LayoutDeviceIntPoint
 APZCCallbackHelper::ApplyCallbackTransform(const LayoutDeviceIntPoint& aPoint,
                                            const ScrollableLayerGuid& aGuid,
                                            const CSSToLayoutDeviceScale& aScale)
 {
     LayoutDevicePoint point = LayoutDevicePoint(aPoint.x, aPoint.y);
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -9326,8 +9326,31 @@ nsLayoutUtils::IsTransformed(nsIFrame* a
   for (nsIFrame* f = aForFrame; f != aTopFrame; f = f->GetParent()) {
     if (f->IsTransformed()) {
       return true;
     }
   }
   return false;
 }
 
+/*static*/ CSSPoint
+nsLayoutUtils::GetCumulativeApzCallbackTransform(nsIFrame* aFrame)
+{
+  CSSPoint delta;
+  if (!aFrame) {
+    return delta;
+  }
+  nsIFrame* frame = aFrame;
+  nsCOMPtr<nsIContent> content = frame->GetContent();
+  nsCOMPtr<nsIContent> lastContent;
+  while (frame) {
+    if (content && (content != lastContent)) {
+      void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform);
+      if (property) {
+        delta += *static_cast<CSSPoint*>(property);
+      }
+    }
+    frame = GetCrossDocParentFrame(frame);
+    lastContent = content;
+    content = frame ? frame->GetContent() : nullptr;
+  }
+  return delta;
+}
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2831,16 +2831,26 @@ public:
 
   /**
    * Walks up the frame tree from |aForFrame| up to |aTopFrame|, or to the
    * root of the frame tree if |aTopFrame| is nullptr, and returns true if
    * a transformed frame is encountered.
    */
   static bool IsTransformed(nsIFrame* aForFrame, nsIFrame* aTopFrame = nullptr);
 
+  /**
+   * Walk up from aFrame to the cross-doc root, accumulating all the APZ callback
+   * transforms on the content elements encountered along the way. Return the
+   * accumulated value.
+   * XXX: Note that this does not take into account CSS transforms, nor
+   * differences in structure between the frame tree and the layer tree (which
+   * is probably what we *want* to be computing).
+   */
+  static CSSPoint GetCumulativeApzCallbackTransform(nsIFrame* aFrame);
+
 private:
   static uint32_t sFontSizeInflationEmPerLine;
   static uint32_t sFontSizeInflationMinTwips;
   static uint32_t sFontSizeInflationLineThreshold;
   static int32_t  sFontSizeInflationMappingIntercept;
   static uint32_t sFontSizeInflationMaxRatio;
   static bool sFontSizeInflationForceEnabled;
   static bool sFontSizeInflationDisabledInMasterProcess;
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3529,17 +3529,30 @@ ScrollFrameHelper::DecideScrollableLayer
 
               // If rootFrame is the RCD-RSF then CalculateCompositionSizeForFrame
               // did not take the document's resolution into account, so we must.
               if (rootPresContext->IsRootContentDocument() &&
                   rootFrame == rootPresShell->GetRootScrollFrame()) {
                 rootCompBounds = rootCompBounds.RemoveResolution(rootPresShell->GetResolution());
               }
 
+              // We want to convert the root composition bounds from the coordinate
+              // space of |rootFrame| to the coordinate space of |mOuter|. We do
+              // that with the TransformRect call below. However, since we care
+              // about the root composition bounds relative to what the user is
+              // actually seeing, we also need to incorporate the APZ callback
+              // transforms into this. Most of the time those transforms are
+              // negligible, but in some cases (e.g. when a zoom is applied on
+              // an overflow:hidden document) it is not (see bug 1280013).
+              // XXX: Eventually we may want to create a modified version of
+              // TransformRect that includes the APZ callback transforms
+              // directly.
               nsLayoutUtils::TransformRect(rootFrame, mOuter, rootCompBounds);
+              rootCompBounds += CSSPoint::ToAppUnits(
+                  nsLayoutUtils::GetCumulativeApzCallbackTransform(mOuter));
 
               displayportBase = displayportBase.Intersect(rootCompBounds);
             }
           }
         }
 
         displayportBase -= mScrollPort.TopLeft();
       }