Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / dom / events / PointerEvent.cpp
blob3acae988dba14a1a13f5d6ac31740e4bfe3607b3
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"
15 #include "prtime.h"
17 namespace mozilla::dom {
19 PointerEvent::PointerEvent(EventTarget* aOwner, nsPresContext* aPresContext,
20 WidgetPointerEvent* aEvent)
21 : MouseEvent(aOwner, aPresContext,
22 aEvent ? aEvent
23 : new WidgetPointerEvent(false, eVoidEvent, nullptr)) {
24 NS_ASSERTION(mEvent->mClass == ePointerEventClass,
25 "event type mismatch ePointerEventClass");
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;
35 // 5.2 Pointer Event types, for all pointer events, |detail| attribute SHOULD
36 // be 0.
37 mDetail = 0;
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");
64 break;
65 case MouseEvent_Binding::MOZ_SOURCE_PEN:
66 aPointerTypeDest.AssignLiteral("pen");
67 break;
68 case MouseEvent_Binding::MOZ_SOURCE_TOUCH:
69 aPointerTypeDest.AssignLiteral("touch");
70 break;
71 default:
72 aPointerTypeDest.Truncate();
73 break;
77 // static
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);
112 return e.forget();
115 // static
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();
144 return;
147 if (ShouldResistFingerprinting()) {
148 aPointerType.AssignLiteral("mouse");
149 return;
152 ConvertPointerTypeToString(mEvent->AsPointerEvent()->mInputSource,
153 aPointerType);
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
236 // mPresContext.
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
268 // event.
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) {
280 return false;
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);
297 return it.forget();