Bug 970964 - Get pointer events from touch and mouse. tests. r=smaug
authorOleg Romashin <oleg.romashin@microsoft.com>
Wed, 26 Feb 2014 13:37:25 -0800
changeset 171077 3d58be18b53a2383b41b53c5859c2eed7e1096a8
parent 171076 788141812826927ad35b1e2fe98c55164ed90f86
child 171078 8bc0fba339392c010b4c2ae2bf5f9f370ad39cd3
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerssmaug
bugs970964
milestone30.0a1
Bug 970964 - Get pointer events from touch and mouse. tests. r=smaug
layout/base/tests/bug970964_inner.html
layout/base/tests/mochitest.ini
layout/base/tests/test_bug970964.html
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug970964_inner.html
@@ -0,0 +1,296 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=970964
+-->
+<head>
+  <title>Test for Bug 970964</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=970964">Mozilla Bug 970964</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 970964 **/
+
+function ok(condition, msg) {
+  parent.ok(condition, msg);
+}
+
+function is(a, b, msg) {
+  parent.is(a, b, msg);
+}
+
+function testtouch(aOptions) {
+  if (!aOptions)
+    aOptions = {};
+  this.identifier = aOptions.identifier || 0;
+  this.target = aOptions.target || 0;
+  this.page = aOptions.page || {x: 0, y: 0};
+  this.radius = aOptions.radius || {x: 0, y: 0};
+  this.rotationAngle = aOptions.rotationAngle || 0;
+  this.force = aOptions.force || 1;
+}
+
+function touchEvent(aOptions) {
+  if (!aOptions) {
+    aOptions = {};
+  }
+  this.ctrlKey = aOptions.ctrlKey || false;
+  this.altKey = aOptions.altKey || false;
+  this.shiftKey = aOptions.shiftKey || false;
+  this.metaKey = aOptions.metaKey || false;
+  this.touches = aOptions.touches || [];
+  this.targetTouches = aOptions.targetTouches || [];
+  this.changedTouches = aOptions.changedTouches || [];
+}
+
+function sendTouchEvent(windowUtils, aType, aEvent, aModifiers) {
+  var ids = [], xs=[], ys=[], rxs = [], rys = [],
+      rotations = [], forces = [];
+
+  for (var touchType of ["touches", "changedTouches", "targetTouches"]) {
+    for (var i = 0; i < aEvent[touchType].length; i++) {
+      if (ids.indexOf(aEvent[touchType][i].identifier) == -1) {
+        ids.push(aEvent[touchType][i].identifier);
+        xs.push(aEvent[touchType][i].page.x);
+        ys.push(aEvent[touchType][i].page.y);
+        rxs.push(aEvent[touchType][i].radius.x);
+        rys.push(aEvent[touchType][i].radius.y);
+        rotations.push(aEvent[touchType][i].rotationAngle);
+        forces.push(aEvent[touchType][i].force);
+      }
+    }
+  }
+  return windowUtils.sendTouchEvent(aType,
+                                    ids, xs, ys, rxs, rys,
+                                    rotations, forces,
+                                    ids.length, aModifiers, 0);
+}
+
+function getDefaultArgEvent(eventname) {
+  return new PointerEvent(eventname, {
+    bubbles: true, cancelable: true, view: window,
+    detail: 0, screenX: 0, screenY: 0, clientX: 0, clientY: 0,
+    ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
+    button: 0, relatedTarget: null, pointerId: 0
+  });
+}
+
+function getTouchEventForTarget(target, cwu, id) {
+  var bcr = target.getBoundingClientRect();
+  var touch = new testtouch({
+    page: {x: Math.round(bcr.left + bcr.width/2),
+           y: Math.round(bcr.top  + bcr.height/2)},
+    target: target,
+    identifier: id,
+  });
+  var event = new touchEvent({
+    touches: [touch],
+    targetTouches: [touch],
+    changedTouches: [touch]
+  });
+  return event;
+}
+
+function runTests() {
+  var d0 = document.getElementById("d0");
+  var d1 = document.getElementById("d1");
+  var d2 = document.getElementById("d2");
+  var d3 = document.getElementById("d3");
+
+  // Test Pointer firing before any mouse/touch original source
+
+  var mouseDownTriggered = 0;
+  var pointerDownTriggered = 0;
+  var touchDownTriggered = 0;
+  var touchCancelTriggered = 0;
+  var pointerCancelTriggered = 0;
+
+  d0.onmousedown = function(e) {
+    mouseDownTriggered = 1;
+    is(pointerDownTriggered , 1, "Mouse event must be triggered after pointer event!");
+  };
+  d0.ontouchstart = function(e) {
+    touchDownTriggered = 1;
+    is(touchDownTriggered , 1, "Touch event must be triggered after pointer event!");
+  }
+  d0.ontouchcancel = function(e) {
+    touchCancelTriggered = 1;
+    is(pointerCancelTriggered, 1, "Touch cancel event must be triggered after pointer event!");
+  }
+  d0.onpointerdown = function(e) {
+    pointerDownTriggered = 1;
+    is(mouseDownTriggered, 0, "Pointer event must be triggered before mouse event!");
+    is(touchDownTriggered, 0, "Pointer event must be triggered before touch event!");
+  };
+  d0.addEventListener("pointercancel", function(ev) {
+    d0.removeEventListener("pointercancel", arguments.callee, false);
+    is(ev.pointerId, 0, "Correct default pointerId");
+    pointerCancelTriggered = 1;
+    is(touchCancelTriggered, 0, "Pointer event must be triggered before touch event!");
+  }, false);
+
+  // Test pointer event generated from mouse event
+  synthesizeMouse(d1, 3, 3, { type: "mousemove"});
+  synthesizeMouse(d1, 3, 3, { type: "mousedown"});
+  synthesizeMouse(d1, 3, 3, { type: "mouseup"});
+
+  // Test pointer event generated from touch event
+  pointerDownTriggered = 0;
+  mouseDownTriggered = 0;
+
+  var cwu = SpecialPowers.getDOMWindowUtils(window);
+  var event1 = getTouchEventForTarget(d1, cwu, 0);
+  sendTouchEvent(cwu, "touchmove", event1, 0);
+  sendTouchEvent(cwu, "touchstart", event1, 0);
+  // Test Touch to Pointer Cancel
+  sendTouchEvent(cwu, "touchcancel", event1, 0);
+
+  // Check Pointer enter/leave from mouse generated event
+  var mouseEnterTriggered = 0;
+  var pointerEnterTriggered = 0;
+  d2.onpointerenter = function(e) {
+    pointerEnterTriggered = 1;
+    is(mouseEnterTriggered, 0, "Pointer event must be triggered before mouse event!");
+  };
+  d2.onmouseenter = function(e) {
+    mouseEnterTriggered = 1;
+    is(pointerEnterTriggered , 1, "Mouse event must be triggered after pointer event!");
+  };
+  synthesizeMouse(d2, 3, 3, { type: "mousemove"});
+  d2.onmouseenter = function(e) {}
+
+  // Test Multi Pointer enter/leave for pointers generated from Mouse and Touch at the same time
+  // Enter mouse and touch generated pointers to different elements
+  var d1enterCount = 0;
+  var d2enterCount = 0;
+  var d3enterCount = 0;
+  var d1leaveCount = 0;
+  var d2leaveCount = 0;
+  var d3leaveCount = 0;
+  var mousePointerEnterLeaveCount = 0;
+  var touchPointerEnterLeaveCount = 0;
+
+  var checkPointerType = function(pointerType) {
+    if (pointerType == "mouse") {
+      ++mousePointerEnterLeaveCount;
+    } else if (pointerType == "touch") {
+      ++touchPointerEnterLeaveCount;
+    }
+  };
+
+  d1.onpointerenter = function(e) {
+    ++d1enterCount;
+    checkPointerType(e.pointerType);
+  };
+  d2.onpointerenter = function(e) {
+    ++d2enterCount;
+    checkPointerType(e.pointerType);
+  };
+  d3.onpointerenter = function(e) {
+    ++d3enterCount;
+    checkPointerType(e.pointerType);
+  };
+  d1.onpointerleave = function(e) {
+    ++d1leaveCount;
+    checkPointerType(e.pointerType);
+  };
+  d2.onpointerleave = function(e) {
+    ++d2leaveCount;
+    checkPointerType(e.pointerType);
+  };
+  d3.onpointerleave = function(e) {
+    ++d3leaveCount;
+    checkPointerType(e.pointerType);
+  };
+
+  synthesizeMouse(d1, 3, 3, { type: "mousemove"});
+  sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d3, cwu, 3), 0);
+  is(touchPointerEnterLeaveCount, 1, "Wrong touch enterLeave count for!");
+  is(mousePointerEnterLeaveCount, 2, "Wrong mouse enterLeave count for!");
+
+  is(d1enterCount, 1, "Wrong enter count for! d1");
+  is(d2leaveCount, 1, "Wrong leave count for! d2");
+  is(d3enterCount, 1, "Wrong enter count for! d3");
+
+  sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d1, cwu, 3), 0);
+  synthesizeMouse(d3, 3, 3, { type: "mousemove"});
+  is(touchPointerEnterLeaveCount, 3, "Wrong touch enterLeave count for!");
+  is(mousePointerEnterLeaveCount, 4, "Wrong mouse enterLeave count for!");
+
+  is(d3leaveCount, 1, "Wrong leave count for! d3");
+  is(d1leaveCount, 1, "Wrong leave count for! d1");
+  is(d1enterCount, 2, "Wrong enter count for! d1");
+  is(d3enterCount, 2, "Wrong enter count for! d3");
+
+  sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d2, cwu, 3), 0);
+  synthesizeMouse(d2, 3, 3, { type: "mousemove"});
+  is(touchPointerEnterLeaveCount, 5, "Wrong touch enterLeave count for!");
+  is(mousePointerEnterLeaveCount, 6, "Wrong mouse enterLeave count for!");
+
+  is(d1leaveCount, 2, "Wrong leave count for! d1");
+  is(d2enterCount, 2, "Wrong enter count for! d2");
+  is(d3leaveCount, 2, "Wrong leave count for! d3");
+
+  sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d1, cwu, 3), 0);
+  synthesizeMouse(d1, 3, 3, { type: "mousemove"});
+  is(touchPointerEnterLeaveCount, 7, "Wrong touch enterLeave count for!");
+  is(mousePointerEnterLeaveCount, 8, "Wrong mouse enterLeave count for!");
+
+  is(d2leaveCount, 3, "Wrong leave count for! d2");
+  is(d1enterCount, 4, "Wrong enter count for! d1");
+
+  // Test for pointer buttons when it generated from mousemove event
+  d1.onpointermove = function(e) {
+    is(e.buttons, 0, "Buttons must be 0 on pointer generated from mousemove");
+    is(e.button, -1, "Button must be -1 on pointer generated from mousemove when no buttons pressed");
+    is(e.pointerType, "mouse", "Pointer type must be mouse");
+  };
+  cwu.sendMouseEvent("mousemove", 4, 4, 0, 0, 0, false, 0, 0);
+
+  d1.onpointermove = function(e) {
+    is(e.buttons, 1, "Buttons must be 1 on pointer generated from touch event");
+    is(e.button, 0, "Button must be 0 on pointer generated from touch eventd");
+    is(e.pointerType, "touch", "Pointer type must be touch");
+  };
+  sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d1, cwu, 2), 0);
+
+  finishTest();
+}
+
+function finishTest() {
+  // Let window.onerror have a chance to fire
+  setTimeout(function() {
+    setTimeout(function() {
+      window.parent.postMessage("SimpleTest.finish();", "*");
+    }, 0);
+  }, 0);
+}
+
+window.onload = function () {
+  SpecialPowers.pushPrefEnv({
+    "set": [
+      ["dom.w3c_pointer_events.enabled", true],
+    ]
+  }, runTests);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+<div id="d0">
+Test divs --
+<div id="d1">t</div><div id="d2">t</div><div id="d3">t</div>
+--
+</div>
+</body>
+</html>
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -187,16 +187,18 @@ skip-if = toolkit == 'android'
 [test_remote_frame.html]
 [test_remote_passpointerevents.html]
 [test_bug842853.html]
 [test_bug842853-2.html]
 [test_bug849219.html]
 [test_bug851485.html]
 [test_bug851445.html]
 support-files = bug851445_helper.html
+[test_bug970964.html]
+support-files = bug970964_inner.html
 [test_emulateMedium.html]
 [test_getClientRects_emptytext.html]
 [test_bug858459.html]
 skip-if = toolkit == "gonk"
 
 # Tests for bugs 441782, 467672 and 570378 do not pass reliably on Windows,
 # because of bug 469208.
 [test_bug332655-1.html]
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/test_bug970964.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=970964
+-->
+<head>
+  <title>Test for Bug 970964</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="text/javascript;version=1.7">
+    function setRemoteFrame() {
+      var iframe = document.getElementById("testFrame");
+      iframe.src = "bug970964_inner.html";
+
+      function messageListener(event) {
+        eval(event.data);
+      }
+
+      window.addEventListener("message", messageListener, false);
+    }
+
+    function runTest() {
+      SimpleTest.waitForExplicitFinish();
+
+      SpecialPowers.pushPrefEnv({
+        "set": [
+          ["dom.w3c_pointer_events.enabled", true]
+        ]
+      }, setRemoteFrame);
+    }
+  </script>
+</head>
+<body onload="runTest();">
+  <iframe id="testFrame" height="500" width="500"></iframe>
+</body>
+