Bug 726615 - Implement w3c touch events for Windows. Original patch by Makoto Kato. r=wesj, smaug, mbrubeck
authorJim Mathies <jmathies@mozilla.com>
Sat, 22 Sep 2012 14:28:35 -0500
changeset 107822 fcf9991c8d97
parent 107821 2afbf5440fc8
child 107823 a1f06437a8d2
push id15228
push userjmathies@mozilla.com
push dateSat, 22 Sep 2012 19:28:59 +0000
treeherdermozilla-inbound@fcf9991c8d97 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswesj, smaug, mbrubeck
bugs726615
milestone18.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 726615 - Implement w3c touch events for Windows. Original patch by Makoto Kato. r=wesj, smaug, mbrubeck
content/events/src/nsDOMMozTouchEvent.cpp
content/events/src/nsDOMMozTouchEvent.h
content/events/test/test_bug508906.html
dom/interfaces/events/nsIDOMMozTouchEvent.idl
modules/libpref/src/init/all.js
widget/windows/Makefile.in
widget/windows/nsWindow.cpp
deleted file mode 100644
--- a/content/events/src/nsDOMMozTouchEvent.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsDOMClassInfoID.h"
-#include "nsDOMMozTouchEvent.h"
-
-nsDOMMozTouchEvent::nsDOMMozTouchEvent(nsPresContext* aPresContext, nsMozTouchEvent* aEvent)
-  : nsDOMMouseEvent(aPresContext, aEvent ? aEvent : new nsMozTouchEvent(false, 0, nullptr, 0))
-{
-  NS_ASSERTION(mEvent->eventStructType == NS_MOZTOUCH_EVENT, "event type mismatch NS_MOZTOUCH_EVENT");
-
-  if (aEvent) {
-    mEventIsInternal = false;
-  } else {
-    mEventIsInternal = true;
-    mEvent->time = PR_Now();
-    mEvent->refPoint.x = mEvent->refPoint.y = 0;
-  }
-}
-
-nsDOMMozTouchEvent::~nsDOMMozTouchEvent()
-{
-  if (mEventIsInternal) {
-    delete static_cast<nsMozTouchEvent*>(mEvent);
-    mEvent = nullptr;
-  }
-}
-
-NS_IMPL_ADDREF_INHERITED(nsDOMMozTouchEvent, nsDOMMouseEvent)
-NS_IMPL_RELEASE_INHERITED(nsDOMMozTouchEvent, nsDOMMouseEvent)
-
-DOMCI_DATA(MozTouchEvent, nsDOMMozTouchEvent)
-
-NS_INTERFACE_MAP_BEGIN(nsDOMMozTouchEvent)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMMozTouchEvent)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozTouchEvent)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMMouseEvent)
-
-/* readonly attribute unsigned long steramId; */
-NS_IMETHODIMP
-nsDOMMozTouchEvent::GetStreamId(uint32_t *aStreamId)
-{
-  NS_ENSURE_ARG_POINTER(aStreamId);
-  *aStreamId = static_cast<nsMozTouchEvent*>(mEvent)->streamId;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMozTouchEvent::InitMozTouchEvent(const nsAString& aTypeArg,
-                                      bool aCanBubbleArg,
-                                      bool aCancelableArg,
-                                      nsIDOMWindow* aViewArg,
-                                      int32_t aDetailArg,
-                                      int32_t aScreenX,
-                                      int32_t aScreenY,
-                                      int32_t aClientX,
-                                      int32_t aClientY,
-                                      bool aCtrlKeyArg,
-                                      bool aAltKeyArg,
-                                      bool aShiftKeyArg,
-                                      bool aMetaKeyArg,
-                                      uint16_t aButton,
-                                      nsIDOMEventTarget* aRelatedTarget,
-                                      uint32_t aStreamId)
-{
-  nsresult rv = nsDOMMouseEvent::InitMouseEvent(aTypeArg,
-                                                aCanBubbleArg,
-                                                aCancelableArg,
-                                                aViewArg,
-                                                aDetailArg,
-                                                aScreenX,
-                                                aScreenY,
-                                                aClientX,
-                                                aClientY,
-                                                aCtrlKeyArg,
-                                                aAltKeyArg,
-                                                aShiftKeyArg,
-                                                aMetaKeyArg,
-                                                aButton,
-                                                aRelatedTarget);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsMozTouchEvent* mozTouchEvent = static_cast<nsMozTouchEvent*>(mEvent);
-  mozTouchEvent->streamId = aStreamId;
-
-  return NS_OK;
-}
-
-nsresult NS_NewDOMMozTouchEvent(nsIDOMEvent** aInstancePtrResult,
-                                     nsPresContext* aPresContext,
-                                     nsMozTouchEvent *aEvent)
-{
-  nsDOMMozTouchEvent *it = new nsDOMMozTouchEvent(aPresContext, aEvent);
-  return CallQueryInterface(it, aInstancePtrResult);
-}
deleted file mode 100644
--- a/content/events/src/nsDOMMozTouchEvent.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsDOMMozTouchEvent_h__
-#define nsDOMMozTouchEvent_h__
-
-#include "nsIDOMMozTouchEvent.h"
-#include "nsDOMMouseEvent.h"
-
-class nsPresContext;
-
-class nsDOMMozTouchEvent : public nsDOMMouseEvent,
-                           public nsIDOMMozTouchEvent
-{
-public:
-  nsDOMMozTouchEvent(nsPresContext* aPresCOntext, nsMozTouchEvent* aEvent);
-  virtual ~nsDOMMozTouchEvent();
-
-  NS_DECL_ISUPPORTS_INHERITED
-
-  NS_DECL_NSIDOMMOZTOUCHEVENT
-
-  // Forward to base class
-  NS_FORWARD_TO_NSDOMMOUSEEVENT
-};
-
-#endif
deleted file mode 100644
--- a/content/events/test/test_bug508906.html
+++ /dev/null
@@ -1,211 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=508906
--->
-<head>
-  <title>Test for Bug 508906</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.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=508906">Mozilla Bug 508906</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-  
-</div>
-<pre id="test">
-<script class="testbody" type="application/javascript;version=1.8">
-
-/** Test for Bug 508906 - MozTouch* Events **/
-
-let tests = [], testTarget, parent;
-
-function nextTest() {
-  if (tests.length)
-    SimpleTest.executeSoon(tests.shift());
-}
-
-function random() {
-  return Math.floor(Math.random() * 100);
-}
-
-function createTestEventValue(name) {
-
-  let detail = random();
-  let screenX = random();
-  let screenY = random();
-  let clientX = random();
-  let clientY = random();
-  let ctrlKey = random() % 2 ? true : false;
-  let altKey = random() % 2 ? true : false;
-  let shiftKey = random() % 2 ? true : false;
-  let metaKey = random() % 2 ? true : false;
-  let button = random();
-  let streamId = random();
-
-  return function() {
-    let event = document.createEvent("MozTouchEvent");
-    event.initMozTouchEvent(name, true, true, window,
-                            detail, screenX, screenY, clientX, clientY,
-                            ctrlKey, altKey, shiftKey, metaKey, button,
-                            null, streamId);
-
-    function check(ev) {
-      is(ev.detail, detail, "Correct detail");
-      is(ev.screenX, screenX, "Correct screenX");
-      is(ev.screenY, screenY, "Correct screenY");
-      is(ev.clientX, clientX, "Correct clientX");
-      is(ev.clientY, clientY, "Correct clientY");
-      is(ev.ctrlKey, ctrlKey, "Correct ctrlKey");
-      is(ev.altKey, altKey, "Correct altKey");
-      is(ev.shiftKey, shiftKey, "Correct shiftKey");
-      is(ev.metaKey, metaKey, "Correct metaKey");
-      is(ev.button, button, "Correct buttonArg");
-      is(ev.streamId, streamId, "Correct streamId");
-    }
-
-    for each (let target in [document, window, testTarget, parent])
-      target.addEventListener(name, check, false);
-
-    testTarget.dispatchEvent(event);
-
-    for each (let target in [document, window, testTarget, parent])
-      target.removeEventListener(name, check, false);
-
-
-    nextTest();
-  }
-}
-
-function testDefaultArg() {
-  let event = document.createEvent("MozTouchEvent");
-  event.initMouseEvent("MozTouchDown", true, true, window, 0, 0, 0, 0, 0, 
-                       false, false, false, false, 0, null);
-  testTarget.addEventListener("MozTouchDown", function(ev) {
-    testTarget.removeEventListener("MozTouchDown", arguments.callee, false);
-    is(ev.streamId, 0, "Correct default streamId");
-  }, false);
-  testTarget.dispatchEvent(event);
-
-  nextTest();
-}
-
-function testStopPropagation() {
-  let event = document.createEvent("MozTouchEvent");
-  event.initMozTouchEvent("MozTouchDown", true, true, window, 0, 0, 0, 0, 0,
-                          false, false, false, false, 0, null, 0);
-
-  let unreachableListener = function () {
-    ok(false, "Event should have been stopped");
-  }
-
-  // Capturing phase
-  let captured = false;
-  parent.addEventListener("MozTouchDown", function() {
-    parent.removeEventListener("MozTouchDown", arguments.callee, true);
-    captured = true;
-  }, true); // Capturing phase
-
-  // Bubbling phase
-  parent.addEventListener("MozTouchDown", unreachableListener, false);
-
-  testTarget.addEventListener("MozTouchDown", function(ev) {
-    testTarget.removeEventListener("MozTouchDown", arguments.callee, false);
-    is(captured, true, "Event should have been captured");
-    ev.stopPropagation();
-  }, false);
-
-  testTarget.dispatchEvent(event);
-
-  parent.removeEventListener("MozTouchDown", unreachableListener, false);
-
-  nextTest();
-}
-
-function testPreventDefault() {
-  let event = document.createEvent("MozTouchEvent");
-  event.initMozTouchEvent("MozTouchDown", true, true, window, 0, 0, 0, 0, 0,
-                          false, false, false, false, 0, null, 0);
-
-  parent.addEventListener("MozTouchDown", function(ev) {
-    parent.removeEventListener("MozTouchDown", arguments.callee, false);
-    is(ev.defaultPrevented, true, "preventDefault can be called");
-    nextTest();
-  }, false);
-
-  testTarget.addEventListener("MozTouchDown", function(ev) {
-    testTarget.removeEventListener("MozTouchDown", arguments.callee, false);
-    ev.preventDefault();
-  }, false);
-
-  testTarget.dispatchEvent(event);
-}
-
-function testBlockPreventDefault() {
-  let event = document.createEvent("MozTouchEvent");
-  event.initMozTouchEvent("MozTouchDown", true, false, window, 0, 0, 0, 0, 0,
-                          false, false, false, false, 0, null, 0);
-
-  parent.addEventListener("MozTouchDown", function(ev) {
-    parent.removeEventListener("MozTouchDown", arguments.callee, false);
-    is(ev.defaultPrevented, false, "aCancelableArg works");
-    nextTest();
-  }, false);
-
-  testTarget.addEventListener("MozTouchDown", function(ev) {
-    testTarget.removeEventListener("MozTouchDown", arguments.callee, false);
-    ev.preventDefault();
-  }, false);
-
-  testTarget.dispatchEvent(event);
-}
-
-function testBlockBubbling() {
-  let unreachableListener = function () {
-    ok(false, "aCanBubble doesn't work");
-  }
-
-  let event = document.createEvent("MozTouchEvent");
-  event.initMozTouchEvent("MozTouchDown", false, true, window, 0, 0, 0, 0, 0,
-                          false, false, false, false, 0, null, 0);
-  parent.addEventListener("MozTouchDown", unreachableListener, false);
-  testTarget.dispatchEvent(event);
-  parent.removeEventListener("MozTouchDown", unreachableListener, false);
-
-  nextTest();
-}
-
-function doTest() {
-  testTarget = document.getElementById("testTarget");
-  parent = testTarget.parentNode;
-
-  tests.push(createTestEventValue("MozTouchDown"));
-  tests.push(createTestEventValue("MozTouchMove"));
-  tests.push(createTestEventValue("MozTouchUp"));
-
-  tests.push(testDefaultArg);
-  tests.push(testStopPropagation);
-
-  tests.push(testPreventDefault);
-  tests.push(testBlockPreventDefault);
-
-  tests.push(testBlockBubbling);
-
-  tests.push(function() {
-    SimpleTest.finish();
-  });
-
-  nextTest();
-}
-
-SimpleTest.waitForExplicitFinish();
-addLoadEvent(doTest);
-
-</script>
-</pre>
-<div id="parent">
-  <span id="testTarget" style="border: 1px solid black;">testTarget</span>
-</div>
-</body>
-</html>
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMMozTouchEvent.idl
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-
-#include "nsIDOMMouseEvent.idl"
-
-
-[scriptable, builtinclass, uuid(58795094-bb6c-488e-af4d-ea029b07869a)]
-interface nsIDOMMozTouchEvent : nsIDOMMouseEvent
-{
-  readonly attribute unsigned long streamId;
-
-  void initMozTouchEvent(in DOMString typeArg,
-                         in boolean canBubbleArg,
-                         in boolean cancelableArg,
-                         in nsIDOMWindow viewArg,
-                         in long detailArg,
-                         in long screenXArg,
-                         in long screenYArg,
-                         in long clientXArg,
-                         in long clientYArg,
-                         in boolean ctrlKeyArg,
-                         in boolean altKeyArg,
-                         in boolean shiftKeyArg,
-                         in boolean metaKeyArg,
-                         in unsigned short buttonArg,
-                         in nsIDOMEventTarget relatedTargetArg,
-                         in unsigned long streamIdArg);
-};
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3678,16 +3678,21 @@ pref("dom.mozContacts.enabled", false);
 
 // WebAlarms
 pref("dom.mozAlarms.enabled", false);
 
 // WebSettings
 pref("dom.mozSettings.enabled", false);
 pref("dom.mozPermissionSettings.enabled", false);
 
+// W3C touch events
+#ifdef XP_WIN
+pref("dom.w3c_touch_events.enabled", true);
+#endif
+
 // enable JS dump() function.
 pref("browser.dom.window.dump.enabled", false);
 
 // SPS Profiler
 pref("profiler.enabled", false);
 pref("profiler.interval", 10);
 pref("profiler.entries", 100000);
 
--- a/widget/windows/Makefile.in
+++ b/widget/windows/Makefile.in
@@ -100,16 +100,17 @@ LOCAL_INCLUDES	= \
 		-I. \
 		-I$(srcdir)/../xpwidgets \
 		-I$(srcdir)/../shared \
 		-I$(srcdir) \
 		-I$(topsrcdir)/layout/generic \
 		-I$(topsrcdir)/layout/xul/base/src \
 		-I$(topsrcdir)/toolkit/xre \
 		-I$(topsrcdir)/xpcom/base \
+		-I$(topsrcdir)/content/events/src \
 		$(NULL)
 
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 
 ifdef ENABLE_TESTS
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -112,16 +112,17 @@
 #include "Layers.h"
 #include "nsPrintfCString.h"
 #include "mozilla/Preferences.h"
 #include "nsISound.h"
 #include "WinTaskbar.h"
 #include "WinUtils.h"
 #include "WidgetUtils.h"
 #include "nsIWidgetListener.h"
+#include "nsDOMTouchEvent.h"
 
 #ifdef MOZ_ENABLE_D3D9_LAYER
 #include "LayerManagerD3D9.h"
 #endif
 
 #ifdef MOZ_ENABLE_D3D10_LAYER
 #include "LayerManagerD3D10.h"
 #endif
@@ -6175,16 +6176,96 @@ void nsWindow::UserActivity()
   }
 }
 
 bool nsWindow::OnTouch(WPARAM wParam, LPARAM lParam)
 {
   uint32_t cInputs = LOWORD(wParam);
   PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
 
+  if (mGesture.GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs)) {
+    nsTouchEvent* touchEventToSend = nullptr;
+    nsTouchEvent* touchEndEventToSend = nullptr;
+    nsEventStatus status;
+
+    // Walk across the touch point array processing each contact point
+    for (uint32_t i = 0; i < cInputs; i++) {
+      uint32_t msg;
+
+      if (pInputs[i].dwFlags & (TOUCHEVENTF_DOWN | TOUCHEVENTF_MOVE)) {
+        // Create a standard touch event to send
+        if (!touchEventToSend) {
+          touchEventToSend = new nsTouchEvent(true, NS_TOUCH_MOVE, this);
+          touchEventToSend->time = ::GetMessageTime();
+          ModifierKeyState modifierKeyState;
+          modifierKeyState.InitInputEvent(*touchEventToSend);
+        }
+
+        // Pres shell expects this event to be a NS_TOUCH_START if new contact
+        // points have been added since the last event sent.
+        if (pInputs[i].dwFlags & TOUCHEVENTF_DOWN) {
+          touchEventToSend->message = msg = NS_TOUCH_START;
+        } else {
+          msg = NS_TOUCH_MOVE;
+        }
+      } else if (pInputs[i].dwFlags & TOUCHEVENTF_UP) {
+        // Pres shell expects removed contacts points to be delivered in a
+        // separate NS_TOUCH_END event containing only the contact points
+        // that were removed.
+        if (!touchEndEventToSend) {
+          touchEndEventToSend = new nsTouchEvent(true, NS_TOUCH_END, this);
+          touchEndEventToSend->time = ::GetMessageTime();
+          ModifierKeyState modifierKeyState;
+          modifierKeyState.InitInputEvent(*touchEndEventToSend);
+        }
+        msg = NS_TOUCH_END;
+      } else {
+        // Filter out spurious Windows events we don't understand, like palm
+        // contact.
+        continue;
+      }
+
+      // Setup the touch point we'll append to the touch event array
+      nsPointWin touchPoint;
+      touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
+      touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
+      touchPoint.ScreenToClient(mWnd);
+      nsCOMPtr<nsIDOMTouch> touch =
+        new nsDOMTouch(pInputs[i].dwID,
+                       touchPoint,
+                       /* radius, if known */
+                       pInputs[i].dwFlags & TOUCHINPUTMASKF_CONTACTAREA ?
+                         nsIntPoint(
+                           TOUCH_COORD_TO_PIXEL(pInputs[i].cxContact) / 2,
+                           TOUCH_COORD_TO_PIXEL(pInputs[i].cyContact) / 2) :
+                         nsIntPoint(1,1),
+                       /* rotation angle and force */
+                       0.0f, 0.0f);
+
+      // Append to the appropriate event
+      if (msg == NS_TOUCH_START || msg == NS_TOUCH_MOVE) {
+        touchEventToSend->touches.AppendElement(touch);
+      } else {
+        touchEndEventToSend->touches.AppendElement(touch);
+      }
+    }
+
+    // Dispatch touch start and move event if we have one.
+    if (touchEventToSend) {
+      DispatchEvent(touchEventToSend, status);
+      delete touchEventToSend;
+    }
+
+    // Dispatch touch end event if we have one.
+    if (touchEndEventToSend) {
+      DispatchEvent(touchEndEventToSend, status);
+      delete touchEndEventToSend;
+    }
+  }
+
   delete [] pInputs;
   mGesture.CloseTouchInputHandle((HTOUCHINPUT)lParam);
   return true;
 }
 
 static int32_t RoundDown(double aDouble)
 {
   return aDouble > 0 ? static_cast<int32_t>(floor(aDouble)) :