Bug 1282084 - Don't allow RDM to show triggered hover states while touch is enabled. r=pbro
authorMicah Tigley <mtigley@mozilla.com>
Tue, 09 Apr 2019 14:23:32 +0000
changeset 468589 106e58c798efea5320f6806f2ef6781a5987b294
parent 468588 d389f6f9743efc1f349d44305a84eb620f433805
child 468590 b53ad32487116413bb6fa068ce43af2eae217e69
push id112738
push usernbeleuzu@mozilla.com
push dateTue, 09 Apr 2019 22:28:41 +0000
treeherdermozilla-inbound@d6bbb316b768 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspbro
bugs1282084
milestone68.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 1282084 - Don't allow RDM to show triggered hover states while touch is enabled. r=pbro Differential Revision: https://phabricator.services.mozilla.com/D26053
devtools/client/responsive.html/test/browser/browser.ini
devtools/client/responsive.html/test/browser/browser_touch_does_not_trigger_hover_states.js
devtools/client/responsive.html/test/browser/hover.html
devtools/server/actors/emulation/touch-simulator.js
--- a/devtools/client/responsive.html/test/browser/browser.ini
+++ b/devtools/client/responsive.html/test/browser/browser.ini
@@ -9,16 +9,17 @@ support-files =
   devices.json
   doc_page_state.html
   doc_toolbox_rule_view.css
   doc_toolbox_rule_view.html
   favicon.html
   favicon.ico
   geolocation.html
   head.js
+  hover.html
   page_style.html
   touch.html
   !/devtools/client/inspector/test/shared-head.js
   !/devtools/client/shared/test/shared-head.js
   !/devtools/client/shared/test/shared-redux-head.js
   !/devtools/client/shared/test/telemetry-test-helpers.js
   !/devtools/client/shared/test/test-actor.js
   !/devtools/client/shared/test/test-actor-registry.js
@@ -64,14 +65,15 @@ skip-if = true # Bug 1413765
 [browser_toggle_zoom.js]
 [browser_toolbox_computed_view.js]
 [browser_toolbox_rule_view.js]
 [browser_toolbox_rule_view_reload.js]
 skip-if = os == "linux" || os == "mac" # Bug 1498336
 [browser_toolbox_swap_browsers.js]
 [browser_toolbox_swap_inspector.js]
 [browser_touch_device.js]
+[browser_touch_does_not_trigger_hover_states.js]
 [browser_touch_simulation.js]
 [browser_user_agent_input.js]
 [browser_viewport_basics.js]
 [browser_viewport_resizing_fixed_width.js]
 [browser_viewport_resizing_fixed_width_and_zoom.js]
 [browser_window_close.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/test/browser/browser_touch_does_not_trigger_hover_states.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that element hover states are not triggered when touch is enabled.
+
+const TEST_URL = `${URL_ROOT}hover.html`;
+
+addRDMTask(TEST_URL, async function({ ui }) {
+  reloadOnTouchChange(true);
+
+  await injectEventUtilsInContentTask(ui.getViewportBrowser());
+  await toggleTouchSimulation(ui);
+
+  info("Test element hover states when touch is enabled.");
+  await testButtonHoverState(ui, "rgb(255, 0, 0)");
+  await testDropDownHoverState(ui, "none");
+
+  await toggleTouchSimulation(ui);
+
+  info("Test element hover states when touch is disabled.");
+  await testButtonHoverState(ui, "rgb(0, 0, 0)");
+  await testDropDownHoverState(ui, "block");
+
+  reloadOnTouchChange(false);
+});
+
+async function testButtonHoverState(ui, expected) {
+  await ContentTask.spawn(ui.getViewportBrowser(), { expected },
+    async function(args) {
+      let button = content.document.querySelector("button");
+      const { expected: contentExpected } = args;
+
+      info("Move mouse into the button element.");
+      await EventUtils.synthesizeMouseAtCenter(button,
+            { type: "mousemove", isSynthesized: false }, content);
+      button = content.document.querySelector("button");
+      const win = content.document.defaultView;
+
+      is(win.getComputedStyle(button).getPropertyValue("background-color"),
+        contentExpected, `Button background color is ${contentExpected}.`);
+    });
+}
+
+async function testDropDownHoverState(ui, expected) {
+  await ContentTask.spawn(ui.getViewportBrowser(), { expected },
+    async function(args) {
+      const dropDownMenu = content.document.querySelector(".drop-down-menu");
+      const { expected: contentExpected } = args;
+
+      info("Move mouse into the drop down menu.");
+      await EventUtils.synthesizeMouseAtCenter(dropDownMenu,
+            { type: "mousemove", isSynthesized: false }, content);
+      const win = content.document.defaultView;
+      const menuItems = content.document.querySelector(".menu-items-list");
+
+      is(win.getComputedStyle(menuItems).getPropertyValue("display"), contentExpected,
+        `Menu items is display: ${contentExpected}.`);
+    });
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/test/browser/hover.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset="UTF-8">
+<style>
+  button {
+    background-color: rgb(255, 0, 0);
+    color: black;
+  }
+
+  button:hover {
+    background-color: rgb(0, 0, 0);
+    color: white;
+  }
+
+  .drop-down-menu {
+    height: 100px;
+    width: 100px;
+  }
+
+  .drop-down-menu .menu-items-list {
+    display: none;
+  }
+
+  .drop-down-menu:hover .menu-items-list {
+    display: block;
+  }
+</style>
+<div>
+  <button>Test Button</button>
+  <div class="drop-down-menu">
+    <div class="menu-title">Test Menu</div>
+    <ul class="menu-items-list">
+      <li class="item-one">One</li>
+      <li class="item-two">Two</li>
+      <li class="item-three">Three</li>
+    </ul>
+  </div>
+</div>
--- a/devtools/server/actors/emulation/touch-simulator.js
+++ b/devtools/server/actors/emulation/touch-simulator.js
@@ -3,31 +3,35 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* global XPCNativeWrapper */
 
 "use strict";
 
 const { Services } = require("resource://gre/modules/Services.jsm");
 
+loader.lazyRequireGetter(this, "InspectorUtils", "InspectorUtils");
+
 var systemAppOrigin = (function() {
   let systemOrigin = "_";
   try {
     systemOrigin =
       Services.io.newURI(Services.prefs.getCharPref("b2g.system_manifest_url"))
                  .prePath;
   } catch (e) {
     // Fall back to default value
   }
   return systemOrigin;
 })();
 
 var threshold = Services.prefs.getIntPref("ui.dragThresholdX", 25);
 var delay = Services.prefs.getIntPref("ui.click_hold_context_menus.delay", 500);
 
+const kStateHover = 0x00000004; // NS_EVENT_STATE_HOVER
+
 function TouchSimulator(simulatorTarget) {
   this.simulatorTarget = simulatorTarget;
 }
 
 /**
  * Simulate touch events for platforms where they aren't generally available.
  */
 TouchSimulator.prototype = {
@@ -140,16 +144,22 @@ TouchSimulator.prototype = {
     let type = "";
     switch (evt.type) {
       case "mouseenter":
       case "mouseover":
       case "mouseout":
       case "mouseleave":
         // Don't propagate events which are not related to touch events
         evt.stopPropagation();
+        evt.preventDefault();
+
+        // We don't want to trigger any visual changes to elements whose content can
+        // be modified via hover states. We can avoid this by removing the element's
+        // content state.
+        InspectorUtils.removeContentState(evt.target, kStateHover);
         break;
 
       case "mousedown":
         this.target = evt.target;
 
         this.contextMenuTimeout = this.sendContextMenu(evt);
 
         this.cancelClick = false;