Bug 1321472, when the capturing content is inside a popup, use the popup as the root frame when searching for a mouse target rather than the root frame, otherwise the capturing content's frame won't be found, r=smaug
authorNeil Deakin <neil@mozilla.com>
Thu, 19 Jan 2017 10:04:04 -0500
changeset 377425 86f0daf456830dd8a4d60724d7f9821ecd7bbcf9
parent 377424 5a03c87a17259a2b78ecfb207246b7b04838545e
child 377426 8a0dc12ec71fca672ed3f33939a9cf0e2284c99d
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1321472
milestone53.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 1321472, when the capturing content is inside a popup, use the popup as the root frame when searching for a mouse target rather than the root frame, otherwise the capturing content's frame won't be found, r=smaug
layout/base/PresShell.cpp
toolkit/content/tests/chrome/chrome.ini
toolkit/content/tests/chrome/test_menu_withcapture.xul
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -7252,35 +7252,41 @@ PresShell::HandleEvent(nsIFrame* aFrame,
       NS_WARNING("Nothing to handle this event!");
       return NS_OK;
     }
 
     nsPresContext* framePresContext = frame->PresContext();
     nsPresContext* rootPresContext = framePresContext->GetRootPresContext();
     NS_ASSERTION(rootPresContext == mPresContext->GetRootPresContext(),
                  "How did we end up outside the connected prescontext/viewmanager hierarchy?");
-    // 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 don't want to search the popup
-    // list.
-    if (framePresContext == rootPresContext &&
-        frame == mFrameConstructor->GetRootFrame()) {
-      nsIFrame* popupFrame =
-        nsLayoutUtils::GetPopupFrameForEventCoordinates(rootPresContext, aEvent);
-      // If a remote browser is currently capturing input break out if we
-      // detect a chrome generated popup.
-      if (popupFrame && capturingContent &&
-          EventStateManager::IsRemoteTarget(capturingContent)) {
-        capturingContent = nullptr;
-      }
-      // If the popupFrame is an ancestor of the 'frame', the frame should
-      // handle the event, otherwise, the popup should handle it.
-      if (popupFrame &&
-          !nsContentUtils::ContentIsCrossDocDescendantOf(
-             framePresContext->GetPresShell()->GetDocument(),
-             popupFrame->GetContent())) {
+    nsIFrame* popupFrame =
+      nsLayoutUtils::GetPopupFrameForEventCoordinates(rootPresContext, aEvent);
+    // If a remote browser is currently capturing input break out if we
+    // detect a chrome generated popup.
+    if (popupFrame && capturingContent &&
+        EventStateManager::IsRemoteTarget(capturingContent)) {
+      capturingContent = nullptr;
+    }
+    // If the popupFrame is an ancestor of the 'frame', the frame should
+    // handle the event, otherwise, the popup should handle it.
+    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 &&
+          frame == mFrameConstructor->GetRootFrame()) {
+        frame = popupFrame;
+      } else if (capturingContent &&
+                 nsContentUtils::ContentIsDescendantOf(
+                   capturingContent, popupFrame->GetContent())) {
         frame = 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
--- a/toolkit/content/tests/chrome/chrome.ini
+++ b/toolkit/content/tests/chrome/chrome.ini
@@ -107,16 +107,17 @@ subsuite = clipboard
 [test_hiddenitems.xul]
 [test_hiddenpaging.xul]
 [test_keys.xul]
 [test_labelcontrol.xul]
 [test_largemenu.xul]
 skip-if = os == 'linux' && !debug #Bug 1207174
 [test_menu.xul]
 [test_menu_anchored.xul]
+[test_menu_withcapture.xul]
 [test_menu_hide.xul]
 [test_menuchecks.xul]
 [test_menuitem_blink.xul]
 [test_menuitem_commands.xul]
 [test_menulist.xul]
 [test_menulist_keynav.xul]
 [test_menulist_null_value.xul]
 [test_menulist_paging.xul]
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menu_withcapture.xul
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="Menu with Mouse Capture"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>      
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>      
+
+  <menulist id="menulist">
+    <menupopup onpopupshown="shown(this)" onpopuphidden="done();">
+      <menuitem id="menuitem" label="Menu Item"
+                onmousemove="moveHappened = true;"
+                onmouseup="upHappened = true;"/>
+    </menupopup>
+  </menulist>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(startTest);
+
+let moveHappened = false, upHappened = false;
+
+function startTest() {
+  disableNonTestMouseEvents(true);
+  document.getElementById("menulist"). open = true;
+}
+
+function shown(popup)
+{
+  popup.setCaptureAlways();
+  synthesizeMouseAtCenter(document.getElementById("menuitem"), { type: "mousemove" });
+  synthesizeMouseAtCenter(document.getElementById("menuitem"), { type: "mouseup" });
+}
+
+function done()
+{
+  ok(moveHappened, "mousemove happened");
+  ok(upHappened, "mouseup happened");
+  disableNonTestMouseEvents(false);
+  SimpleTest.finish();
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>