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 * Portions Copyright 2013 Microsoft Open Technologies, Inc. */
9 #include "mozilla/dom/MouseEventBinding.h"
10 #include "mozilla/dom/PointerEvent.h"
11 #include "mozilla/dom/PointerEventBinding.h"
12 #include "mozilla/dom/PointerEventHandler.h"
13 #include "mozilla/MouseEvents.h"
14 #include "nsContentUtils.h"
17 namespace mozilla::dom
{
19 PointerEvent::PointerEvent(EventTarget
* aOwner
, nsPresContext
* aPresContext
,
20 WidgetPointerEvent
* aEvent
)
21 : MouseEvent(aOwner
, aPresContext
,
23 : new WidgetPointerEvent(false, eVoidEvent
, nullptr)) {
24 NS_ASSERTION(mEvent
->mClass
== ePointerEventClass
,
25 "event type mismatch ePointerEventClass");
27 WidgetMouseEvent
* mouseEvent
= mEvent
->AsMouseEvent();
29 mEventIsInternal
= false;
31 mEventIsInternal
= true;
32 mEvent
->mTime
= PR_Now();
33 mEvent
->mRefPoint
= LayoutDeviceIntPoint(0, 0);
34 mouseEvent
->mInputSource
= MouseEvent_Binding::MOZ_SOURCE_UNKNOWN
;
36 // 5.2 Pointer Event types, for all pointer events, |detail| attribute SHOULD
41 JSObject
* PointerEvent::WrapObjectInternal(JSContext
* aCx
,
42 JS::Handle
<JSObject
*> aGivenProto
) {
43 return PointerEvent_Binding::Wrap(aCx
, this, aGivenProto
);
46 static uint16_t ConvertStringToPointerType(const nsAString
& aPointerTypeArg
) {
47 if (aPointerTypeArg
.EqualsLiteral("mouse")) {
48 return MouseEvent_Binding::MOZ_SOURCE_MOUSE
;
50 if (aPointerTypeArg
.EqualsLiteral("pen")) {
51 return MouseEvent_Binding::MOZ_SOURCE_PEN
;
53 if (aPointerTypeArg
.EqualsLiteral("touch")) {
54 return MouseEvent_Binding::MOZ_SOURCE_TOUCH
;
57 return MouseEvent_Binding::MOZ_SOURCE_UNKNOWN
;
60 void ConvertPointerTypeToString(uint16_t aPointerTypeSrc
,
61 nsAString
& aPointerTypeDest
) {
62 switch (aPointerTypeSrc
) {
63 case MouseEvent_Binding::MOZ_SOURCE_MOUSE
:
64 aPointerTypeDest
.AssignLiteral("mouse");
66 case MouseEvent_Binding::MOZ_SOURCE_PEN
:
67 aPointerTypeDest
.AssignLiteral("pen");
69 case MouseEvent_Binding::MOZ_SOURCE_TOUCH
:
70 aPointerTypeDest
.AssignLiteral("touch");
73 aPointerTypeDest
.Truncate();
79 already_AddRefed
<PointerEvent
> PointerEvent::Constructor(
80 EventTarget
* aOwner
, const nsAString
& aType
,
81 const PointerEventInit
& aParam
) {
82 RefPtr
<PointerEvent
> e
= new PointerEvent(aOwner
, nullptr, nullptr);
83 bool trusted
= e
->Init(aOwner
);
85 e
->InitMouseEvent(aType
, aParam
.mBubbles
, aParam
.mCancelable
, aParam
.mView
,
86 aParam
.mDetail
, aParam
.mScreenX
, aParam
.mScreenY
,
87 aParam
.mClientX
, aParam
.mClientY
, false, false, false,
88 false, aParam
.mButton
, aParam
.mRelatedTarget
);
89 e
->InitializeExtraMouseEventDictionaryMembers(aParam
);
91 WidgetPointerEvent
* widgetEvent
= e
->mEvent
->AsPointerEvent();
92 widgetEvent
->pointerId
= aParam
.mPointerId
;
93 widgetEvent
->mWidth
= aParam
.mWidth
;
94 widgetEvent
->mHeight
= aParam
.mHeight
;
95 widgetEvent
->mPressure
= aParam
.mPressure
;
96 widgetEvent
->tangentialPressure
= aParam
.mTangentialPressure
;
97 widgetEvent
->tiltX
= aParam
.mTiltX
;
98 widgetEvent
->tiltY
= aParam
.mTiltY
;
99 widgetEvent
->twist
= aParam
.mTwist
;
100 widgetEvent
->mInputSource
= ConvertStringToPointerType(aParam
.mPointerType
);
101 widgetEvent
->mIsPrimary
= aParam
.mIsPrimary
;
102 widgetEvent
->mButtons
= aParam
.mButtons
;
104 if (!aParam
.mCoalescedEvents
.IsEmpty()) {
105 e
->mCoalescedEvents
.AppendElements(aParam
.mCoalescedEvents
);
107 e
->SetTrusted(trusted
);
108 e
->SetComposed(aParam
.mComposed
);
113 already_AddRefed
<PointerEvent
> PointerEvent::Constructor(
114 const GlobalObject
& aGlobal
, const nsAString
& aType
,
115 const PointerEventInit
& aParam
) {
116 nsCOMPtr
<EventTarget
> owner
= do_QueryInterface(aGlobal
.GetAsSupports());
117 return Constructor(owner
, aType
, aParam
);
120 NS_IMPL_CYCLE_COLLECTION_CLASS(PointerEvent
)
122 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PointerEvent
, MouseEvent
)
123 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCoalescedEvents
)
124 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
126 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PointerEvent
, MouseEvent
)
127 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCoalescedEvents
)
128 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
130 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PointerEvent
)
131 NS_INTERFACE_MAP_END_INHERITING(MouseEvent
)
133 NS_IMPL_ADDREF_INHERITED(PointerEvent
, MouseEvent
)
134 NS_IMPL_RELEASE_INHERITED(PointerEvent
, MouseEvent
)
136 void PointerEvent::GetPointerType(nsAString
& aPointerType
,
137 CallerType aCallerType
) {
138 if (ShouldResistFingerprinting(aCallerType
)) {
139 aPointerType
.AssignLiteral("mouse");
143 ConvertPointerTypeToString(mEvent
->AsPointerEvent()->mInputSource
,
147 int32_t PointerEvent::PointerId(CallerType aCallerType
) {
148 return ShouldResistFingerprinting(aCallerType
)
149 ? PointerEventHandler::GetSpoofedPointerIdForRFP()
150 : mEvent
->AsPointerEvent()->pointerId
;
153 int32_t PointerEvent::Width(CallerType aCallerType
) {
154 return ShouldResistFingerprinting(aCallerType
)
156 : mEvent
->AsPointerEvent()->mWidth
;
159 int32_t PointerEvent::Height(CallerType aCallerType
) {
160 return ShouldResistFingerprinting(aCallerType
)
162 : mEvent
->AsPointerEvent()->mHeight
;
165 float PointerEvent::Pressure(CallerType aCallerType
) {
166 if (mEvent
->mMessage
== ePointerUp
||
167 !ShouldResistFingerprinting(aCallerType
)) {
168 return mEvent
->AsPointerEvent()->mPressure
;
171 // According to [1], we should use 0.5 when it is in active buttons state and
172 // 0 otherwise for devices that don't support pressure. And a pointerup event
173 // always reports 0, so we don't need to spoof that.
175 // [1] https://www.w3.org/TR/pointerevents/#dom-pointerevent-pressure
176 float spoofedPressure
= 0.0;
177 if (mEvent
->AsPointerEvent()->mButtons
) {
178 spoofedPressure
= 0.5;
181 return spoofedPressure
;
184 float PointerEvent::TangentialPressure(CallerType aCallerType
) {
185 return ShouldResistFingerprinting(aCallerType
)
187 : mEvent
->AsPointerEvent()->tangentialPressure
;
190 int32_t PointerEvent::TiltX(CallerType aCallerType
) {
191 return ShouldResistFingerprinting(aCallerType
)
193 : mEvent
->AsPointerEvent()->tiltX
;
196 int32_t PointerEvent::TiltY(CallerType aCallerType
) {
197 return ShouldResistFingerprinting(aCallerType
)
199 : mEvent
->AsPointerEvent()->tiltY
;
202 int32_t PointerEvent::Twist(CallerType aCallerType
) {
203 return ShouldResistFingerprinting(aCallerType
)
205 : mEvent
->AsPointerEvent()->twist
;
208 bool PointerEvent::IsPrimary() { return mEvent
->AsPointerEvent()->mIsPrimary
; }
210 void PointerEvent::GetCoalescedEvents(
211 nsTArray
<RefPtr
<PointerEvent
>>& aPointerEvents
) {
212 WidgetPointerEvent
* widgetEvent
= mEvent
->AsPointerEvent();
213 if (mCoalescedEvents
.IsEmpty() && widgetEvent
&&
214 widgetEvent
->mCoalescedWidgetEvents
&&
215 !widgetEvent
->mCoalescedWidgetEvents
->mEvents
.IsEmpty()) {
216 nsCOMPtr
<EventTarget
> owner
= do_QueryInterface(mOwner
);
217 for (WidgetPointerEvent
& event
:
218 widgetEvent
->mCoalescedWidgetEvents
->mEvents
) {
219 RefPtr
<PointerEvent
> domEvent
=
220 NS_NewDOMPointerEvent(owner
, nullptr, &event
);
222 // The dom event is derived from an OS generated widget event. Setup
223 // mWidget and mPresContext since they are necessary to calculate
224 // offsetX / offsetY.
225 domEvent
->mEvent
->AsGUIEvent()->mWidget
= widgetEvent
->mWidget
;
226 domEvent
->mPresContext
= mPresContext
;
228 // The coalesced widget mouse events shouldn't have been dispatched.
229 MOZ_ASSERT(!domEvent
->mEvent
->mTarget
);
230 // The event target should be the same as the dispatched event's target.
231 domEvent
->mEvent
->mTarget
= mEvent
->mTarget
;
233 // JS could hold reference to dom events. We have to ask dom event to
234 // duplicate its private data to avoid the widget event is destroyed.
235 domEvent
->DuplicatePrivateData();
237 // Setup mPresContext again after DuplicatePrivateData since it clears
239 domEvent
->mPresContext
= mPresContext
;
240 mCoalescedEvents
.AppendElement(domEvent
);
243 if (mEvent
->mTarget
) {
244 for (RefPtr
<PointerEvent
>& pointerEvent
: mCoalescedEvents
) {
245 // Only set event target when it's null.
246 if (!pointerEvent
->mEvent
->mTarget
) {
247 pointerEvent
->mEvent
->mTarget
= mEvent
->mTarget
;
251 aPointerEvents
.AppendElements(mCoalescedEvents
);
254 bool PointerEvent::ShouldResistFingerprinting(CallerType aCallerType
) {
255 // There are four situations we don't need to spoof this pointer event.
256 // 1. This event is generated by scripts.
257 // 2. This event is a mouse pointer event.
258 // 3. The caller type is system.
259 // 4. The pref privcy.resistFingerprinting' is false, we fast return here
260 // since we don't need to do any QI of following codes.
261 // We don't need to check for the system group since pointer events won't be
262 // dispatched to the system group.
263 if (!mEvent
->IsTrusted() || aCallerType
== CallerType::System
||
264 !nsContentUtils::ShouldResistFingerprinting() ||
265 mEvent
->AsPointerEvent()->mInputSource
==
266 MouseEvent_Binding::MOZ_SOURCE_MOUSE
) {
270 nsCOMPtr
<Document
> doc
= GetDocument();
272 return doc
&& !nsContentUtils::IsChromeDoc(doc
);
275 } // namespace mozilla::dom
277 using namespace mozilla
;
278 using namespace mozilla::dom
;
280 already_AddRefed
<PointerEvent
> NS_NewDOMPointerEvent(
281 EventTarget
* aOwner
, nsPresContext
* aPresContext
,
282 WidgetPointerEvent
* aEvent
) {
283 RefPtr
<PointerEvent
> it
= new PointerEvent(aOwner
, aPresContext
, aEvent
);