Bug 1638806 - Do not update sLastMouseRemoteTarget for eMouseExitFromWidget event; r=smaug
authorEdgar Chen <echen@mozilla.com>
Fri, 22 May 2020 20:12:25 +0000
changeset 531738 56423aee609ec894e9d7e1077d5cdb3751891376
parent 531737 8f9d7916be0157d299f1b88a4a09ae8fbff334b3
child 531739 03d09cb05213745b92d6c4afb51d168ada95df4e
push id37442
push userncsoregi@mozilla.com
push dateSat, 23 May 2020 09:21:24 +0000
treeherdermozilla-central@bbcc193fe0f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1638806
milestone78.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 1638806 - Do not update sLastMouseRemoteTarget for eMouseExitFromWidget event; r=smaug Firing eMouseExitFromWidget means we are leaving a specific remote target, then we should not update sLastMouseRemoteTarget. Otherwise the subsequent event might trigger sending eMouseExitFromWidget again. Differential Revision: https://phabricator.services.mozilla.com/D75916
dom/events/test/browser.ini
dom/events/test/browser_mouse_enterleave_switch_tab.js
dom/ipc/BrowserParent.cpp
--- a/dom/events/test/browser.ini
+++ b/dom/events/test/browser.ini
@@ -1,10 +1,14 @@
 [DEFAULT]
 
 [browser_beforeinput_by_execCommand_in_contentscript.js]
 support-files =
   file_beforeinput_by_execCommand_in_contentscript.html
   ../../../browser/base/content/test/general/head.js
 
 [browser_bug1539497.js]
+[browser_mouse_enterleave_switch_tab.js]
+support-files =
+  ../../../browser/base/content/test/general/dummy_page.html
+
 [browser_shortcutkey_modifier_conflicts_with_content_accesskey_modifier.js]
 skip-if = os != 'linux' && os != 'win' // Alt + D is defined only on Linux and Windows
new file mode 100644
--- /dev/null
+++ b/dom/events/test/browser_mouse_enterleave_switch_tab.js
@@ -0,0 +1,64 @@
+"use strict";
+
+function AddMouseEventListener(aBrowser) {
+  return SpecialPowers.spawn(aBrowser, [], () => {
+    content.catchedEvents = [];
+    let listener = function(aEvent) {
+      content.catchedEvents.push(aEvent.type);
+    };
+
+    let target = content.document.querySelector("p");
+    target.onmouseenter = listener;
+    target.onmouseleave = listener;
+  });
+}
+
+function clearMouseEventListenerAndCheck(aBrowser, aExpectedEvents) {
+  return SpecialPowers.spawn(aBrowser, [aExpectedEvents], events => {
+    let target = content.document.querySelector("p");
+    target.onmouseenter = null;
+    target.onmouseleave = null;
+
+    Assert.deepEqual(content.catchedEvents, events);
+  });
+}
+
+add_task(async function testSwitchTabs() {
+  const tabFirst = await BrowserTestUtils.openNewForegroundTab(
+    gBrowser,
+    "http://example.com/browser/browser/base/content/test/general/dummy_page.html",
+    true
+  );
+
+  info("Initial mouse move");
+  await EventUtils.synthesizeAndWaitNativeMouseMove(
+    tabFirst.linkedBrowser,
+    10,
+    10
+  );
+
+  info("Open and move to a new tab");
+  await AddMouseEventListener(tabFirst.linkedBrowser);
+  const tabSecond = await BrowserTestUtils.openNewForegroundTab(
+    gBrowser,
+    "http://example.com/browser/browser/base/content/test/general/dummy_page.html"
+  );
+  // Wait a bit to see if there is any unexpected mouse event.
+  await TestUtils.waitForTick();
+  await clearMouseEventListenerAndCheck(tabFirst.linkedBrowser, ["mouseleave"]);
+
+  info("switch back to the previous tab");
+  await AddMouseEventListener(tabFirst.linkedBrowser);
+  await AddMouseEventListener(tabSecond.linkedBrowser);
+  await BrowserTestUtils.switchTab(gBrowser, tabFirst);
+  // Wait a bit to see if there is any unexpected mouse event.
+  await TestUtils.waitForTick();
+  await clearMouseEventListenerAndCheck(tabFirst.linkedBrowser, ["mouseenter"]);
+  await clearMouseEventListenerAndCheck(tabSecond.linkedBrowser, [
+    "mouseleave",
+  ]);
+
+  info("Close tabs");
+  BrowserTestUtils.removeTab(tabFirst);
+  BrowserTestUtils.removeTab(tabSecond);
+});
--- a/dom/ipc/BrowserParent.cpp
+++ b/dom/ipc/BrowserParent.cpp
@@ -1164,17 +1164,16 @@ void BrowserParent::Activate() {
 }
 
 void BrowserParent::Deactivate(bool aWindowLowering) {
   LOGBROWSERFOCUS(("Deactivate %p", this));
   if (!aWindowLowering) {
     UnsetTopLevelWebFocus(this);  // Intentionally outside the next "if"
   }
   if (!mIsDestroyed) {
-    BrowserParent::UnsetLastMouseRemoteTarget(this);
     Unused << Manager()->SendDeactivate(this);
   }
 }
 
 #ifdef ACCESSIBILITY
 a11y::PDocAccessibleParent* BrowserParent::AllocPDocAccessibleParent(
     PDocAccessibleParent* aParent, const uint64_t&, const uint32_t&,
     const IAccessibleHolder&) {
@@ -1389,17 +1388,26 @@ void BrowserParent::SendRealMouseEvent(W
     return;
   }
 
   // XXXedgar, if the synthesized mouse events could deliver to the correct
   // process directly (see
   // https://bugzilla.mozilla.org/show_bug.cgi?id=1549355), we probably don't
   // need to check mReason then.
   if (aEvent.mReason == WidgetMouseEvent::eReal) {
-    sLastMouseRemoteTarget = this;
+    if (aEvent.mMessage == eMouseExitFromWidget) {
+      // Since we are leaving this remote target, so don't need to update
+      // sLastMouseRemoteTarget, and if we are sLastMouseRemoteTarget, reset it
+      // to null.
+      BrowserParent::UnsetLastMouseRemoteTarget(this);
+    } else {
+      // Last remote target should not be changed without eMouseExitFromWidget.
+      MOZ_ASSERT_IF(sLastMouseRemoteTarget, sLastMouseRemoteTarget == this);
+      sLastMouseRemoteTarget = this;
+    }
   }
 
   aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     // When we mouseenter the tab, the tab's cursor should
     // become the current cursor.  When we mouseexit, we stop.