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"
15 namespace mozilla::dom
{
17 MouseEvent::MouseEvent(EventTarget
* aOwner
, nsPresContext
* aPresContext
,
18 WidgetMouseEventBase
* aEvent
)
19 : UIEvent(aOwner
, aPresContext
,
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
27 WidgetMouseEvent
* mouseEvent
= mEvent
->AsMouseEvent();
29 mEventIsInternal
= false;
31 mEventIsInternal
= true;
32 mEvent
->mRefPoint
= LayoutDeviceIntPoint(0, 0);
33 mouseEvent
->mInputSource
= MouseEvent_Binding::MOZ_SOURCE_UNKNOWN
;
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
:
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
,
66 mDefaultClientPoint
.x
= aClientX
;
67 mDefaultClientPoint
.y
= aClientY
;
68 mouseEventBase
->mRefPoint
.x
= aScreenX
;
69 mouseEventBase
->mRefPoint
.y
= aScreenY
;
71 WidgetMouseEvent
* mouseEvent
= mEvent
->AsMouseEvent();
73 mouseEvent
->mClickCount
= aDetail
;
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
);
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
;
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
);
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
,
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
;
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
;
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
;
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
;
215 return EnsureWebAccessibleRelatedTarget(relatedTarget
);
218 CSSIntPoint
MouseEvent::ScreenPoint(CallerType aCallerType
) const {
219 if (mEvent
->mFlags
.mIsPositionless
) {
223 if (nsContentUtils::ShouldResistFingerprinting(
224 aCallerType
, GetParentObject(), RFPTarget::MouseEventScreenPoint
)) {
225 // Sanitize to something sort of like client cooords, but not quite
226 // (defaulting to (0,0) instead of our pre-specified client coords).
227 return Event::GetClientCoords(mPresContext
, mEvent
, mEvent
->mRefPoint
,
231 return Event::GetScreenCoords(mPresContext
, mEvent
, mEvent
->mRefPoint
)
235 LayoutDeviceIntPoint
MouseEvent::ScreenPointLayoutDevicePix() const {
236 const CSSIntPoint point
= ScreenPoint(CallerType::System
);
237 auto scale
= mPresContext
? mPresContext
->CSSToDevPixelScale()
238 : CSSToLayoutDeviceScale();
239 return LayoutDeviceIntPoint::Round(point
* scale
);
242 DesktopIntPoint
MouseEvent::ScreenPointDesktopPix() const {
243 const CSSIntPoint point
= ScreenPoint(CallerType::System
);
246 ? mPresContext
->CSSToDevPixelScale() /
247 mPresContext
->DeviceContext()->GetDesktopToDeviceScale()
248 : CSSToDesktopScale();
249 return DesktopIntPoint::Round(point
* scale
);
252 already_AddRefed
<nsIScreen
> MouseEvent::GetScreen() {
253 nsCOMPtr
<nsIScreenManager
> screenMgr
=
254 do_GetService("@mozilla.org/gfx/screenmanager;1");
258 return screenMgr
->ScreenForRect(
259 DesktopIntRect(ScreenPointDesktopPix(), DesktopIntSize(1, 1)));
262 CSSIntPoint
MouseEvent::PagePoint() const {
263 if (mEvent
->mFlags
.mIsPositionless
) {
267 if (mPrivateDataDuplicated
) {
271 return Event::GetPageCoords(mPresContext
, mEvent
, mEvent
->mRefPoint
,
272 mDefaultClientPoint
);
275 CSSIntPoint
MouseEvent::ClientPoint() const {
276 if (mEvent
->mFlags
.mIsPositionless
) {
280 return Event::GetClientCoords(mPresContext
, mEvent
, mEvent
->mRefPoint
,
281 mDefaultClientPoint
);
284 CSSIntPoint
MouseEvent::OffsetPoint() const {
285 if (mEvent
->mFlags
.mIsPositionless
) {
289 return Event::GetOffsetCoords(mPresContext
, mEvent
, mEvent
->mRefPoint
,
290 mDefaultClientPoint
);
293 bool MouseEvent::AltKey() { return mEvent
->AsInputEvent()->IsAlt(); }
295 bool MouseEvent::CtrlKey() { return mEvent
->AsInputEvent()->IsControl(); }
297 bool MouseEvent::ShiftKey() { return mEvent
->AsInputEvent()->IsShift(); }
299 bool MouseEvent::MetaKey() { return mEvent
->AsInputEvent()->IsMeta(); }
301 float MouseEvent::MozPressure() const {
302 return mEvent
->AsMouseEventBase()->mPressure
;
305 uint16_t MouseEvent::InputSource() const {
306 return mEvent
->AsMouseEventBase()->mInputSource
;
309 } // namespace mozilla::dom
311 using namespace mozilla
;
312 using namespace mozilla::dom
;
314 already_AddRefed
<MouseEvent
> NS_NewDOMMouseEvent(EventTarget
* aOwner
,
315 nsPresContext
* aPresContext
,
316 WidgetMouseEvent
* aEvent
) {
317 RefPtr
<MouseEvent
> it
= new MouseEvent(aOwner
, aPresContext
, aEvent
);