Bug 1466208 - part 7: Create PresShell::EventHandler::GetFrameForHandlingEventWith() to retrieve a frame which is necessary to handle event with another PresShell instance r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 01 Feb 2019 02:15:54 +0000
changeset 456385 e7930893f8f0c64d1bbad3d87f9c397ad9eb7fd0
parent 456384 58fe5a3d3c403199b9ff87d2f5051fd6e0564a45
child 456386 36d845cdb7f0c001f0a8c38e87a41f8bceb71b3a
push id19
push usermdeboer@mozilla.com
push dateFri, 01 Feb 2019 10:05:45 +0000
reviewerssmaug
bugs1466208
milestone67.0a1
Bug 1466208 - part 7: Create PresShell::EventHandler::GetFrameForHandlingEventWith() to retrieve a frame which is necessary to handle event with another PresShell instance r=smaug Next, we need to look for a frame for first parameter of calling PresShell::HandleEvent() of another PresShell instance. This patch creates PresShell::EventHandler::GetFrameForHandlingEventWith() to do it. Unfortunately, the result is used in 3 patterns. One is, the caller should stop handling the event. Another one is, the caller should keep handling the event by itself. The other is, the caller should call PresShell::HandleEvent() of different PresShell instance. Therefore, this patch makes the method take aFrame of the caller. Then, the caller can check the last 2 patterns with check the result is same as aFrame. This is not so smart approach, but I have no better idea without adding a bool argument or making the return type bool and adding out argument of nsIFrame. Differential Revision: https://phabricator.services.mozilla.com/D16957
layout/base/PresShell.cpp
layout/base/PresShell.h
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -6523,46 +6523,22 @@ nsresult PresShell::EventHandler::Handle
   if (!aDontRetargetEvents) {
     RefPtr<Document> retargetEventDoc;
     if (!GetRetargetEventDocument(aGUIEvent,
                                   getter_AddRefs(retargetEventDoc))) {
       return NS_OK;  // Not need to return error.
     }
 
     if (retargetEventDoc) {
-      nsCOMPtr<nsIPresShell> presShell = retargetEventDoc->GetShell();
-      // Even if the document doesn't have PresShell, i.e., it's invisible, we
-      // need to dispatch only KeyboardEvent in its nearest visible document
-      // because key focus shouldn't be caught by invisible document.
-      if (!presShell) {
-        if (!aGUIEvent->HasKeyEventMessage()) {
-          return NS_OK;
-        }
-        while (!presShell) {
-          retargetEventDoc = retargetEventDoc->GetParentDocument();
-          if (!retargetEventDoc) {
-            return NS_OK;
-          }
-          presShell = retargetEventDoc->GetShell();
-        }
-      }
-
-      if (presShell != mPresShell) {
-        nsIFrame* frame = presShell->GetRootFrame();
-        if (!frame) {
-          if (aGUIEvent->mMessage == eQueryTextContent ||
-              aGUIEvent->IsContentCommandEvent()) {
-            return NS_OK;
-          }
-
-          frame = GetNearestFrameContainingPresShell(presShell);
-        }
-
-        if (!frame) return NS_OK;
-
+      nsIFrame* frame =
+          GetFrameForHandlingEventWith(aGUIEvent, retargetEventDoc, aFrame);
+      if (!frame) {
+        return NS_OK;  // Not need to return error.
+      }
+      if (frame != aFrame) {
         nsCOMPtr<nsIPresShell> shell = frame->PresContext()->GetPresShell();
         return shell->HandleEvent(frame, aGUIEvent, true, aEventStatus);
       }
     }
   }
 
   if (aGUIEvent->mClass == eKeyboardEventClass && GetDocument() &&
       GetDocument()->EventHandlingSuppressed()) {
@@ -7191,16 +7167,56 @@ bool PresShell::EventHandler::GetRetarge
   }
 #endif  // #ifdef ANDROID
 
   // When we don't find another document to handle the event, we need to keep
   // handling the event by ourselves.
   return true;
 }
 
+nsIFrame* PresShell::EventHandler::GetFrameForHandlingEventWith(
+    WidgetGUIEvent* aGUIEvent, Document* aRetargetDocument,
+    nsIFrame* aFrameForPresShell) {
+  MOZ_ASSERT(aGUIEvent);
+  MOZ_ASSERT(aRetargetDocument);
+
+  nsCOMPtr<nsIPresShell> presShell = aRetargetDocument->GetShell();
+  // Even if the document doesn't have PresShell, i.e., it's invisible, we
+  // need to dispatch only KeyboardEvent in its nearest visible document
+  // because key focus shouldn't be caught by invisible document.
+  if (!presShell) {
+    if (!aGUIEvent->HasKeyEventMessage()) {
+      return nullptr;
+    }
+    Document* retargetEventDoc = aRetargetDocument;
+    while (!presShell) {
+      retargetEventDoc = retargetEventDoc->GetParentDocument();
+      if (!retargetEventDoc) {
+        return nullptr;
+      }
+      presShell = retargetEventDoc->GetShell();
+    }
+  }
+
+  if (presShell != mPresShell) {
+    nsIFrame* frame = presShell->GetRootFrame();
+    if (!frame) {
+      if (aGUIEvent->mMessage == eQueryTextContent ||
+          aGUIEvent->IsContentCommandEvent()) {
+        return nullptr;
+      }
+
+      frame = GetNearestFrameContainingPresShell(presShell);
+    }
+
+    return frame;
+  }
+  return aFrameForPresShell;
+}
+
 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
@@ -587,16 +587,40 @@ class PresShell final : public nsIPresSh
      * @param aGUIEvent                 Handling event.
      * @param aRetargetEventDocument    Document which should handle aGUIEvent.
      * @return                          true if caller can keep handling
      *                                  aGUIEvent.
      */
     bool GetRetargetEventDocument(WidgetGUIEvent* aGUIEvent,
                                   Document** aRetargetEventDocument);
 
+    /**
+     * GetFrameForHandlingEventWith() returns a frame which should be used as
+     * aFrame of HandleEvent().  See @return for the detail.
+     *
+     * @param aGUIEvent                 Handling event.
+     * @param aRetargetDocument         Document which aGUIEvent should be
+     *                                  fired on.  Typically, should be result
+     *                                  of GetRetargetEventDocument().
+     * @param aFrameForPresShell        The frame if we need to handle the
+     *                                  event with current instance.  I.e.,
+     *                                  typically, caller sets aFrame of
+     *                                  HandleEvent().
+     * @return                          nullptr if caller should stop handling
+     *                                  the event.
+     *                                  aFrameForPresShell if caller should
+     *                                  keep handling the event by itself.
+     *                                  Otherwise, caller should handle it with
+     *                                  another PresShell which is result of
+     *                                  nsIFrame::PresContext()->GetPresShell().
+     */
+    nsIFrame* GetFrameForHandlingEventWith(WidgetGUIEvent* aGUIEvent,
+                                           Document* aRetargetDocument,
+                                           nsIFrame* aFrameForPresShell);
+
     MOZ_CAN_RUN_SCRIPT
     nsresult RetargetEventToParent(WidgetGUIEvent* aGUIEvent,
                                    nsEventStatus* aEventStatus);
 
     /**
      * MaybeHandleEventWithAccessibleCaret() may handle aGUIEvent with
      * AccessibleCaretEventHub if it's necessary.
      *