Bug 1686668 [wpt PR 27185] - Update wpt metadata, a=testonly
[gecko.git] / dom / events / PointerEvent.cpp
blobc8f05aa700cb3bd56e0b0f337fca7ec055e02152
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->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
37 // be 0.
38 mDetail = 0;
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");
65 break;
66 case MouseEvent_Binding::MOZ_SOURCE_PEN:
67 aPointerTypeDest.AssignLiteral("pen");
68 break;
69 case MouseEvent_Binding::MOZ_SOURCE_TOUCH:
70 aPointerTypeDest.AssignLiteral("touch");
71 break;
72 default:
73 aPointerTypeDest.Truncate();
74 break;
78 // static
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);
109 return e.forget();
112 // static
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");
140 return;
143 ConvertPointerTypeToString(mEvent->AsPointerEvent()->mInputSource,
144 aPointerType);
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
238 // mPresContext.
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) {
267 return false;
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);
284 return it.forget();