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 "PointerEventHandler.h"
9 #include "PointerEvent.h"
10 #include "PointerLockManager.h"
11 #include "mozilla/PresShell.h"
12 #include "mozilla/StaticPrefs_dom.h"
13 #include "mozilla/dom/BrowserChild.h"
14 #include "mozilla/dom/BrowserParent.h"
15 #include "mozilla/dom/Document.h"
16 #include "mozilla/dom/MouseEventBinding.h"
22 Maybe
<int32_t> PointerEventHandler::sSpoofedPointerId
;
24 // Keeps a map between pointerId and element that currently capturing pointer
25 // with such pointerId. If pointerId is absent in this map then nobody is
26 // capturing it. Additionally keep information about pending capturing content.
27 static nsClassHashtable
<nsUint32HashKey
, PointerCaptureInfo
>*
30 // Keeps information about pointers such as pointerId, activeState, pointerType,
32 static nsClassHashtable
<nsUint32HashKey
, PointerInfo
>* sActivePointersIds
;
34 // Keeps track of which BrowserParent requested pointer capture for a pointer
36 static nsDataHashtable
<nsUint32HashKey
, BrowserParent
*>*
37 sPointerCaptureRemoteTargetTable
= nullptr;
40 void PointerEventHandler::InitializeStatics() {
41 MOZ_ASSERT(!sPointerCaptureList
, "InitializeStatics called multiple times!");
43 new nsClassHashtable
<nsUint32HashKey
, PointerCaptureInfo
>;
44 sActivePointersIds
= new nsClassHashtable
<nsUint32HashKey
, PointerInfo
>;
45 if (XRE_IsParentProcess()) {
46 sPointerCaptureRemoteTargetTable
=
47 new nsDataHashtable
<nsUint32HashKey
, BrowserParent
*>;
52 void PointerEventHandler::ReleaseStatics() {
53 MOZ_ASSERT(sPointerCaptureList
, "ReleaseStatics called without Initialize!");
54 delete sPointerCaptureList
;
55 sPointerCaptureList
= nullptr;
56 delete sActivePointersIds
;
57 sActivePointersIds
= nullptr;
58 if (sPointerCaptureRemoteTargetTable
) {
59 MOZ_ASSERT(XRE_IsParentProcess());
60 delete sPointerCaptureRemoteTargetTable
;
61 sPointerCaptureRemoteTargetTable
= nullptr;
66 bool PointerEventHandler::IsPointerEventImplicitCaptureForTouchEnabled() {
67 return StaticPrefs::dom_w3c_pointer_events_implicit_capture();
71 void PointerEventHandler::UpdateActivePointerState(WidgetMouseEvent
* aEvent
,
72 nsIContent
* aTargetContent
) {
76 switch (aEvent
->mMessage
) {
77 case eMouseEnterIntoWidget
:
78 // In this case we have to know information about available mouse pointers
79 sActivePointersIds
->Put(
81 new PointerInfo(false, aEvent
->mInputSource
, true, nullptr));
83 MaybeCacheSpoofedPointerID(aEvent
->mInputSource
, aEvent
->pointerId
);
86 // In this case we switch pointer to active state
87 if (WidgetPointerEvent
* pointerEvent
= aEvent
->AsPointerEvent()) {
88 // XXXedgar, test could possibly synthesize a mousedown event on a
89 // coordinate outside the browser window and cause aTargetContent to be
90 // nullptr, not sure if this also happens on real usage.
91 sActivePointersIds
->Put(
92 pointerEvent
->pointerId
,
94 true, pointerEvent
->mInputSource
, pointerEvent
->mIsPrimary
,
95 aTargetContent
? aTargetContent
->OwnerDoc() : nullptr));
96 MaybeCacheSpoofedPointerID(pointerEvent
->mInputSource
,
97 pointerEvent
->pointerId
);
101 // pointercancel means a pointer is unlikely to continue to produce
102 // pointer events. In that case, we should turn off active state or remove
103 // the pointer from active pointers.
105 // In this case we remove information about pointer or turn off active
107 if (WidgetPointerEvent
* pointerEvent
= aEvent
->AsPointerEvent()) {
108 if (pointerEvent
->mInputSource
!=
109 MouseEvent_Binding::MOZ_SOURCE_TOUCH
) {
110 sActivePointersIds
->Put(
111 pointerEvent
->pointerId
,
112 new PointerInfo(false, pointerEvent
->mInputSource
,
113 pointerEvent
->mIsPrimary
, nullptr));
115 sActivePointersIds
->Remove(pointerEvent
->pointerId
);
119 case eMouseExitFromWidget
:
120 // In this case we have to remove information about disappeared mouse
122 sActivePointersIds
->Remove(aEvent
->pointerId
);
125 MOZ_ASSERT_UNREACHABLE("event has invalid type");
131 void PointerEventHandler::RequestPointerCaptureById(uint32_t aPointerId
,
133 SetPointerCaptureById(aPointerId
, aElement
);
135 if (BrowserChild
* browserChild
=
136 BrowserChild::GetFrom(aElement
->OwnerDoc()->GetDocShell())) {
137 browserChild
->SendRequestPointerCapture(
139 [aPointerId
](bool aSuccess
) {
141 PointerEventHandler::ReleasePointerCaptureById(aPointerId
);
144 [](mozilla::ipc::ResponseRejectReason
) {});
149 void PointerEventHandler::SetPointerCaptureById(uint32_t aPointerId
,
151 MOZ_ASSERT(aElement
);
152 PointerCaptureInfo
* pointerCaptureInfo
= GetPointerCaptureInfo(aPointerId
);
153 if (pointerCaptureInfo
) {
154 pointerCaptureInfo
->mPendingElement
= aElement
;
156 sPointerCaptureList
->Put(aPointerId
, new PointerCaptureInfo(aElement
));
161 PointerCaptureInfo
* PointerEventHandler::GetPointerCaptureInfo(
162 uint32_t aPointerId
) {
163 PointerCaptureInfo
* pointerCaptureInfo
= nullptr;
164 sPointerCaptureList
->Get(aPointerId
, &pointerCaptureInfo
);
165 return pointerCaptureInfo
;
169 void PointerEventHandler::ReleasePointerCaptureById(uint32_t aPointerId
) {
170 PointerCaptureInfo
* pointerCaptureInfo
= GetPointerCaptureInfo(aPointerId
);
171 if (pointerCaptureInfo
) {
172 if (Element
* pendingElement
= pointerCaptureInfo
->mPendingElement
) {
173 if (BrowserChild
* browserChild
= BrowserChild::GetFrom(
174 pendingElement
->OwnerDoc()->GetDocShell())) {
175 browserChild
->SendReleasePointerCapture(aPointerId
);
178 pointerCaptureInfo
->mPendingElement
= nullptr;
183 void PointerEventHandler::ReleaseAllPointerCapture() {
184 for (auto iter
= sPointerCaptureList
->Iter(); !iter
.Done(); iter
.Next()) {
185 PointerCaptureInfo
* data
= iter
.UserData();
186 if (data
&& data
->mPendingElement
) {
187 ReleasePointerCaptureById(iter
.Key());
193 bool PointerEventHandler::SetPointerCaptureRemoteTarget(
194 uint32_t aPointerId
, dom::BrowserParent
* aBrowserParent
) {
195 MOZ_ASSERT(XRE_IsParentProcess());
196 MOZ_ASSERT(sPointerCaptureRemoteTargetTable
);
197 MOZ_ASSERT(aBrowserParent
);
199 if (PointerLockManager::GetLockedRemoteTarget()) {
203 BrowserParent
* currentRemoteTarget
=
204 PointerEventHandler::GetPointerCapturingRemoteTarget(aPointerId
);
205 if (currentRemoteTarget
&& currentRemoteTarget
!= aBrowserParent
) {
209 sPointerCaptureRemoteTargetTable
->Put(aPointerId
, aBrowserParent
);
214 void PointerEventHandler::ReleasePointerCaptureRemoteTarget(
215 BrowserParent
* aBrowserParent
) {
216 MOZ_ASSERT(XRE_IsParentProcess());
217 MOZ_ASSERT(sPointerCaptureRemoteTargetTable
);
218 MOZ_ASSERT(aBrowserParent
);
220 sPointerCaptureRemoteTargetTable
->RemoveIf([aBrowserParent
](
222 BrowserParent
* browserParent
= iter
.Data();
223 MOZ_ASSERT(browserParent
, "Null BrowserParent in pointer captured table?");
225 return aBrowserParent
== browserParent
;
230 void PointerEventHandler::ReleasePointerCaptureRemoteTarget(
231 uint32_t aPointerId
) {
232 MOZ_ASSERT(XRE_IsParentProcess());
233 MOZ_ASSERT(sPointerCaptureRemoteTargetTable
);
235 sPointerCaptureRemoteTargetTable
->Remove(aPointerId
);
239 BrowserParent
* PointerEventHandler::GetPointerCapturingRemoteTarget(
240 uint32_t aPointerId
) {
241 MOZ_ASSERT(XRE_IsParentProcess());
242 MOZ_ASSERT(sPointerCaptureRemoteTargetTable
);
244 return sPointerCaptureRemoteTargetTable
->Get(aPointerId
);
248 void PointerEventHandler::ReleaseAllPointerCaptureRemoteTarget() {
249 MOZ_ASSERT(XRE_IsParentProcess());
250 MOZ_ASSERT(sPointerCaptureRemoteTargetTable
);
252 for (auto iter
= sPointerCaptureRemoteTargetTable
->Iter(); !iter
.Done();
254 BrowserParent
* browserParent
= iter
.Data();
255 MOZ_ASSERT(browserParent
, "Null BrowserParent in pointer captured table?");
257 Unused
<< browserParent
->SendReleaseAllPointerCapture();
263 const PointerInfo
* PointerEventHandler::GetPointerInfo(uint32_t aPointerId
) {
264 return sActivePointersIds
->Get(aPointerId
);
268 void PointerEventHandler::MaybeProcessPointerCapture(WidgetGUIEvent
* aEvent
) {
269 switch (aEvent
->mClass
) {
270 case eMouseEventClass
:
271 ProcessPointerCaptureForMouse(aEvent
->AsMouseEvent());
273 case eTouchEventClass
:
274 ProcessPointerCaptureForTouch(aEvent
->AsTouchEvent());
282 void PointerEventHandler::ProcessPointerCaptureForMouse(
283 WidgetMouseEvent
* aEvent
) {
284 if (!ShouldGeneratePointerEventFromMouse(aEvent
)) {
288 PointerCaptureInfo
* info
= GetPointerCaptureInfo(aEvent
->pointerId
);
289 if (!info
|| info
->mPendingElement
== info
->mOverrideElement
) {
292 WidgetPointerEvent
localEvent(*aEvent
);
293 InitPointerEventFromMouse(&localEvent
, aEvent
, eVoidEvent
);
294 CheckPointerCaptureState(&localEvent
);
298 void PointerEventHandler::ProcessPointerCaptureForTouch(
299 WidgetTouchEvent
* aEvent
) {
300 if (!ShouldGeneratePointerEventFromTouch(aEvent
)) {
304 for (uint32_t i
= 0; i
< aEvent
->mTouches
.Length(); ++i
) {
305 Touch
* touch
= aEvent
->mTouches
[i
];
306 if (!TouchManager::ShouldConvertTouchToPointer(touch
, aEvent
)) {
309 PointerCaptureInfo
* info
= GetPointerCaptureInfo(touch
->Identifier());
310 if (!info
|| info
->mPendingElement
== info
->mOverrideElement
) {
313 WidgetPointerEvent
event(aEvent
->IsTrusted(), eVoidEvent
, aEvent
->mWidget
);
314 InitPointerEventFromTouch(&event
, aEvent
, touch
, i
== 0);
315 CheckPointerCaptureState(&event
);
320 void PointerEventHandler::CheckPointerCaptureState(WidgetPointerEvent
* aEvent
) {
321 // Handle pending pointer capture before any pointer events except
322 // gotpointercapture / lostpointercapture.
326 MOZ_ASSERT(aEvent
->mClass
== ePointerEventClass
);
328 PointerCaptureInfo
* captureInfo
= GetPointerCaptureInfo(aEvent
->pointerId
);
330 // When fingerprinting resistance is enabled, we need to map other pointer
331 // ids into the spoofed one. We don't have to do the mapping if the capture
332 // info exists for the non-spoofed pointer id because of we won't allow
333 // content to set pointer capture other than the spoofed one. Thus, it must be
334 // from chrome if the capture info exists in this case. And we don't have to
335 // do anything if the pointer id is the same as the spoofed one.
336 if (nsContentUtils::ShouldResistFingerprinting() &&
337 aEvent
->pointerId
!= (uint32_t)GetSpoofedPointerIdForRFP() &&
339 PointerCaptureInfo
* spoofedCaptureInfo
=
340 GetPointerCaptureInfo(GetSpoofedPointerIdForRFP());
342 // We need to check the target element is content or chrome. If it is chrome
343 // we don't need to send a capture event since the capture info of the
344 // original pointer id doesn't exist in the case.
345 if (!spoofedCaptureInfo
||
346 (spoofedCaptureInfo
->mPendingElement
&&
347 spoofedCaptureInfo
->mPendingElement
->IsInChromeDocument())) {
351 captureInfo
= spoofedCaptureInfo
;
355 captureInfo
->mPendingElement
== captureInfo
->mOverrideElement
) {
359 RefPtr
<Element
> overrideElement
= captureInfo
->mOverrideElement
;
360 RefPtr
<Element
> pendingElement
= captureInfo
->mPendingElement
;
362 // Update captureInfo before dispatching event since sPointerCaptureList may
363 // be changed in the pointer event listener.
364 captureInfo
->mOverrideElement
= captureInfo
->mPendingElement
;
365 if (captureInfo
->Empty()) {
366 sPointerCaptureList
->Remove(aEvent
->pointerId
);
369 if (overrideElement
) {
370 DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ false, aEvent
,
373 if (pendingElement
) {
374 DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ true, aEvent
,
380 void PointerEventHandler::ImplicitlyCapturePointer(nsIFrame
* aFrame
,
381 WidgetEvent
* aEvent
) {
382 MOZ_ASSERT(aEvent
->mMessage
== ePointerDown
);
383 if (!aFrame
|| !IsPointerEventImplicitCaptureForTouchEnabled()) {
386 WidgetPointerEvent
* pointerEvent
= aEvent
->AsPointerEvent();
387 NS_WARNING_ASSERTION(pointerEvent
,
388 "Call ImplicitlyCapturePointer with non-pointer event");
389 if (pointerEvent
->mInputSource
!= MouseEvent_Binding::MOZ_SOURCE_TOUCH
) {
390 // We only implicitly capture the pointer for touch device.
393 nsCOMPtr
<nsIContent
> target
;
394 aFrame
->GetContentForEvent(aEvent
, getter_AddRefs(target
));
395 while (target
&& !target
->IsElement()) {
396 target
= target
->GetParent();
398 if (NS_WARN_IF(!target
)) {
401 RequestPointerCaptureById(pointerEvent
->pointerId
, target
->AsElement());
405 void PointerEventHandler::ImplicitlyReleasePointerCapture(WidgetEvent
* aEvent
) {
407 if (aEvent
->mMessage
!= ePointerUp
&& aEvent
->mMessage
!= ePointerCancel
) {
410 WidgetPointerEvent
* pointerEvent
= aEvent
->AsPointerEvent();
411 ReleasePointerCaptureById(pointerEvent
->pointerId
);
412 CheckPointerCaptureState(pointerEvent
);
416 Element
* PointerEventHandler::GetPointerCapturingElement(uint32_t aPointerId
) {
417 PointerCaptureInfo
* pointerCaptureInfo
= GetPointerCaptureInfo(aPointerId
);
418 if (pointerCaptureInfo
) {
419 return pointerCaptureInfo
->mOverrideElement
;
425 Element
* PointerEventHandler::GetPointerCapturingElement(
426 WidgetGUIEvent
* aEvent
) {
427 if ((aEvent
->mClass
!= ePointerEventClass
&&
428 aEvent
->mClass
!= eMouseEventClass
) ||
429 aEvent
->mMessage
== ePointerDown
|| aEvent
->mMessage
== eMouseDown
) {
430 // Pointer capture should only be applied to all pointer events and mouse
431 // events except ePointerDown and eMouseDown;
435 WidgetMouseEvent
* mouseEvent
= aEvent
->AsMouseEvent();
439 return GetPointerCapturingElement(mouseEvent
->pointerId
);
443 void PointerEventHandler::ReleaseIfCaptureByDescendant(nsIContent
* aContent
) {
444 // We should check that aChild does not contain pointer capturing elements.
445 // If it does we should release the pointer capture for the elements.
446 for (auto iter
= sPointerCaptureList
->Iter(); !iter
.Done(); iter
.Next()) {
447 PointerCaptureInfo
* data
= iter
.UserData();
448 if (data
&& data
->mPendingElement
&&
449 data
->mPendingElement
->IsInclusiveDescendantOf(aContent
)) {
450 ReleasePointerCaptureById(iter
.Key());
456 void PointerEventHandler::PreHandlePointerEventsPreventDefault(
457 WidgetPointerEvent
* aPointerEvent
, WidgetGUIEvent
* aMouseOrTouchEvent
) {
458 if (!aPointerEvent
->mIsPrimary
|| aPointerEvent
->mMessage
== ePointerDown
) {
461 PointerInfo
* pointerInfo
= nullptr;
462 if (!sActivePointersIds
->Get(aPointerEvent
->pointerId
, &pointerInfo
) ||
464 // The PointerInfo for active pointer should be added for normal cases. But
465 // in some cases, we may receive mouse events before adding PointerInfo in
466 // sActivePointersIds. (e.g. receive mousemove before
467 // eMouseEnterIntoWidget). In these cases, we could ignore them because they
468 // are not the events between a DefaultPrevented pointerdown and the
469 // corresponding pointerup.
472 if (!pointerInfo
->mPreventMouseEventByContent
) {
475 aMouseOrTouchEvent
->PreventDefault(false);
476 aMouseOrTouchEvent
->mFlags
.mOnlyChromeDispatch
= true;
477 if (aPointerEvent
->mMessage
== ePointerUp
) {
478 pointerInfo
->mPreventMouseEventByContent
= false;
483 void PointerEventHandler::PostHandlePointerEventsPreventDefault(
484 WidgetPointerEvent
* aPointerEvent
, WidgetGUIEvent
* aMouseOrTouchEvent
) {
485 if (!aPointerEvent
->mIsPrimary
|| aPointerEvent
->mMessage
!= ePointerDown
||
486 !aPointerEvent
->DefaultPreventedByContent()) {
489 PointerInfo
* pointerInfo
= nullptr;
490 if (!sActivePointersIds
->Get(aPointerEvent
->pointerId
, &pointerInfo
) ||
492 // We already added the PointerInfo for active pointer when
493 // PresShell::HandleEvent handling pointerdown event.
495 MOZ_CRASH("Got ePointerDown w/o active pointer info!!");
496 #endif // #ifdef DEBUG
499 // PreventDefault only applied for active pointers.
500 if (!pointerInfo
->mActiveState
) {
503 aMouseOrTouchEvent
->PreventDefault(false);
504 aMouseOrTouchEvent
->mFlags
.mOnlyChromeDispatch
= true;
505 pointerInfo
->mPreventMouseEventByContent
= true;
509 void PointerEventHandler::InitPointerEventFromMouse(
510 WidgetPointerEvent
* aPointerEvent
, WidgetMouseEvent
* aMouseEvent
,
511 EventMessage aMessage
) {
512 MOZ_ASSERT(aPointerEvent
);
513 MOZ_ASSERT(aMouseEvent
);
514 aPointerEvent
->pointerId
= aMouseEvent
->pointerId
;
515 aPointerEvent
->mInputSource
= aMouseEvent
->mInputSource
;
516 aPointerEvent
->mMessage
= aMessage
;
517 aPointerEvent
->mButton
= aMouseEvent
->mMessage
== eMouseMove
518 ? MouseButton::eNotPressed
519 : aMouseEvent
->mButton
;
521 aPointerEvent
->mButtons
= aMouseEvent
->mButtons
;
522 aPointerEvent
->mPressure
=
523 aPointerEvent
->mButtons
524 ? aMouseEvent
->mPressure
? aMouseEvent
->mPressure
: 0.5f
529 void PointerEventHandler::InitPointerEventFromTouch(
530 WidgetPointerEvent
* aPointerEvent
, WidgetTouchEvent
* aTouchEvent
,
531 mozilla::dom::Touch
* aTouch
, bool aIsPrimary
) {
532 MOZ_ASSERT(aPointerEvent
);
533 MOZ_ASSERT(aTouchEvent
);
535 int16_t button
= aTouchEvent
->mMessage
== eTouchMove
536 ? MouseButton::eNotPressed
537 : MouseButton::ePrimary
;
539 int16_t buttons
= aTouchEvent
->mMessage
== eTouchEnd
540 ? MouseButtonsFlag::eNoButtons
541 : MouseButtonsFlag::ePrimaryFlag
;
543 aPointerEvent
->mIsPrimary
= aIsPrimary
;
544 aPointerEvent
->pointerId
= aTouch
->Identifier();
545 aPointerEvent
->mRefPoint
= aTouch
->mRefPoint
;
546 aPointerEvent
->mModifiers
= aTouchEvent
->mModifiers
;
547 aPointerEvent
->mWidth
= aTouch
->RadiusX(CallerType::System
);
548 aPointerEvent
->mHeight
= aTouch
->RadiusY(CallerType::System
);
549 aPointerEvent
->tiltX
= aTouch
->tiltX
;
550 aPointerEvent
->tiltY
= aTouch
->tiltY
;
551 aPointerEvent
->mTime
= aTouchEvent
->mTime
;
552 aPointerEvent
->mTimeStamp
= aTouchEvent
->mTimeStamp
;
553 aPointerEvent
->mFlags
= aTouchEvent
->mFlags
;
554 aPointerEvent
->mButton
= button
;
555 aPointerEvent
->mButtons
= buttons
;
556 aPointerEvent
->mInputSource
= MouseEvent_Binding::MOZ_SOURCE_TOUCH
;
560 void PointerEventHandler::DispatchPointerFromMouseOrTouch(
561 PresShell
* aShell
, nsIFrame
* aFrame
, nsIContent
* aContent
,
562 WidgetGUIEvent
* aEvent
, bool aDontRetargetEvents
, nsEventStatus
* aStatus
,
563 nsIContent
** aTargetContent
) {
564 MOZ_ASSERT(aFrame
|| aContent
);
567 EventMessage pointerMessage
= eVoidEvent
;
568 if (aEvent
->mClass
== eMouseEventClass
) {
569 WidgetMouseEvent
* mouseEvent
= aEvent
->AsMouseEvent();
570 // Don't dispatch pointer events caused by a mouse when simulating touch
572 Document
* doc
= aShell
->GetDocument();
577 BrowsingContext
* bc
= doc
->GetBrowsingContext();
578 if (bc
&& bc
->TouchEventsOverride() == TouchEventsOverride::Enabled
&&
583 // 1. If it is not mouse then it is likely will come as touch event
584 // 2. We don't synthesize pointer events for those events that are not
585 // dispatched to DOM.
586 if (!mouseEvent
->convertToPointer
||
587 !aEvent
->IsAllowedToDispatchDOMEvent()) {
591 switch (mouseEvent
->mMessage
) {
593 pointerMessage
= ePointerMove
;
596 pointerMessage
= mouseEvent
->mButtons
? ePointerMove
: ePointerUp
;
600 mouseEvent
->mButtons
& ~nsContentUtils::GetButtonsFlagForButton(
609 WidgetPointerEvent
event(*mouseEvent
);
610 InitPointerEventFromMouse(&event
, mouseEvent
, pointerMessage
);
611 event
.convertToPointer
= mouseEvent
->convertToPointer
= false;
612 RefPtr
<PresShell
> shell(aShell
);
614 shell
= PresShell::GetShellForEventTarget(nullptr, aContent
);
619 PreHandlePointerEventsPreventDefault(&event
, aEvent
);
620 // Dispatch pointer event to the same target which is found by the
621 // corresponding mouse event.
622 shell
->HandleEventWithTarget(&event
, aFrame
, aContent
, aStatus
, true,
624 PostHandlePointerEventsPreventDefault(&event
, aEvent
);
625 } else if (aEvent
->mClass
== eTouchEventClass
) {
626 WidgetTouchEvent
* touchEvent
= aEvent
->AsTouchEvent();
627 // loop over all touches and dispatch pointer events on each touch
629 switch (touchEvent
->mMessage
) {
631 pointerMessage
= ePointerMove
;
634 pointerMessage
= ePointerUp
;
637 pointerMessage
= ePointerDown
;
640 case eTouchPointerCancel
:
641 pointerMessage
= ePointerCancel
;
647 RefPtr
<PresShell
> shell(aShell
);
648 for (uint32_t i
= 0; i
< touchEvent
->mTouches
.Length(); ++i
) {
649 Touch
* touch
= touchEvent
->mTouches
[i
];
650 if (!TouchManager::ShouldConvertTouchToPointer(touch
, touchEvent
)) {
654 WidgetPointerEvent
event(touchEvent
->IsTrusted(), pointerMessage
,
655 touchEvent
->mWidget
);
657 InitPointerEventFromTouch(&event
, touchEvent
, touch
, i
== 0);
658 event
.convertToPointer
= touch
->convertToPointer
= false;
659 if (aEvent
->mMessage
== eTouchStart
) {
660 // We already did hit test for touchstart in PresShell. We should
661 // dispatch pointerdown to the same target as touchstart.
662 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(touch
->mTarget
);
667 nsIFrame
* frame
= content
->GetPrimaryFrame();
668 shell
= PresShell::GetShellForEventTarget(frame
, content
);
673 PreHandlePointerEventsPreventDefault(&event
, aEvent
);
674 shell
->HandleEventWithTarget(&event
, frame
, content
, aStatus
, true,
676 PostHandlePointerEventsPreventDefault(&event
, aEvent
);
678 // We didn't hit test for other touch events. Spec doesn't mention that
679 // all pointer events should be dispatched to the same target as their
680 // corresponding touch events. Call PresShell::HandleEvent so that we do
681 // hit test for pointer events.
682 PreHandlePointerEventsPreventDefault(&event
, aEvent
);
683 shell
->HandleEvent(aFrame
, &event
, aDontRetargetEvents
, aStatus
);
684 PostHandlePointerEventsPreventDefault(&event
, aEvent
);
691 void PointerEventHandler::NotifyDestroyPresContext(
692 nsPresContext
* aPresContext
) {
693 // Clean up pointer capture info
694 for (auto iter
= sPointerCaptureList
->Iter(); !iter
.Done(); iter
.Next()) {
695 PointerCaptureInfo
* data
= iter
.UserData();
696 MOZ_ASSERT(data
, "how could we have a null PointerCaptureInfo here?");
697 if (data
->mPendingElement
&&
698 data
->mPendingElement
->GetPresContext(Element::eForComposedDoc
) ==
700 data
->mPendingElement
= nullptr;
702 if (data
->mOverrideElement
&&
703 data
->mOverrideElement
->GetPresContext(Element::eForComposedDoc
) ==
705 data
->mOverrideElement
= nullptr;
714 uint16_t PointerEventHandler::GetPointerType(uint32_t aPointerId
) {
715 PointerInfo
* pointerInfo
= nullptr;
716 if (sActivePointersIds
->Get(aPointerId
, &pointerInfo
) && pointerInfo
) {
717 return pointerInfo
->mPointerType
;
719 return MouseEvent_Binding::MOZ_SOURCE_UNKNOWN
;
723 bool PointerEventHandler::GetPointerPrimaryState(uint32_t aPointerId
) {
724 PointerInfo
* pointerInfo
= nullptr;
725 if (sActivePointersIds
->Get(aPointerId
, &pointerInfo
) && pointerInfo
) {
726 return pointerInfo
->mPrimaryState
;
732 void PointerEventHandler::DispatchGotOrLostPointerCaptureEvent(
733 bool aIsGotCapture
, const WidgetPointerEvent
* aPointerEvent
,
734 Element
* aCaptureTarget
) {
735 Document
* targetDoc
= aCaptureTarget
->OwnerDoc();
736 RefPtr
<PresShell
> presShell
= targetDoc
->GetPresShell();
737 if (NS_WARN_IF(!presShell
|| presShell
->IsDestroying())) {
741 if (!aIsGotCapture
&& !aCaptureTarget
->IsInComposedDoc()) {
742 // If the capturing element was removed from the DOM tree, fire
743 // ePointerLostCapture at the document.
744 PointerEventInit init
;
745 init
.mPointerId
= aPointerEvent
->pointerId
;
746 init
.mBubbles
= true;
747 init
.mComposed
= true;
748 ConvertPointerTypeToString(aPointerEvent
->mInputSource
, init
.mPointerType
);
749 init
.mIsPrimary
= aPointerEvent
->mIsPrimary
;
750 RefPtr
<PointerEvent
> event
;
751 event
= PointerEvent::Constructor(aCaptureTarget
, u
"lostpointercapture"_ns
,
753 targetDoc
->DispatchEvent(*event
);
756 nsEventStatus status
= nsEventStatus_eIgnore
;
757 WidgetPointerEvent
localEvent(
758 aPointerEvent
->IsTrusted(),
759 aIsGotCapture
? ePointerGotCapture
: ePointerLostCapture
,
760 aPointerEvent
->mWidget
);
762 localEvent
.AssignPointerEventData(*aPointerEvent
, true);
763 DebugOnly
<nsresult
> rv
= presShell
->HandleEventWithTarget(
764 &localEvent
, aCaptureTarget
->GetPrimaryFrame(), aCaptureTarget
, &status
);
766 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
767 "DispatchGotOrLostPointerCaptureEvent failed");
771 void PointerEventHandler::MaybeCacheSpoofedPointerID(uint16_t aInputSource
,
772 uint32_t aPointerId
) {
773 if (sSpoofedPointerId
.isSome() || aInputSource
!= SPOOFED_POINTER_INTERFACE
) {
777 sSpoofedPointerId
.emplace(aPointerId
);
780 } // namespace mozilla