Bug 1292070 - Part 2: Add API to synthesize mouse event with buttons. f=bevistseng, r=smaug
authorStone Shih <sshih@mozilla.com>
Thu, 18 Aug 2016 11:58:48 +0800
changeset 353444 4bd4a10213eb377f03b2ad982c81703a379c8faf
parent 353443 1689533031c3d0856da0ae9c858c83f41ab9e940
child 353445 fd3d0b6b7f71fc109715fe8f32382bea794a3f79
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1292070
milestone51.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 1292070 - Part 2: Add API to synthesize mouse event with buttons. f=bevistseng, r=smaug
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsDOMWindowUtils.h
dom/events/test/pointerevents/mochitest_support_external.js
dom/interfaces/base/nsIDOMWindowUtils.idl
gfx/layers/apz/util/APZCCallbackHelper.cpp
testing/mochitest/tests/SimpleTest/EventUtils.js
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8095,16 +8095,17 @@ nsContentUtils::SendKeyEvent(nsIWidget* 
 }
 
 nsresult
 nsContentUtils::SendMouseEvent(nsCOMPtr<nsIPresShell> aPresShell,
                                const nsAString& aType,
                                float aX,
                                float aY,
                                int32_t aButton,
+                               int32_t aButtons,
                                int32_t aClickCount,
                                int32_t aModifiers,
                                bool aIgnoreRootScrollFrame,
                                float aPressure,
                                unsigned short aInputSourceArg,
                                bool aToWindow,
                                bool *aPreventDefault,
                                bool aIsDOMEventSynthesized,
@@ -8145,17 +8146,19 @@ nsContentUtils::SendMouseEvent(nsCOMPtr<
   WidgetMouseEvent event(true, msg, widget,
                          aIsWidgetEventSynthesized ?
                            WidgetMouseEvent::eSynthesized :
                            WidgetMouseEvent::eReal,
                          contextMenuKey ? WidgetMouseEvent::eContextMenuKey :
                                           WidgetMouseEvent::eNormal);
   event.mModifiers = GetWidgetModifiers(aModifiers);
   event.button = aButton;
-  event.buttons = GetButtonsFlagForButton(aButton);
+  event.buttons = aButtons != nsIDOMWindowUtils::MOUSE_BUTTONS_NOT_SPECIFIED ?
+                  aButtons :
+                  msg == eMouseUp ? 0 : GetButtonsFlagForButton(aButton);
   event.pressure = aPressure;
   event.inputSource = aInputSourceArg;
   event.mClickCount = aClickCount;
   event.mTime = PR_IntervalNow();
   event.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized;
 
   nsPresContext* presContext = aPresShell->GetPresContext();
   if (!presContext)
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2549,16 +2549,17 @@ public:
    * Synthesize a mouse event to the given widget
    * (see nsIDOMWindowUtils.sendMouseEvent).
    */
   static nsresult SendMouseEvent(nsCOMPtr<nsIPresShell> aPresShell,
                                  const nsAString& aType,
                                  float aX,
                                  float aY,
                                  int32_t aButton,
+                                 int32_t aButtons,
                                  int32_t aClickCount,
                                  int32_t aModifiers,
                                  bool aIgnoreRootScrollFrame,
                                  float aPressure,
                                  unsigned short aInputSourceArg,
                                  bool aToWindow,
                                  bool *aPreventDefault,
                                  bool aIsDOMEventSynthesized,
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -645,72 +645,79 @@ nsDOMWindowUtils::SendMouseEvent(const n
                                  int32_t aButton,
                                  int32_t aClickCount,
                                  int32_t aModifiers,
                                  bool aIgnoreRootScrollFrame,
                                  float aPressure,
                                  unsigned short aInputSourceArg,
                                  bool aIsDOMEventSynthesized,
                                  bool aIsWidgetEventSynthesized,
+                                 int32_t aButtons,
                                  uint8_t aOptionalArgCount,
                                  bool *aPreventDefault)
 {
   return SendMouseEventCommon(aType, aX, aY, aButton, aClickCount, aModifiers,
                               aIgnoreRootScrollFrame, aPressure,
                               aInputSourceArg, false, aPreventDefault,
                               aOptionalArgCount >= 4 ?
                                 aIsDOMEventSynthesized : true,
                               aOptionalArgCount >= 5 ?
-                                aIsWidgetEventSynthesized : false);
+                                aIsWidgetEventSynthesized : false,
+                              aOptionalArgCount >= 6 ?
+                              aButtons : MOUSE_BUTTONS_NOT_SPECIFIED);
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendMouseEventToWindow(const nsAString& aType,
                                          float aX,
                                          float aY,
                                          int32_t aButton,
                                          int32_t aClickCount,
                                          int32_t aModifiers,
                                          bool aIgnoreRootScrollFrame,
                                          float aPressure,
                                          unsigned short aInputSourceArg,
                                          bool aIsDOMEventSynthesized,
                                          bool aIsWidgetEventSynthesized,
+                                         int32_t aButtons,
                                          uint8_t aOptionalArgCount)
 {
   PROFILER_LABEL("nsDOMWindowUtils", "SendMouseEventToWindow",
     js::ProfileEntry::Category::EVENTS);
 
   return SendMouseEventCommon(aType, aX, aY, aButton, aClickCount, aModifiers,
                               aIgnoreRootScrollFrame, aPressure,
                               aInputSourceArg, true, nullptr,
                               aOptionalArgCount >= 4 ?
                                 aIsDOMEventSynthesized : true,
                               aOptionalArgCount >= 5 ?
-                                aIsWidgetEventSynthesized : false);
+                                aIsWidgetEventSynthesized : false,
+                              aOptionalArgCount >= 6 ?
+                              aButtons : MOUSE_BUTTONS_NOT_SPECIFIED);
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendMouseEventCommon(const nsAString& aType,
                                        float aX,
                                        float aY,
                                        int32_t aButton,
                                        int32_t aClickCount,
                                        int32_t aModifiers,
                                        bool aIgnoreRootScrollFrame,
                                        float aPressure,
                                        unsigned short aInputSourceArg,
                                        bool aToWindow,
                                        bool *aPreventDefault,
                                        bool aIsDOMEventSynthesized,
-                                       bool aIsWidgetEventSynthesized)
+                                       bool aIsWidgetEventSynthesized,
+                                       int32_t aButtons)
 {
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   return nsContentUtils::SendMouseEvent(presShell, aType, aX, aY, aButton,
-      aClickCount, aModifiers, aIgnoreRootScrollFrame, aPressure,
+      aButtons, aClickCount, aModifiers, aIgnoreRootScrollFrame, aPressure,
       aInputSourceArg, aToWindow, aPreventDefault, aIsDOMEventSynthesized,
       aIsWidgetEventSynthesized);
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendPointerEventCommon(const nsAString& aType,
                                          float aX,
                                          float aY,
--- a/dom/base/nsDOMWindowUtils.h
+++ b/dom/base/nsDOMWindowUtils.h
@@ -89,17 +89,18 @@ protected:
                                   int32_t aClickCount,
                                   int32_t aModifiers,
                                   bool aIgnoreRootScrollFrame,
                                   float aPressure,
                                   unsigned short aInputSourceArg,
                                   bool aToWindow,
                                   bool *aPreventDefault,
                                   bool aIsDOMEventSynthesized,
-                                  bool aIsWidgetEventSynthesized);
+                                  bool aIsWidgetEventSynthesized,
+                                  int32_t aButtons);
 
   NS_IMETHOD SendPointerEventCommon(const nsAString& aType,
                                     float aX,
                                     float aY,
                                     int32_t aButton,
                                     int32_t aClickCount,
                                     int32_t aModifiers,
                                     bool aIgnoreRootScrollFrame,
--- a/dom/events/test/pointerevents/mochitest_support_external.js
+++ b/dom/events/test/pointerevents/mochitest_support_external.js
@@ -67,16 +67,18 @@ function sendMouseEvent(int_win, elemId,
   var elem = int_win.document.getElementById(elemId);
   if(!!elem) {
     var rect = elem.getBoundingClientRect();
     var eventObj = {type: mouseEventType};
     if(params && "button" in params)
       eventObj.button = params.button;
     if(params && "inputSource" in params)
       eventObj.inputSource = params.inputSource;
+    if(params && "buttons" in params)
+      eventObj.buttons = params.buttons;
     console.log(elemId, eventObj);
     synthesizeMouse(elem, rect.width/4, rect.height/2, eventObj, int_win);
   } else {
     is(!!elem, true, "Document should have element with id: " + elemId);
   }
 }
 
 // Helper function to send TouchEvent with different parameters
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -326,17 +326,18 @@ interface nsIDOMWindowUtils : nsISupport
                          in float aY,
                          in long aButton,
                          in long aClickCount,
                          in long aModifiers,
                          [optional] in boolean aIgnoreRootScrollFrame,
                          [optional] in float aPressure,
                          [optional] in unsigned short aInputSourceArg,
                          [optional] in boolean aIsDOMEventSynthesized,
-                         [optional] in boolean aIsWidgetEventSynthesized);
+                         [optional] in boolean aIsWidgetEventSynthesized,
+                         [optional] in long aButtons);
 
 
   /** Synthesize a pointer event. The event types supported are:
    *    pointerdown, pointerup, pointermove, pointerover, pointerout
    *
    * Events are sent in coordinates offset by aX and aY from the window.
    *
    * Note that additional events may be fired as a result of this call. For
@@ -446,17 +447,18 @@ interface nsIDOMWindowUtils : nsISupport
                               in float aY,
                               in long aButton,
                               in long aClickCount,
                               in long aModifiers,
                               [optional] in boolean aIgnoreRootScrollFrame,
                               [optional] in float aPressure,
                               [optional] in unsigned short aInputSourceArg,
                               [optional] in boolean aIsDOMEventSynthesized,
-                              [optional] in boolean aIsWidgetEventSynthesized);
+                              [optional] in boolean aIsWidgetEventSynthesized,
+                              [optional] in long aButtons);
 
   /** The same as sendPointerEvent but ensures that the event
    *  is dispatched to this DOM window or one of its children.
    */
   [optional_argc]
   void sendPointerEventToWindow(in AString aType,
                                 in float aX,
                                 in float aY,
@@ -1945,16 +1947,29 @@ interface nsIDOMWindowUtils : nsISupport
    */
   void respectDisplayPortSuppression(in boolean aEnabled);
 
   /**
    * Set a flag that forces the next reflow interrupt check to return true. This
    * can be used by tests to force execution of the interrupted reflow codepaths.
    */
   void forceReflowInterrupt();
+
+  const long MOUSE_BUTTONS_NO_BUTTON = 0x00;
+  const long MOUSE_BUTTONS_LEFT_BUTTON = 0x01;
+  const long MOUSE_BUTTONS_RIGHT_BUTTON = 0x02;
+  const long MOUSE_BUTTONS_MIDDLE_BUTTON = 0x04;
+  // Typically, "back" button being left side of 5-button
+  // mice, see "buttons" attribute document of DOM3 Events.
+  const long MOUSE_BUTTONS_4TH_BUTTON = 0x08;
+  // Typically, "forward" button being right side of 5-button
+  // mice, see "buttons" attribute document of DOM3 Events.
+  const long MOUSE_BUTTONS_5TH_BUTTON = 0x10;
+  // Buttons are not specified, will be calculated from |aButton|.
+  const long MOUSE_BUTTONS_NOT_SPECIFIED = -1;
 };
 
 [scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)]
 interface nsITranslationNodeList : nsISupports {
   readonly attribute unsigned long length;
   nsIDOMNode item(in unsigned long index);
 
   // A translation root is a block element, or an inline element
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -18,16 +18,17 @@
 #include "nsContentUtils.h"
 #include "nsContainerFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMWindow.h"
+#include "nsIDOMWindowUtils.h"
 #include "nsRefreshDriver.h"
 #include "nsString.h"
 #include "nsView.h"
 #include "Layers.h"
 
 #define APZCCH_LOG(...)
 // #define APZCCH_LOG(...) printf_stderr("APZCCH: " __VA_ARGS__)
 
@@ -509,19 +510,19 @@ APZCCallbackHelper::DispatchMouseEvent(c
                                        int32_t aModifiers,
                                        bool aIgnoreRootScrollFrame,
                                        unsigned short aInputSourceArg)
 {
   NS_ENSURE_TRUE(aPresShell, true);
 
   bool defaultPrevented = false;
   nsContentUtils::SendMouseEvent(aPresShell, aType, aPoint.x, aPoint.y,
-      aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, 0,
-      aInputSourceArg, false, &defaultPrevented, false,
-      /* aIsWidgetEventSynthesized = */ false);
+      aButton, nsIDOMWindowUtils::MOUSE_BUTTONS_NOT_SPECIFIED, aClickCount,
+      aModifiers, aIgnoreRootScrollFrame, 0, aInputSourceArg, false,
+      &defaultPrevented, false, /* aIsWidgetEventSynthesized = */ false);
   return defaultPrevented;
 }
 
 
 void
 APZCCallbackHelper::FireSingleTapEvent(const LayoutDevicePoint& aPoint,
                                        Modifiers aModifiers,
                                        nsIWidget* aWidget)
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -360,31 +360,33 @@ function synthesizeMouseAtPoint(left, to
     var clickCount = aEvent.clickCount || 1;
     var modifiers = _parseModifiers(aEvent, aWindow);
     var pressure = ("pressure" in aEvent) ? aEvent.pressure : 0;
     var inputSource = ("inputSource" in aEvent) ? aEvent.inputSource : 0;
     var isDOMEventSynthesized =
       ("isSynthesized" in aEvent) ? aEvent.isSynthesized : true;
     var isWidgetEventSynthesized =
       ("isWidgetEventSynthesized" in aEvent) ? aEvent.isWidgetEventSynthesized : false;
-
+    var buttons = ("buttons" in aEvent) ? aEvent.buttons :
+                                          utils.MOUSE_BUTTONS_NOT_SPECIFIED;
     if (("type" in aEvent) && aEvent.type) {
       defaultPrevented = utils.sendMouseEvent(aEvent.type, left, top, button,
                                               clickCount, modifiers, false,
                                               pressure, inputSource,
                                               isDOMEventSynthesized,
-                                              isWidgetEventSynthesized);
+                                              isWidgetEventSynthesized,
+                                              buttons);
     }
     else {
       utils.sendMouseEvent("mousedown", left, top, button, clickCount, modifiers,
                            false, pressure, inputSource, isDOMEventSynthesized,
-                           isWidgetEventSynthesized);
+                           isWidgetEventSynthesized, buttons);
       utils.sendMouseEvent("mouseup", left, top, button, clickCount, modifiers,
                            false, pressure, inputSource, isDOMEventSynthesized,
-                           isWidgetEventSynthesized);
+                           isWidgetEventSynthesized, buttons);
     }
   }
 
   return defaultPrevented;
 }
 
 function synthesizeTouchAtPoint(left, top, aEvent, aWindow = window)
 {