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
->mRefPoint
= LayoutDeviceIntPoint(0, 0);
33 mouseEvent
->mInputSource
= MouseEvent_Binding::MOZ_SOURCE_UNKNOWN
;
35 // 5.2 Pointer Event types, for all pointer events, |detail| attribute SHOULD
40 JSObject
* PointerEvent::WrapObjectInternal(JSContext
* aCx
,
41 JS::Handle
<JSObject
*> aGivenProto
) {
42 return PointerEvent_Binding::Wrap(aCx
, this, aGivenProto
);
45 static uint16_t ConvertStringToPointerType(const nsAString
& aPointerTypeArg
) {
46 if (aPointerTypeArg
.EqualsLiteral("mouse")) {
47 return MouseEvent_Binding::MOZ_SOURCE_MOUSE
;
49 if (aPointerTypeArg
.EqualsLiteral("pen")) {
50 return MouseEvent_Binding::MOZ_SOURCE_PEN
;
52 if (aPointerTypeArg
.EqualsLiteral("touch")) {
53 return MouseEvent_Binding::MOZ_SOURCE_TOUCH
;
56 return MouseEvent_Binding::MOZ_SOURCE_UNKNOWN
;
59 void ConvertPointerTypeToString(uint16_t aPointerTypeSrc
,
60 nsAString
& aPointerTypeDest
) {
61 switch (aPointerTypeSrc
) {
62 case MouseEvent_Binding::MOZ_SOURCE_MOUSE
:
63 aPointerTypeDest
.AssignLiteral("mouse");
65 case MouseEvent_Binding::MOZ_SOURCE_PEN
:
66 aPointerTypeDest
.AssignLiteral("pen");
68 case MouseEvent_Binding::MOZ_SOURCE_TOUCH
:
69 aPointerTypeDest
.AssignLiteral("touch");
72 aPointerTypeDest
.Truncate();
78 already_AddRefed
<PointerEvent
> PointerEvent::Constructor(
79 EventTarget
* aOwner
, const nsAString
& aType
,
80 const PointerEventInit
& aParam
) {
81 RefPtr
<PointerEvent
> e
= new PointerEvent(aOwner
, nullptr, nullptr);
82 bool trusted
= e
->Init(aOwner
);
84 e
->InitMouseEvent(aType
, aParam
.mBubbles
, aParam
.mCancelable
, aParam
.mView
,
85 aParam
.mDetail
, aParam
.mScreenX
, aParam
.mScreenY
,
86 aParam
.mClientX
, aParam
.mClientY
, false, false, false,
87 false, aParam
.mButton
, aParam
.mRelatedTarget
);
88 e
->InitializeExtraMouseEventDictionaryMembers(aParam
);
89 e
->mPointerType
= Some(aParam
.mPointerType
);
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 if (!aParam
.mPredictedEvents
.IsEmpty()) {
108 e
->mPredictedEvents
.AppendElements(aParam
.mPredictedEvents
);
110 e
->SetTrusted(trusted
);
111 e
->SetComposed(aParam
.mComposed
);
116 already_AddRefed
<PointerEvent
> PointerEvent::Constructor(
117 const GlobalObject
& aGlobal
, const nsAString
& aType
,
118 const PointerEventInit
& aParam
) {
119 nsCOMPtr
<EventTarget
> owner
= do_QueryInterface(aGlobal
.GetAsSupports());
120 return Constructor(owner
, aType
, aParam
);
123 NS_IMPL_CYCLE_COLLECTION_CLASS(PointerEvent
)
125 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PointerEvent
, MouseEvent
)
126 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCoalescedEvents
)
127 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPredictedEvents
)
128 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
130 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PointerEvent
, MouseEvent
)
131 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCoalescedEvents
)
132 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPredictedEvents
)
133 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
135 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PointerEvent
)
136 NS_INTERFACE_MAP_END_INHERITING(MouseEvent
)
138 NS_IMPL_ADDREF_INHERITED(PointerEvent
, MouseEvent
)
139 NS_IMPL_RELEASE_INHERITED(PointerEvent
, MouseEvent
)
141 void PointerEvent::GetPointerType(nsAString
& aPointerType
) {
142 if (mPointerType
.isSome()) {
143 aPointerType
= mPointerType
.value();
147 if (ShouldResistFingerprinting()) {
148 aPointerType
.AssignLiteral("mouse");
152 ConvertPointerTypeToString(mEvent
->AsPointerEvent()->mInputSource
,
156 int32_t PointerEvent::PointerId() {
157 return ShouldResistFingerprinting()
158 ? PointerEventHandler::GetSpoofedPointerIdForRFP()
159 : mEvent
->AsPointerEvent()->pointerId
;
162 int32_t PointerEvent::Width() {
163 return ShouldResistFingerprinting() ? 1 : mEvent
->AsPointerEvent()->mWidth
;
166 int32_t PointerEvent::Height() {
167 return ShouldResistFingerprinting() ? 1 : mEvent
->AsPointerEvent()->mHeight
;
170 float PointerEvent::Pressure() {
171 if (mEvent
->mMessage
== ePointerUp
|| !ShouldResistFingerprinting()) {
172 return mEvent
->AsPointerEvent()->mPressure
;
175 // According to [1], we should use 0.5 when it is in active buttons state and
176 // 0 otherwise for devices that don't support pressure. And a pointerup event
177 // always reports 0, so we don't need to spoof that.
179 // [1] https://www.w3.org/TR/pointerevents/#dom-pointerevent-pressure
180 float spoofedPressure
= 0.0;
181 if (mEvent
->AsPointerEvent()->mButtons
) {
182 spoofedPressure
= 0.5;
185 return spoofedPressure
;
188 float PointerEvent::TangentialPressure() {
189 return ShouldResistFingerprinting()
191 : mEvent
->AsPointerEvent()->tangentialPressure
;
194 int32_t PointerEvent::TiltX() {
195 return ShouldResistFingerprinting() ? 0 : mEvent
->AsPointerEvent()->tiltX
;
198 int32_t PointerEvent::TiltY() {
199 return ShouldResistFingerprinting() ? 0 : mEvent
->AsPointerEvent()->tiltY
;
202 int32_t PointerEvent::Twist() {
203 return ShouldResistFingerprinting() ? 0 : mEvent
->AsPointerEvent()->twist
;
206 bool PointerEvent::IsPrimary() { return mEvent
->AsPointerEvent()->mIsPrimary
; }
208 void PointerEvent::GetCoalescedEvents(
209 nsTArray
<RefPtr
<PointerEvent
>>& aPointerEvents
) {
210 WidgetPointerEvent
* widgetEvent
= mEvent
->AsPointerEvent();
211 if (mCoalescedEvents
.IsEmpty() && widgetEvent
&&
212 widgetEvent
->mCoalescedWidgetEvents
&&
213 !widgetEvent
->mCoalescedWidgetEvents
->mEvents
.IsEmpty()) {
214 nsCOMPtr
<EventTarget
> owner
= do_QueryInterface(mOwner
);
215 for (WidgetPointerEvent
& event
:
216 widgetEvent
->mCoalescedWidgetEvents
->mEvents
) {
217 RefPtr
<PointerEvent
> domEvent
=
218 NS_NewDOMPointerEvent(owner
, nullptr, &event
);
220 // The dom event is derived from an OS generated widget event. Setup
221 // mWidget and mPresContext since they are necessary to calculate
222 // offsetX / offsetY.
223 domEvent
->mEvent
->AsGUIEvent()->mWidget
= widgetEvent
->mWidget
;
224 domEvent
->mPresContext
= mPresContext
;
226 // The coalesced widget mouse events shouldn't have been dispatched.
227 MOZ_ASSERT(!domEvent
->mEvent
->mTarget
);
228 // The event target should be the same as the dispatched event's target.
229 domEvent
->mEvent
->mTarget
= mEvent
->mTarget
;
231 // JS could hold reference to dom events. We have to ask dom event to
232 // duplicate its private data to avoid the widget event is destroyed.
233 domEvent
->DuplicatePrivateData();
235 // Setup mPresContext again after DuplicatePrivateData since it clears
237 domEvent
->mPresContext
= mPresContext
;
238 mCoalescedEvents
.AppendElement(domEvent
);
241 if (mEvent
->IsTrusted() && mEvent
->mTarget
) {
242 for (RefPtr
<PointerEvent
>& pointerEvent
: mCoalescedEvents
) {
243 // Only set event target when it's null.
244 if (!pointerEvent
->mEvent
->mTarget
) {
245 pointerEvent
->mEvent
->mTarget
= mEvent
->mTarget
;
249 aPointerEvents
.AppendElements(mCoalescedEvents
);
252 void PointerEvent::GetPredictedEvents(
253 nsTArray
<RefPtr
<PointerEvent
>>& aPointerEvents
) {
254 // XXX Add support for native predicted events, bug 1550461
255 if (mEvent
->IsTrusted() && mEvent
->mTarget
) {
256 for (RefPtr
<PointerEvent
>& pointerEvent
: mPredictedEvents
) {
257 // Only set event target when it's null.
258 if (!pointerEvent
->mEvent
->mTarget
) {
259 pointerEvent
->mEvent
->mTarget
= mEvent
->mTarget
;
263 aPointerEvents
.AppendElements(mPredictedEvents
);
266 bool PointerEvent::ShouldResistFingerprinting() {
267 // There are three simple situations we don't need to spoof this pointer
269 // 1. The pref privcy.resistFingerprinting' is false, we fast return here
270 // since we don't need to do any QI of following codes.
271 // 2. This event is generated by scripts.
272 // 3. This event is a mouse pointer event.
273 // We don't need to check for the system group since pointer events won't be
274 // dispatched to the system group.
275 if (!nsContentUtils::ShouldResistFingerprinting("Efficiency Check",
276 RFPTarget::PointerEvents
) ||
277 !mEvent
->IsTrusted() ||
278 mEvent
->AsPointerEvent()->mInputSource
==
279 MouseEvent_Binding::MOZ_SOURCE_MOUSE
) {
283 // Pref is checked above, so use true as fallback.
284 nsCOMPtr
<Document
> doc
= GetDocument();
285 return doc
? doc
->ShouldResistFingerprinting(RFPTarget::PointerEvents
) : true;
288 } // namespace mozilla::dom
290 using namespace mozilla
;
291 using namespace mozilla::dom
;
293 already_AddRefed
<PointerEvent
> NS_NewDOMPointerEvent(
294 EventTarget
* aOwner
, nsPresContext
* aPresContext
,
295 WidgetPointerEvent
* aEvent
) {
296 RefPtr
<PointerEvent
> it
= new PointerEvent(aOwner
, aPresContext
, aEvent
);