Bug 894485 - Have touch events precede mouse events to simulate touch devices. r=surkov
authorEitan Isaacson <eitan@monotonous.org>
Thu, 25 Jul 2013 08:59:08 -0700
changeset 152309 a6192b162ba20a4e8cdfc91cc36648f8ec6709a9
parent 152308 daeeae8ab22a00c2e947b9b5fdf4d3c7290ae655
child 152310 092abce120e6cd98216cebb1b0530be8b030fb25
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssurkov
bugs894485
milestone25.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 894485 - Have touch events precede mouse events to simulate touch devices. r=surkov
accessible/src/base/nsCoreUtils.cpp
accessible/src/base/nsCoreUtils.h
accessible/src/generic/Accessible.cpp
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -27,16 +27,17 @@
 #include "nsEventStateManager.h"
 #include "nsISelectionPrivate.h"
 #include "nsISelectionController.h"
 #include "nsPIDOMWindow.h"
 #include "nsGUIEvent.h"
 #include "nsView.h"
 #include "nsLayoutUtils.h"
 #include "nsGkAtoms.h"
+#include "nsDOMTouchEvent.h"
 
 #include "nsComponentManagerUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "mozilla/dom/Element.h"
 
 #include "nsITreeBoxObject.h"
 #include "nsITreeColumns.h"
 
@@ -108,50 +109,24 @@ nsCoreUtils::DispatchClickEvent(nsITreeB
 
   nsPresContext* presContext = presShell->GetPresContext();
 
   int32_t cnvdX = presContext->CSSPixelsToDevPixels(tcX + x + 1) +
     presContext->AppUnitsToDevPixels(offset.x);
   int32_t cnvdY = presContext->CSSPixelsToDevPixels(tcY + y + 1) +
     presContext->AppUnitsToDevPixels(offset.y);
 
+  // XUL is just desktop, so there is no real reason for senfing touch events.
   DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, cnvdX, cnvdY,
                      tcContent, tcFrame, presShell, rootWidget);
 
   DispatchMouseEvent(NS_MOUSE_BUTTON_UP, cnvdX, cnvdY,
                      tcContent, tcFrame, presShell, rootWidget);
 }
 
-bool
-nsCoreUtils::DispatchMouseEvent(uint32_t aEventType,
-                                nsIPresShell *aPresShell,
-                                nsIContent *aContent)
-{
-  nsIFrame *frame = aContent->GetPrimaryFrame();
-  if (!frame)
-    return false;
-
-  // Compute x and y coordinates.
-  nsPoint point;
-  nsCOMPtr<nsIWidget> widget = frame->GetNearestWidget(point);
-  if (!widget)
-    return false;
-
-  nsSize size = frame->GetSize();
-
-  nsPresContext* presContext = aPresShell->GetPresContext();
-
-  int32_t x = presContext->AppUnitsToDevPixels(point.x + size.width / 2);
-  int32_t y = presContext->AppUnitsToDevPixels(point.y + size.height / 2);
-
-  // Fire mouse event.
-  DispatchMouseEvent(aEventType, x, y, aContent, frame, aPresShell, widget);
-  return true;
-}
-
 void
 nsCoreUtils::DispatchMouseEvent(uint32_t aEventType, int32_t aX, int32_t aY,
                                 nsIContent *aContent, nsIFrame *aFrame,
                                 nsIPresShell *aPresShell, nsIWidget *aRootWidget)
 {
   nsMouseEvent event(true, aEventType, aRootWidget,
                      nsMouseEvent::eReal, nsMouseEvent::eNormal);
 
@@ -161,16 +136,38 @@ nsCoreUtils::DispatchMouseEvent(uint32_t
   event.button = nsMouseEvent::eLeftButton;
   event.time = PR_IntervalNow();
   event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
 
   nsEventStatus status = nsEventStatus_eIgnore;
   aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status);
 }
 
+void
+nsCoreUtils::DispatchTouchEvent(uint32_t aEventType, int32_t aX, int32_t aY,
+                                nsIContent* aContent, nsIFrame* aFrame,
+                                nsIPresShell* aPresShell, nsIWidget* aRootWidget)
+{
+  if (!nsDOMTouchEvent::PrefEnabled())
+    return;
+
+  nsTouchEvent event(true, aEventType, aRootWidget);
+
+  event.time = PR_IntervalNow();
+
+  // XXX: Touch has an identifier of -1 to hint that it is synthesized.
+  nsRefPtr<mozilla::dom::Touch> t =
+    new mozilla::dom::Touch(-1, nsIntPoint(aX, aY),
+                            nsIntPoint(1, 1), 0.0f, 1.0f);
+  t->SetTarget(aContent);
+  event.touches.AppendElement(t);
+  nsEventStatus status = nsEventStatus_eIgnore;
+  aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status);
+}
+
 uint32_t
 nsCoreUtils::GetAccessKeyFor(nsIContent* aContent)
 {
   // Accesskeys are registered by @accesskey attribute only. At first check
   // whether it is presented on the given element to avoid the slow
   // nsEventStateManager::GetRegisteredAccessKey() method.
   if (!aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::accesskey))
     return 0;
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -44,39 +44,42 @@ public:
    */
   static void DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj,
                                  int32_t aRowIndex, nsITreeColumn *aColumn,
                                  const nsCString& aPseudoElt = EmptyCString());
 
   /**
    * Send mouse event to the given element.
    *
-   * @param  aEventType  [in] an event type (see nsGUIEvent.h for constants)
-   * @param  aPresShell  [in] the presshell for the given element
-   * @param  aContent    [in] the element
-   */
-  static bool DispatchMouseEvent(uint32_t aEventType,
-                                   nsIPresShell *aPresShell,
-                                   nsIContent *aContent);
-
-  /**
-   * Send mouse event to the given element.
-   *
    * @param aEventType   [in] an event type (see nsGUIEvent.h for constants)
    * @param aX           [in] x coordinate in dev pixels
    * @param aY           [in] y coordinate in dev pixels
    * @param aContent     [in] the element
    * @param aFrame       [in] frame of the element
    * @param aPresShell   [in] the presshell for the element
    * @param aRootWidget  [in] the root widget of the element
    */
   static void DispatchMouseEvent(uint32_t aEventType, int32_t aX, int32_t aY,
                                  nsIContent *aContent, nsIFrame *aFrame,
-                                 nsIPresShell *aPresShell,
-                                 nsIWidget *aRootWidget);
+                                 nsIPresShell *aPresShell, nsIWidget *aRootWidget);
+
+  /**
+   * Send a touch event with a single touch point to the given element.
+   *
+   * @param aEventType   [in] an event type (see nsGUIEvent.h for constants)
+   * @param aX           [in] x coordinate in dev pixels
+   * @param aY           [in] y coordinate in dev pixels
+   * @param aContent     [in] the element
+   * @param aFrame       [in] frame of the element
+   * @param aPresShell   [in] the presshell for the element
+   * @param aRootWidget  [in] the root widget of the element
+   */
+  static void DispatchTouchEvent(uint32_t aEventType, int32_t aX, int32_t aY,
+                                 nsIContent* aContent, nsIFrame* aFrame,
+                                 nsIPresShell* aPresShell, nsIWidget* aRootWidget);
 
   /**
    * Return an accesskey registered on the given element by
    * nsEventStateManager or 0 if there is no registered accesskey.
    *
    * @param aContent - the given element.
    */
   static uint32_t GetAccessKeyFor(nsIContent *aContent);
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -2288,23 +2288,38 @@ Accessible::DispatchClickEvent(nsIConten
   nsIPresShell* presShell = mDoc->PresShell();
 
   // Scroll into view.
   presShell->ScrollContentIntoView(aContent,
                                    nsIPresShell::ScrollAxis(),
                                    nsIPresShell::ScrollAxis(),
                                    nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
 
-  // Fire mouse down and mouse up events.
-  bool res = nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, presShell,
-                                               aContent);
-  if (!res)
+  nsIFrame* frame = aContent->GetPrimaryFrame();
+  if (!frame)
+    return;
+
+  // Compute x and y coordinates.
+  nsPoint point;
+  nsCOMPtr<nsIWidget> widget = frame->GetNearestWidget(point);
+  if (!widget)
     return;
 
-  nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_UP, presShell, aContent);
+  nsSize size = frame->GetSize();
+
+  nsPresContext* presContext = presShell->GetPresContext();
+
+  int32_t x = presContext->AppUnitsToDevPixels(point.x + size.width / 2);
+  int32_t y = presContext->AppUnitsToDevPixels(point.y + size.height / 2);
+
+  // Simulate a touch interaction by dispatching touch events with mouse events.
+  nsCoreUtils::DispatchTouchEvent(NS_TOUCH_START, x, y, aContent, frame, presShell, widget);
+  nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, x, y, aContent, frame, presShell, widget);
+  nsCoreUtils::DispatchTouchEvent(NS_TOUCH_END, x, y, aContent, frame, presShell, widget);
+  nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_UP, x, y, aContent, frame, presShell, widget);
 }
 
 NS_IMETHODIMP
 Accessible::ScrollTo(uint32_t aHow)
 {
   if (IsDefunct())
     return NS_ERROR_FAILURE;