Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / dom / events / MouseEvent.cpp
blobcf5a3120c5a35f93a33f31b5a5638350f204f8f4
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/MouseEvent.h"
8 #include "mozilla/MouseEvents.h"
9 #include "mozilla/BasePrincipal.h"
10 #include "nsContentUtils.h"
11 #include "nsIContent.h"
12 #include "nsIScreenManager.h"
13 #include "prtime.h"
15 namespace mozilla::dom {
17 MouseEvent::MouseEvent(EventTarget* aOwner, nsPresContext* aPresContext,
18 WidgetMouseEventBase* aEvent)
19 : UIEvent(aOwner, aPresContext,
20 aEvent ? aEvent
21 : new WidgetMouseEvent(false, eVoidEvent, nullptr,
22 WidgetMouseEvent::eReal)) {
23 // There's no way to make this class' ctor allocate an WidgetMouseScrollEvent.
24 // It's not that important, though, since a scroll event is not a real
25 // DOM event.
27 WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent();
28 if (aEvent) {
29 mEventIsInternal = false;
30 } else {
31 mEventIsInternal = true;
32 mEvent->mRefPoint = LayoutDeviceIntPoint(0, 0);
33 mouseEvent->mInputSource = MouseEvent_Binding::MOZ_SOURCE_UNKNOWN;
36 if (mouseEvent) {
37 MOZ_ASSERT(mouseEvent->mReason != WidgetMouseEvent::eSynthesized,
38 "Don't dispatch DOM events from synthesized mouse events");
39 mDetail = mouseEvent->mClickCount;
43 void MouseEvent::InitMouseEvent(const nsAString& aType, bool aCanBubble,
44 bool aCancelable, nsGlobalWindowInner* aView,
45 int32_t aDetail, int32_t aScreenX,
46 int32_t aScreenY, int32_t aClientX,
47 int32_t aClientY, bool aCtrlKey, bool aAltKey,
48 bool aShiftKey, bool aMetaKey, uint16_t aButton,
49 EventTarget* aRelatedTarget) {
50 NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
52 UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
54 switch (mEvent->mClass) {
55 case eMouseEventClass:
56 case eMouseScrollEventClass:
57 case eWheelEventClass:
58 case eDragEventClass:
59 case ePointerEventClass:
60 case eSimpleGestureEventClass: {
61 WidgetMouseEventBase* mouseEventBase = mEvent->AsMouseEventBase();
62 mouseEventBase->mRelatedTarget = aRelatedTarget;
63 mouseEventBase->mButton = aButton;
64 mouseEventBase->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey,
65 aMetaKey);
66 mDefaultClientPoint.x = aClientX;
67 mDefaultClientPoint.y = aClientY;
68 mouseEventBase->mRefPoint.x = aScreenX;
69 mouseEventBase->mRefPoint.y = aScreenY;
71 WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent();
72 if (mouseEvent) {
73 mouseEvent->mClickCount = aDetail;
75 break;
77 default:
78 break;
82 void MouseEvent::InitMouseEvent(const nsAString& aType, bool aCanBubble,
83 bool aCancelable, nsGlobalWindowInner* aView,
84 int32_t aDetail, int32_t aScreenX,
85 int32_t aScreenY, int32_t aClientX,
86 int32_t aClientY, int16_t aButton,
87 EventTarget* aRelatedTarget,
88 const nsAString& aModifiersList) {
89 NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
91 Modifiers modifiers = ComputeModifierState(aModifiersList);
93 InitMouseEvent(
94 aType, aCanBubble, aCancelable, aView, aDetail, aScreenX, aScreenY,
95 aClientX, aClientY, (modifiers & MODIFIER_CONTROL) != 0,
96 (modifiers & MODIFIER_ALT) != 0, (modifiers & MODIFIER_SHIFT) != 0,
97 (modifiers & MODIFIER_META) != 0, aButton, aRelatedTarget);
99 switch (mEvent->mClass) {
100 case eMouseEventClass:
101 case eMouseScrollEventClass:
102 case eWheelEventClass:
103 case eDragEventClass:
104 case ePointerEventClass:
105 case eSimpleGestureEventClass:
106 mEvent->AsInputEvent()->mModifiers = modifiers;
107 return;
108 default:
109 MOZ_CRASH("There is no space to store the modifiers");
113 void MouseEvent::InitializeExtraMouseEventDictionaryMembers(
114 const MouseEventInit& aParam) {
115 InitModifiers(aParam);
116 mEvent->AsMouseEventBase()->mButtons = aParam.mButtons;
117 mMovementPoint.x = aParam.mMovementX;
118 mMovementPoint.y = aParam.mMovementY;
121 already_AddRefed<MouseEvent> MouseEvent::Constructor(
122 const GlobalObject& aGlobal, const nsAString& aType,
123 const MouseEventInit& aParam) {
124 nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
125 RefPtr<MouseEvent> e = new MouseEvent(t, nullptr, nullptr);
126 bool trusted = e->Init(t);
127 e->InitMouseEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
128 aParam.mDetail, aParam.mScreenX, aParam.mScreenY,
129 aParam.mClientX, aParam.mClientY, aParam.mCtrlKey,
130 aParam.mAltKey, aParam.mShiftKey, aParam.mMetaKey,
131 aParam.mButton, aParam.mRelatedTarget);
132 e->InitializeExtraMouseEventDictionaryMembers(aParam);
133 e->SetTrusted(trusted);
134 e->SetComposed(aParam.mComposed);
135 return e.forget();
138 void MouseEvent::InitNSMouseEvent(const nsAString& aType, bool aCanBubble,
139 bool aCancelable, nsGlobalWindowInner* aView,
140 int32_t aDetail, int32_t aScreenX,
141 int32_t aScreenY, int32_t aClientX,
142 int32_t aClientY, bool aCtrlKey, bool aAltKey,
143 bool aShiftKey, bool aMetaKey,
144 uint16_t aButton, EventTarget* aRelatedTarget,
145 float aPressure, uint16_t aInputSource) {
146 NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
148 MouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView, aDetail,
149 aScreenX, aScreenY, aClientX, aClientY, aCtrlKey,
150 aAltKey, aShiftKey, aMetaKey, aButton,
151 aRelatedTarget);
153 WidgetMouseEventBase* mouseEventBase = mEvent->AsMouseEventBase();
154 mouseEventBase->mPressure = aPressure;
155 mouseEventBase->mInputSource = aInputSource;
158 void MouseEvent::PreventClickEvent() {
159 if (WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent()) {
160 mouseEvent->mClickEventPrevented = true;
164 bool MouseEvent::ClickEventPrevented() {
165 if (WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent()) {
166 return mouseEvent->mClickEventPrevented;
168 return false;
171 int16_t MouseEvent::Button() {
172 switch (mEvent->mClass) {
173 case eMouseEventClass:
174 case eMouseScrollEventClass:
175 case eWheelEventClass:
176 case eDragEventClass:
177 case ePointerEventClass:
178 case eSimpleGestureEventClass:
179 return mEvent->AsMouseEventBase()->mButton;
180 default:
181 NS_WARNING("Tried to get mouse mButton for non-mouse event!");
182 return MouseButton::ePrimary;
186 uint16_t MouseEvent::Buttons() {
187 switch (mEvent->mClass) {
188 case eMouseEventClass:
189 case eMouseScrollEventClass:
190 case eWheelEventClass:
191 case eDragEventClass:
192 case ePointerEventClass:
193 case eSimpleGestureEventClass:
194 return mEvent->AsMouseEventBase()->mButtons;
195 default:
196 MOZ_CRASH("Tried to get mouse buttons for non-mouse event!");
200 already_AddRefed<EventTarget> MouseEvent::GetRelatedTarget() {
201 nsCOMPtr<EventTarget> relatedTarget;
202 switch (mEvent->mClass) {
203 case eMouseEventClass:
204 case eMouseScrollEventClass:
205 case eWheelEventClass:
206 case eDragEventClass:
207 case ePointerEventClass:
208 case eSimpleGestureEventClass:
209 relatedTarget = mEvent->AsMouseEventBase()->mRelatedTarget;
210 break;
211 default:
212 break;
215 return EnsureWebAccessibleRelatedTarget(relatedTarget);
218 void MouseEvent::GetRegion(nsAString& aRegion) { SetDOMStringToNull(aRegion); }
220 CSSIntPoint MouseEvent::ScreenPoint(CallerType aCallerType) const {
221 if (mEvent->mFlags.mIsPositionless) {
222 return {};
225 if (nsContentUtils::ShouldResistFingerprinting(
226 aCallerType, GetParentObject(), RFPTarget::MouseEventScreenPoint)) {
227 // Sanitize to something sort of like client cooords, but not quite
228 // (defaulting to (0,0) instead of our pre-specified client coords).
229 return Event::GetClientCoords(mPresContext, mEvent, mEvent->mRefPoint,
230 CSSIntPoint(0, 0));
233 return Event::GetScreenCoords(mPresContext, mEvent, mEvent->mRefPoint)
234 .extract();
237 LayoutDeviceIntPoint MouseEvent::ScreenPointLayoutDevicePix() const {
238 const CSSIntPoint point = ScreenPoint(CallerType::System);
239 auto scale = mPresContext ? mPresContext->CSSToDevPixelScale()
240 : CSSToLayoutDeviceScale();
241 return LayoutDeviceIntPoint::Round(point * scale);
244 DesktopIntPoint MouseEvent::ScreenPointDesktopPix() const {
245 const CSSIntPoint point = ScreenPoint(CallerType::System);
246 auto scale =
247 mPresContext
248 ? mPresContext->CSSToDevPixelScale() /
249 mPresContext->DeviceContext()->GetDesktopToDeviceScale()
250 : CSSToDesktopScale();
251 return DesktopIntPoint::Round(point * scale);
254 already_AddRefed<nsIScreen> MouseEvent::GetScreen() {
255 nsCOMPtr<nsIScreenManager> screenMgr =
256 do_GetService("@mozilla.org/gfx/screenmanager;1");
257 if (!screenMgr) {
258 return nullptr;
260 return screenMgr->ScreenForRect(
261 DesktopIntRect(ScreenPointDesktopPix(), DesktopIntSize(1, 1)));
264 CSSIntPoint MouseEvent::PagePoint() const {
265 if (mEvent->mFlags.mIsPositionless) {
266 return {};
269 if (mPrivateDataDuplicated) {
270 return mPagePoint;
273 return Event::GetPageCoords(mPresContext, mEvent, mEvent->mRefPoint,
274 mDefaultClientPoint);
277 CSSIntPoint MouseEvent::ClientPoint() const {
278 if (mEvent->mFlags.mIsPositionless) {
279 return {};
282 return Event::GetClientCoords(mPresContext, mEvent, mEvent->mRefPoint,
283 mDefaultClientPoint);
286 CSSIntPoint MouseEvent::OffsetPoint() const {
287 if (mEvent->mFlags.mIsPositionless) {
288 return {};
291 return Event::GetOffsetCoords(mPresContext, mEvent, mEvent->mRefPoint,
292 mDefaultClientPoint);
295 bool MouseEvent::AltKey() { return mEvent->AsInputEvent()->IsAlt(); }
297 bool MouseEvent::CtrlKey() { return mEvent->AsInputEvent()->IsControl(); }
299 bool MouseEvent::ShiftKey() { return mEvent->AsInputEvent()->IsShift(); }
301 bool MouseEvent::MetaKey() { return mEvent->AsInputEvent()->IsMeta(); }
303 float MouseEvent::MozPressure() const {
304 return mEvent->AsMouseEventBase()->mPressure;
307 uint16_t MouseEvent::MozInputSource() const {
308 return mEvent->AsMouseEventBase()->mInputSource;
311 } // namespace mozilla::dom
313 using namespace mozilla;
315 void WidgetDragEvent::UpdateDefaultPreventedOnContent(
316 dom::EventTarget* aTarget) {
317 MOZ_ASSERT(DefaultPrevented());
318 nsIPrincipal* principal = nullptr;
319 nsINode* node = nsINode::FromEventTargetOrNull(aTarget);
320 if (node) {
321 principal = node->NodePrincipal();
322 } else {
323 nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aTarget);
324 if (sop) {
325 principal = sop->GetPrincipal();
328 if (principal && !principal->IsSystemPrincipal()) {
329 mDefaultPreventedOnContent = true;
333 using namespace mozilla::dom;
335 already_AddRefed<MouseEvent> NS_NewDOMMouseEvent(EventTarget* aOwner,
336 nsPresContext* aPresContext,
337 WidgetMouseEvent* aEvent) {
338 RefPtr<MouseEvent> it = new MouseEvent(aOwner, aPresContext, aEvent);
339 return it.forget();