Bug 1264017 - Add an APZ test API to synthesize a mouse click. r=botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Sun, 15 May 2016 20:29:47 -0400
changeset 367369 433f162ebd3ea0b9db1da841d36c5b5137d958bf
parent 367171 4a8ed77f6bb573f20980056bf8c1dadd125c1a85
child 367370 c30755a90eb33f54f084f2af81c1a27f11d094b3
push id18221
push userkgupta@mozilla.com
push dateMon, 16 May 2016 13:48:43 +0000
reviewersbotond
bugs1264017
milestone49.0a1
Bug 1264017 - Add an APZ test API to synthesize a mouse click. r=botond MozReview-Commit-ID: EWp4BtdAHZz
gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
widget/gtk/nsWindow.cpp
--- a/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
+++ b/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
@@ -39,25 +39,41 @@ function nativeScrollUnits(aElement, aDi
       var targetWindow = aElement.ownerDocument.defaultView;
       var lineHeight = targetWindow.getComputedStyle(aElement)["font-size"];
       return aDimen / (parseInt(lineHeight) * 3);
     }
   }
   return aDimen;
 }
 
+function nativeMouseDownEventMsg() {
+  switch (getPlatform()) {
+    case "windows": return 2; // MOUSEEVENTF_LEFTDOWN
+    case "mac": return 1; // NSLeftMouseDown
+    case "linux": return 4; // GDK_BUTTON_PRESS
+  }
+}
+
 function nativeMouseMoveEventMsg() {
   switch (getPlatform()) {
     case "windows": return 1; // MOUSEEVENTF_MOVE
     case "mac": return 5; // NSMouseMoved
     case "linux": return 3; // GDK_MOTION_NOTIFY
   }
   throw "Native wheel events not supported on platform " + getPlatform();
 }
 
+function nativeMouseUpEventMsg() {
+  switch (getPlatform()) {
+    case "windows": return 4; // MOUSEEVENTF_LEFTUP
+    case "mac": return 2; // NSLeftMouseUp
+    case "linux": return 7; // GDK_BUTTON_RELEASE
+  }
+}
+
 // Convert (aX, aY), in CSS pixels relative to aElement's bounding rect,
 // to device pixels relative to aElement's containing window.
 function coordinatesRelativeToWindow(aX, aY, aElement) {
   var targetWindow = aElement.ownerDocument.defaultView;
   var scale = targetWindow.devicePixelRatio;
   var rect = aElement.getBoundingClientRect();
   return {
     x: (targetWindow.mozInnerScreenX + rect.left + aX) * scale,
@@ -172,8 +188,17 @@ function synthesizeNativeDrag(aElement, 
 }
 
 function synthesizeNativeTap(aElement, aX, aY, aObserver = null) {
   var pt = coordinatesRelativeToWindow(aX, aY, aElement);
   var utils = SpecialPowers.getDOMWindowUtils(aElement.ownerDocument.defaultView);
   utils.sendNativeTouchTap(pt.x, pt.y, false, aObserver);
   return true;
 }
+
+function synthesizeNativeClick(aElement, aX, aY, aObserver = null) {
+  var pt = coordinatesRelativeToWindow(aX, aY, aElement);
+  var utils = SpecialPowers.getDOMWindowUtils(aElement.ownerDocument.defaultView);
+  utils.sendNativeMouseEvent(pt.x, pt.y, nativeMouseDownEventMsg(), 0, aElement, function() {
+    utils.sendNativeMouseEvent(pt.x, pt.y, nativeMouseUpEventMsg(), 0, aElement, aObserver);
+  });
+  return true;
+}
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -6806,40 +6806,47 @@ nsWindow::SynthesizeNativeMouseEvent(Lay
   AutoObserverNotifier notifier(aObserver, "mouseevent");
 
   if (!mGdkWindow) {
     return NS_OK;
   }
 
   GdkDisplay* display = gdk_window_get_display(mGdkWindow);
 
-  // When a button-release event is requested, create it here and put it in the
+  // When a button-press/release event is requested, create it here and put it in the
   // event queue. This will not emit a motion event - this needs to be done
-  // explicitly *before* requesting a button-release. You will also need to wait
-  // for the motion event to be dispatched before requesting a button-release
+  // explicitly *before* requesting a button-press/release. You will also need to wait
+  // for the motion event to be dispatched before requesting a button-press/release
   // event to maintain the desired event order.
-  if (aNativeMessage == GDK_BUTTON_RELEASE) {
+  if (aNativeMessage == GDK_BUTTON_PRESS || aNativeMessage == GDK_BUTTON_RELEASE) {
     GdkEvent event;
     memset(&event, 0, sizeof(GdkEvent));
     event.type = (GdkEventType)aNativeMessage;
     event.button.button = 1;
     event.button.window = mGdkWindow;
     event.button.time = GDK_CURRENT_TIME;
 
 #if (MOZ_WIDGET_GTK == 3)
     // Get device for event source
     GdkDeviceManager *device_manager = gdk_display_get_device_manager(display);
     event.button.device = gdk_device_manager_get_client_pointer(device_manager);
 #endif
 
+    event.button.x_root = DevicePixelsToGdkCoordRoundDown(aPoint.x);
+    event.button.y_root = DevicePixelsToGdkCoordRoundDown(aPoint.y);
+
+    LayoutDeviceIntPoint pointInWindow = aPoint - WidgetToScreenOffset();
+    event.button.x = DevicePixelsToGdkCoordRoundDown(pointInWindow.x);
+    event.button.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
+
     gdk_event_put(&event);
   } else {
-    // We don't support specific events other than button-release. In case
-    // aNativeMessage != GDK_BUTTON_RELEASE we'll synthesize a motion event
-    // that will be emitted by gdk_display_warp_pointer().
+    // We don't support specific events other than button-press/release. In all
+    // other cases we'll synthesize a motion event that will be emitted by
+    // gdk_display_warp_pointer().
     GdkScreen* screen = gdk_window_get_screen(mGdkWindow);
     GdkPoint point = DevicePixelsToGdkPointRoundDown(aPoint);
     gdk_display_warp_pointer(display, screen, point.x, point.y);
   }
 
   return NS_OK;
 }