Commits

Jim Mathies  committed fcf9991 Draft

Bug 726615 - Implement w3c touch events for Windows. Original patch by Makoto Kato. r=wesj, smaug, mbrubeck

  • Participants
  • Parent commits 2afbf54

Comments (0)

Files changed (7)

File content/events/src/nsDOMMozTouchEvent.cpp

-/* -*- 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);
-}

File content/events/src/nsDOMMozTouchEvent.h

-/* 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

File content/events/test/test_bug508906.html

-<!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>

File dom/interfaces/events/nsIDOMMozTouchEvent.idl

-/* -*- 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);
-};

File modules/libpref/src/init/all.js

 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);
 

File widget/windows/Makefile.in

 		-I$(topsrcdir)/layout/xul/base/src \
 		-I$(topsrcdir)/toolkit/xre \
 		-I$(topsrcdir)/xpcom/base \
+		-I$(topsrcdir)/content/events/src \
 		$(NULL)
 
 FORCE_STATIC_LIB = 1

File widget/windows/nsWindow.cpp

 #include "WinUtils.h"
 #include "WidgetUtils.h"
 #include "nsIWidgetListener.h"
+#include "nsDOMTouchEvent.h"
 
 #ifdef MOZ_ENABLE_D3D9_LAYER
 #include "LayerManagerD3D9.h"
   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;