Bug 1556556 - Add a "relative to layout viewport" option for display list building. r=mstange,mattwoodrow
☠☠ backed out by 95fac5915a31 ☠ ☠
authorBotond Ballo <botond@mozilla.com>
Tue, 28 Apr 2020 01:37:47 +0000
changeset 593495 a7bd34d961bbdf9783e7b6e21137c671495c06c9
parent 593494 fccd1d3c71891e695939bf082a21a8c182411037
child 593496 93190ae4f5ffd4b9f8a8cfa2a5d4f67898c6b085
push id2335
push userffxbld-merge
push dateMon, 25 May 2020 13:47:24 +0000
treeherdermozilla-release@69ca1d06f46a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange, mattwoodrow
bugs1556556
milestone77.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 1556556 - Add a "relative to layout viewport" option for display list building. r=mstange,mattwoodrow Use it in document.elementFromPoint(). Differential Revision: https://phabricator.services.mozilla.com/D68914
dom/base/DocumentOrShadowRoot.cpp
dom/base/DocumentOrShadowRoot.h
dom/base/nsDOMWindowUtils.cpp
dom/events/ContentEventHandler.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/dom/base/DocumentOrShadowRoot.cpp
+++ b/dom/base/DocumentOrShadowRoot.cpp
@@ -452,43 +452,51 @@ static void QueryNodesFromPoint(Document
   nsPoint pt(x, y);
   QueryNodesFromRect(aRoot, nsRect(pt, nsSize(1, 1)), aOptions,
                      aShouldFlushLayout, aMultiple, aNodes);
 }
 
 }  // namespace
 
 Element* DocumentOrShadowRoot::ElementFromPoint(float aX, float aY) {
-  return ElementFromPointHelper(aX, aY, false, true);
+  return ElementFromPointHelper(aX, aY, false, true, true);
 }
 
 void DocumentOrShadowRoot::ElementsFromPoint(
     float aX, float aY, nsTArray<RefPtr<Element>>& aElements) {
-  QueryNodesFromPoint(*this, aX, aY, {}, FlushLayout::Yes, Multiple::Yes,
-                      aElements);
+  QueryNodesFromPoint(*this, aX, aY,
+                      FrameForPointOption::IsRelativeToLayoutViewport,
+                      FlushLayout::Yes, Multiple::Yes, aElements);
 }
 
 void DocumentOrShadowRoot::NodesFromPoint(float aX, float aY,
                                           nsTArray<RefPtr<nsINode>>& aNodes) {
-  QueryNodesFromPoint(*this, aX, aY, {}, FlushLayout::Yes, Multiple::Yes,
-                      aNodes);
+  QueryNodesFromPoint(*this, aX, aY,
+                      FrameForPointOption::IsRelativeToLayoutViewport,
+                      FlushLayout::Yes, Multiple::Yes, aNodes);
 }
 
 nsINode* DocumentOrShadowRoot::NodeFromPoint(float aX, float aY) {
   AutoTArray<RefPtr<nsINode>, 1> nodes;
-  QueryNodesFromPoint(*this, aX, aY, {}, FlushLayout::Yes, Multiple::No, nodes);
+  QueryNodesFromPoint(*this, aX, aY,
+                      FrameForPointOption::IsRelativeToLayoutViewport,
+                      FlushLayout::Yes, Multiple::No, nodes);
   return nodes.SafeElementAt(0);
 }
 
 Element* DocumentOrShadowRoot::ElementFromPointHelper(
-    float aX, float aY, bool aIgnoreRootScrollFrame, bool aFlushLayout) {
+    float aX, float aY, bool aIgnoreRootScrollFrame, bool aFlushLayout,
+    bool aIsRelativeToLayoutViewport) {
   EnumSet<FrameForPointOption> options;
   if (aIgnoreRootScrollFrame) {
     options += FrameForPointOption::IgnoreRootScrollFrame;
   }
+  if (aIsRelativeToLayoutViewport) {
+    options += FrameForPointOption::IsRelativeToLayoutViewport;
+  }
 
   auto flush = aFlushLayout ? FlushLayout::Yes : FlushLayout::No;
 
   AutoTArray<RefPtr<Element>, 1> elements;
   QueryNodesFromPoint(*this, aX, aY, options, flush, Multiple::No, elements);
   return elements.SafeElementAt(0);
 }
 
--- a/dom/base/DocumentOrShadowRoot.h
+++ b/dom/base/DocumentOrShadowRoot.h
@@ -130,17 +130,18 @@ class DocumentOrShadowRoot {
   /**
    * Helper for elementFromPoint implementation that allows
    * ignoring the scroll frame and/or avoiding layout flushes.
    *
    * @see nsIDOMWindowUtils::elementFromPoint
    */
   Element* ElementFromPointHelper(float aX, float aY,
                                   bool aIgnoreRootScrollFrame,
-                                  bool aFlushLayout);
+                                  bool aFlushLayout,
+                                  bool aIsRelativeToLayoutViewport);
 
   void NodesFromRect(float aX, float aY, float aTopSize, float aRightSize,
                      float aBottomSize, float aLeftSize,
                      bool aIgnoreRootScrollFrame, bool aFlushLayout,
                      bool aOnlyVisible, nsTArray<RefPtr<nsINode>>&);
 
   /**
    * This gets fired when the element that an id refers to changes.
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1150,18 +1150,18 @@ nsDOMWindowUtils::SendSimpleGestureEvent
 
 NS_IMETHODIMP
 nsDOMWindowUtils::ElementFromPoint(float aX, float aY,
                                    bool aIgnoreRootScrollFrame,
                                    bool aFlushLayout, Element** aReturn) {
   nsCOMPtr<Document> doc = GetDocument();
   NS_ENSURE_STATE(doc);
 
-  RefPtr<Element> el =
-      doc->ElementFromPointHelper(aX, aY, aIgnoreRootScrollFrame, aFlushLayout);
+  RefPtr<Element> el = doc->ElementFromPointHelper(
+      aX, aY, aIgnoreRootScrollFrame, aFlushLayout, false);
   el.forget(aReturn);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::NodesFromRect(float aX, float aY, float aTopSize,
                                 float aRightSize, float aBottomSize,
                                 float aLeftSize, bool aIgnoreRootScrollFrame,
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -2643,17 +2643,17 @@ nsresult ContentEventHandler::OnQueryDOM
   CSSIntRect docFrameRect = docFrame->GetScreenRect();
   CSSIntPoint eventLocCSS(
       docFrame->PresContext()->DevPixelsToIntCSSPixels(eventLoc.x) -
           docFrameRect.x,
       docFrame->PresContext()->DevPixelsToIntCSSPixels(eventLoc.y) -
           docFrameRect.y);
 
   Element* contentUnderMouse = mDocument->ElementFromPointHelper(
-      eventLocCSS.x, eventLocCSS.y, false, false);
+      eventLocCSS.x, eventLocCSS.y, false, false, false);
   if (contentUnderMouse) {
     nsIWidget* targetWidget = nullptr;
     nsIFrame* targetFrame = contentUnderMouse->GetPrimaryFrame();
     nsIObjectFrame* pluginFrame = do_QueryFrame(targetFrame);
     if (pluginFrame) {
       targetWidget = pluginFrame->GetWidget();
     } else if (targetFrame) {
       targetWidget = targetFrame->GetNearestWidget();
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3179,16 +3179,19 @@ nsresult nsLayoutUtils::GetFramesForArea
     builder.IgnorePaintSuppression();
   }
   if (aOptions.contains(FrameForPointOption::IgnoreRootScrollFrame)) {
     nsIFrame* rootScrollFrame = aFrame->PresShell()->GetRootScrollFrame();
     if (rootScrollFrame) {
       builder.SetIgnoreScrollFrame(rootScrollFrame);
     }
   }
+  if (aOptions.contains(FrameForPointOption::IsRelativeToLayoutViewport)) {
+    builder.SetIsRelativeToLayoutViewport();
+  }
   if (aOptions.contains(FrameForPointOption::IgnoreCrossDoc)) {
     builder.SetDescendIntoSubdocuments(false);
   }
 
   builder.SetHitTestIsForVisibility(
       aOptions.contains(FrameForPointOption::OnlyVisible));
 
   builder.EnterPresShell(frame);
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -867,16 +867,22 @@ class nsLayoutUtils {
     /**
      * When set, return only content in the same document as aFrame.
      */
     IgnoreCrossDoc,
     /**
      * When set, return only content that is actually visible.
      */
     OnlyVisible,
+    /**
+     * When set, coordinates are interpreted as being relative to the layout
+     * viewport. When not set, coordinates are interpreted as being relative
+     * to the visual viewport.
+     */
+    IsRelativeToLayoutViewport,
   };
 
   /**
    * Given aFrame, the root frame of a stacking context, find its descendant
    * frame under the point aPt that receives a mouse event at that location,
    * or nullptr if there is no such frame.
    * @param aPt the point, relative to the frame origin
    * @param aFlags some combination of FrameForPointOption.
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -1223,16 +1223,17 @@ nsDisplayListBuilder::nsDisplayListBuild
       mHitTestIsForVisibility(false),
       mIsBuilding(false),
       mInInvalidSubtree(false),
       mDisablePartialUpdates(false),
       mPartialBuildFailed(false),
       mIsInActiveDocShell(false),
       mBuildAsyncZoomContainer(false),
       mContainsBackdropFilter(false),
+      mIsRelativeToLayoutViewport(false),
       mHitTestArea(),
       mHitTestInfo(CompositorHitTestInvisibleToHit) {
   MOZ_COUNT_CTOR(nsDisplayListBuilder);
 
   mBuildCompositorHitTestInfo = mAsyncPanZoomEnabled && IsForPainting();
 
   ShouldRebuildDisplayListDueToPrefChange();
 
@@ -1445,19 +1446,25 @@ AnimatedGeometryRoot* nsDisplayListBuild
         aItem->Frame(), LayoutFrameType::Viewport, RootReferenceFrame());
     if (viewportFrame) {
       return FindAnimatedGeometryRootFor(viewportFrame);
     }
   }
   return FindAnimatedGeometryRootFor(aItem->Frame());
 }
 
+void nsDisplayListBuilder::SetIsRelativeToLayoutViewport() {
+  mIsRelativeToLayoutViewport = true;
+  UpdateShouldBuildAsyncZoomContainer();
+}
+
 void nsDisplayListBuilder::UpdateShouldBuildAsyncZoomContainer() {
   Document* document = mReferenceFrame->PresContext()->Document();
-  mBuildAsyncZoomContainer = nsLayoutUtils::AllowZoomingForDocument(document);
+  mBuildAsyncZoomContainer = !mIsRelativeToLayoutViewport &&
+                             nsLayoutUtils::AllowZoomingForDocument(document);
 }
 
 // Certain prefs may cause display list items to be added or removed when they
 // are toggled. In those cases, we need to fully rebuild the display list.
 bool nsDisplayListBuilder::ShouldRebuildDisplayListDueToPrefChange() {
   // If we transition between wrapping the RCD-RSF contents into an async
   // zoom container vs. not, we need to rebuild the display list. This only
   // happens when the zooming or container scrolling prefs are toggled
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -580,16 +580,20 @@ class nsDisplayListBuilder {
    * this to allow RenderOffscreen to render a whole document without beign
    * clipped by the viewport or drawing the viewport scrollbars.
    */
   void SetIgnoreScrollFrame(nsIFrame* aFrame) { mIgnoreScrollFrame = aFrame; }
   /**
    * Get the scrollframe to ignore, if any.
    */
   nsIFrame* GetIgnoreScrollFrame() { return mIgnoreScrollFrame; }
+  void SetIsRelativeToLayoutViewport();
+  bool IsRelativeToLayoutViewport() const {
+    return mIsRelativeToLayoutViewport;
+  }
   /**
    * Get the ViewID of the nearest scrolling ancestor frame.
    */
   ViewID GetCurrentScrollParentId() const { return mCurrentScrollParentId; }
   /**
    * Get and set the flag that indicates if scroll parents should have layers
    * forcibly created. This flag is set when a deeply nested scrollframe has
    * a displayport, and for scroll handoff to work properly the ancestor
@@ -2025,16 +2029,17 @@ class nsDisplayListBuilder {
   bool mIsBuilding;
   bool mInInvalidSubtree;
   bool mBuildCompositorHitTestInfo;
   bool mDisablePartialUpdates;
   bool mPartialBuildFailed;
   bool mIsInActiveDocShell;
   bool mBuildAsyncZoomContainer;
   bool mContainsBackdropFilter;
+  bool mIsRelativeToLayoutViewport;
 
   nsRect mHitTestArea;
   CompositorHitTestInfo mHitTestInfo;
 };
 
 class nsDisplayItem;
 class nsDisplayItemBase;
 class nsPaintedDisplayItem;