Bug 1339758, click() and similar can return 0 from various coordinate properties, r=masayuki
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Thu, 23 Mar 2017 12:57:44 +0200
changeset 397402 bec20d74d93a82d584804f5cce6019d23db57666
parent 397401 7dee6ff041fe99439e28aefa39c7ded8d3f530a3
child 397403 ad48fee41646a4f58e37954c42548b21aa150dcb
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki
bugs1339758
milestone55.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 1339758, click() and similar can return 0 from various coordinate properties, r=masayuki
dom/base/Element.cpp
dom/events/MouseEvent.cpp
dom/events/UIEvent.cpp
dom/events/test/mochitest.ini
dom/events/test/test_bug1339758.html
dom/html/nsGenericHTMLElement.cpp
widget/BasicEvents.h
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -2130,16 +2130,17 @@ Element::DispatchClickEvent(nsPresContex
   uint16_t inputSource = 0;
   WidgetMouseEvent* sourceMouseEvent = aSourceEvent->AsMouseEvent();
   if (sourceMouseEvent) {
     clickCount = sourceMouseEvent->mClickCount;
     pressure = sourceMouseEvent->pressure;
     pointerId = sourceMouseEvent->pointerId;
     inputSource = sourceMouseEvent->inputSource;
   } else if (aSourceEvent->mClass == eKeyboardEventClass) {
+    event.mFlags.mIsPositionless = true;
     inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
   }
   event.pressure = pressure;
   event.mClickCount = clickCount;
   event.pointerId = pointerId;
   event.inputSource = inputSource;
   event.mModifiers = aSourceEvent->mModifiers;
   if (aExtraEventFlags) {
--- a/dom/events/MouseEvent.cpp
+++ b/dom/events/MouseEvent.cpp
@@ -339,16 +339,20 @@ MouseEvent::GetScreenX(int32_t* aScreenX
   NS_ENSURE_ARG_POINTER(aScreenX);
   *aScreenX = ScreenX(CallerType::System);
   return NS_OK;
 }
 
 int32_t
 MouseEvent::ScreenX(CallerType aCallerType)
 {
+  if (mEvent->mFlags.mIsPositionless) {
+    return 0;
+  }
+
   if (nsContentUtils::ResistFingerprinting(aCallerType)) {
     // Sanitize to something sort of like client cooords, but not quite
     // (defaulting to (0,0) instead of our pre-specified client coords).
     return Event::GetClientCoords(mPresContext, mEvent, mEvent->mRefPoint,
                                   CSSIntPoint(0, 0)).x;
   }
 
   return Event::GetScreenCoords(mPresContext, mEvent, mEvent->mRefPoint).x;
@@ -360,16 +364,20 @@ MouseEvent::GetScreenY(int32_t* aScreenY
   NS_ENSURE_ARG_POINTER(aScreenY);
   *aScreenY = ScreenY(CallerType::System);
   return NS_OK;
 }
 
 int32_t
 MouseEvent::ScreenY(CallerType aCallerType)
 {
+  if (mEvent->mFlags.mIsPositionless) {
+    return 0;
+  }
+
   if (nsContentUtils::ResistFingerprinting(aCallerType)) {
     // Sanitize to something sort of like client cooords, but not quite
     // (defaulting to (0,0) instead of our pre-specified client coords).
     return Event::GetClientCoords(mPresContext, mEvent, mEvent->mRefPoint,
                                   CSSIntPoint(0, 0)).y;
   }
 
   return Event::GetScreenCoords(mPresContext, mEvent, mEvent->mRefPoint).y;
@@ -382,45 +390,59 @@ MouseEvent::GetClientX(int32_t* aClientX
   NS_ENSURE_ARG_POINTER(aClientX);
   *aClientX = ClientX();
   return NS_OK;
 }
 
 int32_t
 MouseEvent::ClientX()
 {
+  if (mEvent->mFlags.mIsPositionless) {
+    return 0;
+  }
+
   return Event::GetClientCoords(mPresContext, mEvent, mEvent->mRefPoint,
                                 mClientPoint).x;
 }
 
 NS_IMETHODIMP
 MouseEvent::GetClientY(int32_t* aClientY)
 {
   NS_ENSURE_ARG_POINTER(aClientY);
   *aClientY = ClientY();
   return NS_OK;
 }
 
 int32_t
 MouseEvent::ClientY()
 {
+  if (mEvent->mFlags.mIsPositionless) {
+    return 0;
+  }
+
   return Event::GetClientCoords(mPresContext, mEvent, mEvent->mRefPoint,
                                 mClientPoint).y;
 }
 
 int32_t
 MouseEvent::OffsetX()
 {
+  if (mEvent->mFlags.mIsPositionless) {
+    return 0;
+  }
   return Event::GetOffsetCoords(mPresContext, mEvent, mEvent->mRefPoint,
                                 mClientPoint).x;
 }
 
 int32_t
 MouseEvent::OffsetY()
 {
+  if (mEvent->mFlags.mIsPositionless) {
+    return 0;
+  }
   return Event::GetOffsetCoords(mPresContext, mEvent, mEvent->mRefPoint,
                                 mClientPoint).y;
 }
 
 bool
 MouseEvent::AltKey()
 {
   return mEvent->AsInputEvent()->IsAlt();
--- a/dom/events/UIEvent.cpp
+++ b/dom/events/UIEvent.cpp
@@ -110,16 +110,20 @@ DevPixelsToCSSPixels(const LayoutDeviceI
 {
   return nsIntPoint(aContext->DevPixelsToIntCSSPixels(aPoint.x),
                     aContext->DevPixelsToIntCSSPixels(aPoint.y));
 }
 
 nsIntPoint
 UIEvent::GetMovementPoint()
 {
+  if (mEvent->mFlags.mIsPositionless) {
+    return nsIntPoint(0, 0);
+  }
+
   if (mPrivateDataDuplicated || mEventIsInternal) {
     return mMovementPoint;
   }
 
   if (!mEvent ||
       (mEvent->mClass != eMouseEventClass &&
        mEvent->mClass != eMouseScrollEventClass &&
        mEvent->mClass != eWheelEventClass &&
@@ -186,16 +190,20 @@ UIEvent::GetPageX(int32_t* aPageX)
   NS_ENSURE_ARG_POINTER(aPageX);
   *aPageX = PageX();
   return NS_OK;
 }
 
 int32_t
 UIEvent::PageX() const
 {
+  if (mEvent->mFlags.mIsPositionless) {
+    return 0;
+  }
+
   if (mPrivateDataDuplicated) {
     return mPagePoint.x;
   }
 
   return Event::GetPageCoords(mPresContext, mEvent, mEvent->mRefPoint,
                               mClientPoint).x;
 }
 
@@ -205,16 +213,20 @@ UIEvent::GetPageY(int32_t* aPageY)
   NS_ENSURE_ARG_POINTER(aPageY);
   *aPageY = PageY();
   return NS_OK;
 }
 
 int32_t
 UIEvent::PageY() const
 {
+  if (mEvent->mFlags.mIsPositionless) {
+    return 0;
+  }
+
   if (mPrivateDataDuplicated) {
     return mPagePoint.y;
   }
 
   return Event::GetPageCoords(mPresContext, mEvent, mEvent->mRefPoint,
                               mClientPoint).y;
 }
 
@@ -286,16 +298,20 @@ UIEvent::RangeOffset() const
   nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent,
                                                             targetFrame);
   return targetFrame->GetContentOffsetsFromPoint(pt).offset;
 }
 
 nsIntPoint
 UIEvent::GetLayerPoint() const
 {
+  if (mEvent->mFlags.mIsPositionless) {
+    return nsIntPoint(0, 0);
+  }
+
   if (!mEvent ||
       (mEvent->mClass != eMouseEventClass &&
        mEvent->mClass != eMouseScrollEventClass &&
        mEvent->mClass != eWheelEventClass &&
        mEvent->mClass != ePointerEventClass &&
        mEvent->mClass != eTouchEventClass &&
        mEvent->mClass != eDragEventClass &&
        mEvent->mClass != eSimpleGestureEventClass) ||
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -171,9 +171,10 @@ skip-if = toolkit == 'android' #CRASH_DU
 [test_passive_listeners.html]
 [test_paste_image.html]
 [test_wheel_default_action.html]
 [test_bug687787.html]
 [test_bug1305458.html]
 [test_bug1298970.html]
 [test_bug1304044.html]
 [test_bug1332699.html]
+[test_bug1339758.html]
 [test_dnd_with_modifiers.html]
new file mode 100644
--- /dev/null
+++ b/dom/events/test/test_bug1339758.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1339758
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1339758</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 1339758 **/
+  var expectNonZeroCoordinates = false;
+  SimpleTest.waitForExplicitFinish();
+
+  function testCoordinates(e) {
+   var coordinateProperties =
+     [ "screenX",
+       "screenY",
+       "clientX",
+       "clientY",
+       "offsetX",
+       "offsetY",
+       "movementX",
+       "movementY",
+       "layerX",
+       "layerY",
+       "x",
+       "y" ];
+    for (var i in coordinateProperties) {
+      if (e[coordinateProperties[i]] != 0) {
+        ok(expectNonZeroCoordinates, e.target.id + " got at least some non-zero coordinate property: " + i);
+        return;
+      }
+    }
+    ok(!expectNonZeroCoordinates, "Non-zero coordinates weren't expected");
+  }
+
+  function runTests() {
+    info("Testing click events which should have only 0 coordinates.");
+    document.getElementById("div_target").click();
+    document.getElementById("a_target").focus();
+    sendKey("RETURN");
+    document.getElementById("input_target").focus();
+    sendKey("RETURN");
+
+    info("Testing click events which should have also non-zero coordinates.");
+    expectNonZeroCoordinates = true;
+    // Test script created MouseEvents
+    sendMouseEvent({ type: "click"}, document.getElementById("a_target"));
+    sendMouseEvent({ type: "click"}, document.getElementById("input_target"));
+
+    // Test widget level mouse events
+    synthesizeMouse(document.getElementById("a_target"), 2, 2, {});
+    synthesizeMouse(document.getElementById("input_target"), 2, 2, {});
+    SimpleTest.finish();
+  }
+
+  SimpleTest.waitForFocus(runTests);
+
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1339758">Mozilla Bug 1339758</a>
+<p id="display"></p>
+
+<div id="div_target" onclick="testCoordinates(event)">&nbsp;</div>
+<a href="#" id="a_target" onclick="testCoordinates(event);">test link</a><br>
+<input type="button" id="input_target" onclick="testCoordinates(event);" value="test button">
+
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -2432,16 +2432,17 @@ nsGenericHTMLElement::Click(CallerType a
     }
   }
 
   SetHandlingClick();
 
   // Mark this event trusted if Click() is called from system code.
   WidgetMouseEvent event(aCallerType == CallerType::System,
                          eMouseClick, nullptr, WidgetMouseEvent::eReal);
+  event.mFlags.mIsPositionless = true;
   event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
 
   EventDispatcher::Dispatch(static_cast<nsIContent*>(this), context, &event);
 
   ClearHandlingClick();
 }
 
 bool
@@ -2556,16 +2557,17 @@ nsGenericHTMLElement::PerformAccesskey(b
 nsresult
 nsGenericHTMLElement::DispatchSimulatedClick(nsGenericHTMLElement* aElement,
                                              bool aIsTrusted,
                                              nsPresContext* aPresContext)
 {
   WidgetMouseEvent event(aIsTrusted, eMouseClick, nullptr,
                          WidgetMouseEvent::eReal);
   event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
+  event.mFlags.mIsPositionless = true;
   return EventDispatcher::Dispatch(ToSupports(aElement), aPresContext, &event);
 }
 
 nsresult
 nsGenericHTMLElement::GetEditor(nsIEditor** aEditor)
 {
   NS_IF_ADDREF(*aEditor = GetEditorInternal());
   return NS_OK;
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -134,16 +134,19 @@ public:
   bool mComposedInNativeAnonymousContent : 1;
   // Set to true for events which are suppressed or delayed so that later a
   // DelayedEvent of it is dispatched. This is used when parent side process
   // the key event after content side, and may drop the event if the event
   // was suppressed or delayed in contents side.
   // It is also set to true for the events (in a DelayedInputEvent), which will
   // be dispatched afterwards.
   bool mIsSuppressedOrDelayed : 1;
+  // Certain mouse events can be marked as positionless to return 0 from
+  // coordinate related getters.
+  bool mIsPositionless : 1;
 
   // If the event is being handled in target phase, returns true.
   inline bool InTargetPhase() const
   {
     return (mInBubblingPhase && mInCapturePhase);
   }
 
   /**