Bug 1466208 - part 14: Create PresShell::EventHandler::ComputeRootFrameToHandleEvent() r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 08 Feb 2019 07:11:01 +0000
changeset 516120 546288d07c7c9fab23afbae369977d911e3e8f2d
parent 516119 37fc40cdf4ed3866963d83f00d41c62a4210b05c
child 516121 b482c6618d72ac38a9a82fbccf425e0a7f8b6129
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1466208
milestone67.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 1466208 - part 14: Create PresShell::EventHandler::ComputeRootFrameToHandleEvent() r=smaug In some reasons, handling event should be handled in specific frame even if the coordinates are out of the frame. PresShell::EventHandler::HandleEvent() computes it with popups, capturing content, etc. This patch moves the blocks into new method for making HandleEvent() simpler. Note that most of the code is just moved. The following patch will clean it up. Differential Revision: https://phabricator.services.mozilla.com/D18523
layout/base/PresShell.cpp
layout/base/PresShell.h
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -6516,91 +6516,24 @@ nsresult PresShell::EventHandler::Handle
       Document::UnlockPointer();
     }
 
     nsIFrame* frameForPresShell = MaybeFlushThrottledStyles(aFrame);
     if (NS_WARN_IF(!frameForPresShell)) {
       return NS_OK;
     }
 
-    nsPresContext* framePresContext = frameForPresShell->PresContext();
-    nsPresContext* rootPresContext = framePresContext->GetRootPresContext();
-    NS_ASSERTION(rootPresContext == GetPresContext()->GetRootPresContext(),
-                 "How did we end up outside the connected "
-                 "prescontext/viewmanager hierarchy?");
-    nsIFrame* popupFrame = nsLayoutUtils::GetPopupFrameForEventCoordinates(
-        rootPresContext, aGUIEvent);
-    // If a remote browser is currently capturing input break out if we
-    // detect a chrome generated popup.
-    if (popupFrame && capturingContent &&
-        EventStateManager::IsRemoteTarget(capturingContent)) {
+    bool isCapturingContentIgnored = false;
+    bool isCaptureRetargeted = false;
+    nsIFrame* rootFrameToHandleEvent = ComputeRootFrameToHandleEvent(
+        frameForPresShell, aGUIEvent, capturingContent,
+        &isCapturingContentIgnored, &isCaptureRetargeted);
+    if (isCapturingContentIgnored) {
       capturingContent = nullptr;
     }
-    // If the popupFrame is an ancestor of the 'frame', the frame should
-    // handle the event, otherwise, the popup should handle it.
-    nsIFrame* rootFrameToHandleEvent = frameForPresShell;
-    if (popupFrame && !nsContentUtils::ContentIsCrossDocDescendantOf(
-                          framePresContext->GetPresShell()->GetDocument(),
-                          popupFrame->GetContent())) {
-      // If we aren't starting our event dispatch from the root frame of the
-      // root prescontext, then someone must be capturing the mouse. In that
-      // case we only want to use the popup list if the capture is
-      // inside the popup.
-      if (framePresContext == rootPresContext &&
-          frameForPresShell == FrameConstructor()->GetRootFrame()) {
-        rootFrameToHandleEvent = popupFrame;
-      } else if (capturingContent &&
-                 nsContentUtils::ContentIsDescendantOf(
-                     capturingContent, popupFrame->GetContent())) {
-        rootFrameToHandleEvent = popupFrame;
-      }
-    }
-
-    bool captureRetarget = false;
-    if (capturingContent) {
-      // If a capture is active, determine if the docshell is visible. If not,
-      // clear the capture and target the mouse event normally instead. This
-      // would occur if the mouse button is held down while a tab change occurs.
-      // If the docshell is visible, look for a scrolling container.
-      bool vis;
-      nsCOMPtr<nsIBaseWindow> baseWin =
-          do_QueryInterface(GetPresContext()->GetContainerWeak());
-      if (baseWin && NS_SUCCEEDED(baseWin->GetVisibility(&vis)) && vis) {
-        captureRetarget = gCaptureInfo.mRetargetToElement;
-        if (!captureRetarget) {
-          // A check was already done above to ensure that capturingContent is
-          // in this presshell.
-          NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(),
-                       "Unexpected document");
-          nsIFrame* captureFrame = capturingContent->GetPrimaryFrame();
-          if (captureFrame) {
-            if (capturingContent->IsHTMLElement(nsGkAtoms::select)) {
-              // a dropdown <select> has a child in its selectPopupList and we
-              // should capture on that instead.
-              nsIFrame* childFrame =
-                  captureFrame->GetChildList(nsIFrame::kSelectPopupList)
-                      .FirstChild();
-              if (childFrame) {
-                captureFrame = childFrame;
-              }
-            }
-
-            // scrollable frames should use the scrolling container as
-            // the root instead of the document
-            nsIScrollableFrame* scrollFrame = do_QueryFrame(captureFrame);
-            if (scrollFrame) {
-              rootFrameToHandleEvent = scrollFrame->GetScrolledFrame();
-            }
-          }
-        }
-      } else {
-        ClearMouseCapture(nullptr);
-        capturingContent = nullptr;
-      }
-    }
 
     // The order to generate pointer event is
     // 1. check pending pointer capture.
     // 2. check if there is a capturing content.
     // 3. hit test
     // 4. dispatch pointer events
     // 5. check whether the targets of all Touch instances are in the same
     //    document and suppress invalid instances.
@@ -6657,17 +6590,17 @@ nsresult PresShell::EventHandler::Handle
         (mouseEvent && mouseEvent->mExitFrom == WidgetMouseEvent::eTopLevel);
 
     // Get the frame at the event point. However, don't do this if we're
     // capturing and retargeting the event because the captured frame will
     // be used instead below. Also keep using the root frame if we're dealing
     // with a window-level mouse exit event since we want to start sending
     // mouse out events at the root EventStateManager.
     nsIFrame* frameToHandleEvent = rootFrameToHandleEvent;
-    if (!captureRetarget && !isWindowLevelMouseExit &&
+    if (!isCaptureRetargeted && !isWindowLevelMouseExit &&
         !pointerCapturingContent) {
       if (aGUIEvent->mClass == eTouchEventClass) {
         frameToHandleEvent = TouchManager::SetupTarget(
             aGUIEvent->AsTouchEvent(), rootFrameToHandleEvent);
       } else {
         uint32_t flags = 0;
         nsPoint eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(
             aGUIEvent, rootFrameToHandleEvent);
@@ -7289,16 +7222,108 @@ nsIFrame* PresShell::EventHandler::Maybe
 
   if (weakFrameForPresShell.IsAlive()) {
     return aFrameForPresShell;
   }
 
   return GetNearestFrameContainingPresShell(mPresShell);
 }
 
+nsIFrame* PresShell::EventHandler::ComputeRootFrameToHandleEvent(
+    nsIFrame* aFrameForPresShell, WidgetGUIEvent* aGUIEvent,
+    nsIContent* aCapturingContent, bool* aIsCapturingContentIgnored,
+    bool* aIsCaptureRetargeted) {
+  MOZ_ASSERT(aFrameForPresShell);
+  MOZ_ASSERT(aGUIEvent);
+  MOZ_ASSERT(aIsCapturingContentIgnored);
+  MOZ_ASSERT(aIsCaptureRetargeted);
+
+  nsIContent* capturingContent = aCapturingContent;
+  *aIsCapturingContentIgnored = false;
+  *aIsCaptureRetargeted = false;
+
+  nsPresContext* framePresContext = aFrameForPresShell->PresContext();
+  nsPresContext* rootPresContext = framePresContext->GetRootPresContext();
+  NS_ASSERTION(rootPresContext == GetPresContext()->GetRootPresContext(),
+               "How did we end up outside the connected "
+               "prescontext/viewmanager hierarchy?");
+  nsIFrame* popupFrame = nsLayoutUtils::GetPopupFrameForEventCoordinates(
+      rootPresContext, aGUIEvent);
+  // If a remote browser is currently capturing input break out if we
+  // detect a chrome generated popup.
+  if (popupFrame && aCapturingContent &&
+      EventStateManager::IsRemoteTarget(aCapturingContent)) {
+    *aIsCapturingContentIgnored = true;
+    capturingContent = nullptr;
+  }
+  // If the popupFrame is an ancestor of the 'frame', the frame should
+  // handle the event, otherwise, the popup should handle it.
+  nsIFrame* rootFrameToHandleEvent = aFrameForPresShell;
+  if (popupFrame && !nsContentUtils::ContentIsCrossDocDescendantOf(
+                        framePresContext->GetPresShell()->GetDocument(),
+                        popupFrame->GetContent())) {
+    // If we aren't starting our event dispatch from the root frame of the
+    // root prescontext, then someone must be capturing the mouse. In that
+    // case we only want to use the popup list if the capture is
+    // inside the popup.
+    if (framePresContext == rootPresContext &&
+        aFrameForPresShell == FrameConstructor()->GetRootFrame()) {
+      rootFrameToHandleEvent = popupFrame;
+    } else if (capturingContent &&
+               nsContentUtils::ContentIsDescendantOf(
+                   capturingContent, popupFrame->GetContent())) {
+      rootFrameToHandleEvent = popupFrame;
+    }
+  }
+
+  if (capturingContent) {
+    // If a capture is active, determine if the docshell is visible. If not,
+    // clear the capture and target the mouse event normally instead. This
+    // would occur if the mouse button is held down while a tab change occurs.
+    // If the docshell is visible, look for a scrolling container.
+    bool vis;
+    nsCOMPtr<nsIBaseWindow> baseWin =
+        do_QueryInterface(GetPresContext()->GetContainerWeak());
+    if (baseWin && NS_SUCCEEDED(baseWin->GetVisibility(&vis)) && vis) {
+      *aIsCaptureRetargeted = gCaptureInfo.mRetargetToElement;
+      if (!*aIsCaptureRetargeted) {
+        // A check was already done above to ensure that capturingContent is
+        // in this presshell.
+        NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(),
+                     "Unexpected document");
+        nsIFrame* captureFrame = capturingContent->GetPrimaryFrame();
+        if (captureFrame) {
+          if (capturingContent->IsHTMLElement(nsGkAtoms::select)) {
+            // a dropdown <select> has a child in its selectPopupList and we
+            // should capture on that instead.
+            nsIFrame* childFrame =
+                captureFrame->GetChildList(nsIFrame::kSelectPopupList)
+                    .FirstChild();
+            if (childFrame) {
+              captureFrame = childFrame;
+            }
+          }
+
+          // scrollable frames should use the scrolling container as
+          // the root instead of the document
+          nsIScrollableFrame* scrollFrame = do_QueryFrame(captureFrame);
+          if (scrollFrame) {
+            rootFrameToHandleEvent = scrollFrame->GetScrolledFrame();
+          }
+        }
+      }
+    } else {
+      ClearMouseCapture(nullptr);
+      capturingContent = nullptr;
+      *aIsCapturingContentIgnored = true;
+    }
+  }
+  return rootFrameToHandleEvent;
+}
+
 Document* PresShell::GetPrimaryContentDocument() {
   nsPresContext* context = GetPresContext();
   if (!context || !context->IsRoot()) {
     return nullptr;
   }
 
   nsCOMPtr<nsIDocShellTreeItem> shellAsTreeItem = context->GetDocShell();
   if (!shellAsTreeItem) {
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -694,16 +694,40 @@ class PresShell final : public nsIPresSh
      *                                  If aFrameForPresShell is not nullptr
      *                                  and hasn't been destroyed, returns
      *                                  aFrameForPresShell as-is.
      */
     MOZ_CAN_RUN_SCRIPT
     nsIFrame* MaybeFlushThrottledStyles(nsIFrame* aFrameForPresShell);
 
     /**
+     * ComputeRootFrameToHandleEvent() returns root frame to handle the event.
+     * For example, if there is a popup, this returns the popup frame.
+     * If there is capturing content and it's in a scrolled frame, returns
+     * the scrolled frame.
+     *
+     * @param aFrameForPresShell                The frame for mPresShell.
+     * @param aGUIEvent                         The handling event.
+     * @param aCapturingContent                 Capturing content if there is.
+     *                                          nullptr, otherwise.
+     * @param aIsCapturingContentIgnored        [out] true if aCapturingContent
+     *                                          is not nullptr but it should be
+     *                                          ignored to handle the event.
+     * @param aIsCaptureRetargeted              [out] true if aCapturingContent
+     *                                          is not nullptr but it's
+     *                                          retargeted.
+     * @return                                  Root frame to handle the event.
+     */
+    nsIFrame* ComputeRootFrameToHandleEvent(nsIFrame* aFrameForPresShell,
+                                            WidgetGUIEvent* aGUIEvent,
+                                            nsIContent* aCapturingContent,
+                                            bool* aIsCapturingContentIgnored,
+                                            bool* aIsCaptureRetargeted);
+
+    /**
      * XXX Needs better name.
      * HandleEventInternal() dispatches aEvent into the DOM tree and
      * notify EventStateManager of that.
      *
      * @param aEvent                    Event to be dispatched.
      * @param aEventStatus              [in/out] EventStatus of aEvent.
      * @param aIsHandlingNativeEvent    true if aGUIEvent represents a native
      *                                  event.