Bug 1316251 Part3: Trigger pointer event implementation in EventStateManager. r=masayuki
To manage pointer event "state" in ESM.
MozReview-Commit-ID: HiAwvSmVTwx
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -611,16 +611,18 @@ EventStateManager::PreHandleEvent(nsPres
if (touchEvent->mMessage == eTouchMove) {
GenerateDragGesture(aPresContext, touchEvent);
} else {
mInTouchDrag = false;
StopTrackingDragGesture();
}
}
+ PointerEventHandler::UpdateActivePointerState(mouseEvent);
+
switch (aEvent->mMessage) {
case eContextMenu:
if (sIsPointerLocked) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
break;
case eMouseTouchDrag:
mInTouchDrag = true;
@@ -705,16 +707,20 @@ EventStateManager::PreHandleEvent(nsPres
GenerateMouseEnterExit(mouseEvent);
//This is a window level mouse exit event and should stop here
aEvent->mMessage = eVoidEvent;
break;
}
MOZ_FALLTHROUGH;
case eMouseMove:
case ePointerDown:
+ if (aEvent->mMessage == ePointerDown) {
+ PointerEventHandler::ImplicitlyCapturePointer(aTargetFrame, aEvent);
+ }
+ MOZ_FALLTHROUGH;
case ePointerMove: {
// on the Mac, GenerateDragGesture() may not return until the drag
// has completed and so |aTargetFrame| may have been deleted (moving
// a bookmark, for example). If this is the case, however, we know
// that ClearFrameRefs() has been called and it cleared out
// |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
// into UpdateCursor().
GenerateDragGesture(aPresContext, mouseEvent);
@@ -3192,25 +3198,38 @@ EventStateManager::PostHandleEvent(nsPre
}
}
}
}
SetActiveManager(this, activeContent);
}
break;
case ePointerCancel: {
- if(WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
- GenerateMouseEnterExit(mouseEvent);
+ if(WidgetMouseEvent* pointerEvent = aEvent->AsPointerEvent()) {
+ // Implicitly releasing capture for given pointer. ePointerLostCapture
+ // should be send after ePointerUp or ePointerCancel.
+ PointerEventHandler::ImplicitlyReleasePointerCapture(pointerEvent);
+ GenerateMouseEnterExit(pointerEvent);
+ // After UP/Cancel Touch pointers become invalid so we can remove relevant
+ // helper from Table. Mouse/Pen pointers are valid all the time (not only
+ // between down/up)
+ if (pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
+ mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
+ GenerateMouseEnterExit(pointerEvent);
+ }
}
- // After firing the pointercancel event, a user agent must also fire a
- // pointerout event followed by a pointerleave event.
- MOZ_FALLTHROUGH;
+ break;
}
case ePointerUp: {
WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
+
+ // Implicitly releasing capture for given pointer. ePointerLostCapture
+ // should be send after ePointerUp or ePointerCancel.
+ PointerEventHandler::ImplicitlyReleasePointerCapture(pointerEvent);
+
// After UP/Cancel Touch pointers become invalid so we can remove relevant helper from Table
// Mouse/Pen pointers are valid all the time (not only between down/up)
if (pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
GenerateMouseEnterExit(pointerEvent);
}
break;
}
@@ -5056,17 +5075,19 @@ EventStateManager::ResetLastOverForConte
if (aElemWrapper && aElemWrapper->mLastOverElement &&
nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement,
aContent)) {
aElemWrapper->mLastOverElement = nullptr;
}
}
void
-EventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
+EventStateManager::ContentRemoved(nsIDocument* aDocument,
+ nsIContent* aMaybeContainer,
+ nsIContent* aContent)
{
/*
* Anchor and area elements when focused or hovered might make the UI to show
* the current link. We want to make sure that the UI gets informed when they
* are actually removed from the DOM.
*/
if (aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) &&
(aContent->AsElement()->State().HasAtLeastOneOfStates(NS_EVENT_STATE_FOCUS |
@@ -5099,16 +5120,18 @@ EventStateManager::ContentRemoved(nsIDoc
}
if (sDragOverContent &&
sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&
nsContentUtils::ContentIsDescendantOf(sDragOverContent, aContent)) {
sDragOverContent = nullptr;
}
+ PointerEventHandler::ReleaseIfCaptureByDescendant(aContent);
+
// See bug 292146 for why we want to null this out
ResetLastOverForContent(0, mMouseEnterLeaveHelper, aContent);
for (auto iter = mPointersEnterLeaveHelper.Iter();
!iter.Done();
iter.Next()) {
ResetLastOverForContent(iter.Key(), iter.Data(), aContent);
}
}
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -135,17 +135,19 @@ public:
* @return Whether the content was able to change all states. Returns false
* if a resulting DOM event causes the content node passed in
* to not change states. Note, the frame for the content may
* change as a result of the content state change, because of
* frame reconstructions that may occur, but this does not
* affect the return value.
*/
bool SetContentState(nsIContent* aContent, EventStates aState);
- void ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
+ void ContentRemoved(nsIDocument* aDocument, nsIContent* aMaybeContainer,
+ nsIContent* aContent);
+
bool EventStatusOK(WidgetGUIEvent* aEvent);
/**
* EventStateManager stores IMEContentObserver while it's observing contents.
* Following mehtods are called by IMEContentObserver when it starts to
* observe or stops observing the content.
*/
void OnStartToObserveContent(IMEContentObserver* aIMEContentObserver);
--- a/dom/events/PointerEventHandler.cpp
+++ b/dom/events/PointerEventHandler.cpp
@@ -84,29 +84,26 @@ PointerEventHandler::IsPointerEventEnabl
/* static */ bool
PointerEventHandler::IsPointerEventImplicitCaptureForTouchEnabled()
{
return sPointerEventEnabled && sPointerEventImplicitCapture;
}
/* static */ void
-PointerEventHandler::UpdateActivePointerState(WidgetGUIEvent* aEvent)
+PointerEventHandler::UpdateActivePointerState(WidgetMouseEvent* aEvent)
{
- if (!IsPointerEventEnabled()) {
+ if (!IsPointerEventEnabled() || !aEvent) {
return;
}
switch (aEvent->mMessage) {
case eMouseEnterIntoWidget:
// In this case we have to know information about available mouse pointers
- if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
- sActivePointersIds->Put(mouseEvent->pointerId,
- new PointerInfo(false, mouseEvent->inputSource,
- true));
- }
+ sActivePointersIds->Put(aEvent->pointerId,
+ new PointerInfo(false, aEvent->inputSource, true));
break;
case ePointerDown:
// In this case we switch pointer to active state
if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
sActivePointersIds->Put(pointerEvent->pointerId,
new PointerInfo(true, pointerEvent->inputSource,
pointerEvent->mIsPrimary));
}
@@ -122,19 +119,17 @@ PointerEventHandler::UpdateActivePointer
} else {
sActivePointersIds->Remove(pointerEvent->pointerId);
}
}
break;
case eMouseExitFromWidget:
// In this case we have to remove information about disappeared mouse
// pointers
- if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
- sActivePointersIds->Remove(mouseEvent->pointerId);
- }
+ sActivePointersIds->Remove(aEvent->pointerId);
break;
default:
break;
}
}
/* static */ void
PointerEventHandler::SetPointerCaptureById(uint32_t aPointerId,
@@ -213,16 +208,55 @@ PointerEventHandler::CheckPointerCapture
captureInfo->mOverrideContent = pendingContent;
if (captureInfo->Empty()) {
sPointerCaptureList->Remove(aEvent->pointerId);
}
}
}
+/* static */ void
+PointerEventHandler::ImplicitlyCapturePointer(nsIFrame* aFrame,
+ WidgetEvent* aEvent)
+{
+ MOZ_ASSERT(aEvent->mMessage == ePointerDown);
+ if (!aFrame || !IsPointerEventEnabled() ||
+ !IsPointerEventImplicitCaptureForTouchEnabled()) {
+ return;
+ }
+ WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
+ NS_WARNING_ASSERTION(pointerEvent,
+ "Call ImplicitlyCapturePointer with non-pointer event");
+ if (pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
+ // We only implicitly capture the pointer for touch device.
+ return;
+ }
+ nsCOMPtr<nsIContent> target;
+ aFrame->GetContentForEvent(aEvent, getter_AddRefs(target));
+ while (target && !target->IsElement()) {
+ target = target->GetParent();
+ }
+ if (NS_WARN_IF(!target)) {
+ return;
+ }
+ SetPointerCaptureById(pointerEvent->pointerId, target);
+}
+
+/* static */ void
+PointerEventHandler::ImplicitlyReleasePointerCapture(WidgetEvent* aEvent)
+{
+ MOZ_ASSERT(aEvent);
+ if (aEvent->mMessage != ePointerUp && aEvent->mMessage != ePointerCancel) {
+ return;
+ }
+ WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
+ ReleasePointerCaptureById(pointerEvent->pointerId);
+ CheckPointerCaptureState(pointerEvent);
+}
+
/* static */ nsIContent*
PointerEventHandler::GetPointerCapturingContent(uint32_t aPointerId)
{
PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
if (pointerCaptureInfo) {
return pointerCaptureInfo->mOverrideContent;
}
return nullptr;
--- a/dom/events/PointerEventHandler.h
+++ b/dom/events/PointerEventHandler.h
@@ -54,17 +54,17 @@ public:
// Return the preference value of pointer event enabled.
static bool IsPointerEventEnabled();
// Return the preference value of implicit capture.
static bool IsPointerEventImplicitCaptureForTouchEnabled();
// Called in ESM::PreHandleEvent to update current active pointers in a hash
// table.
- static void UpdateActivePointerState(WidgetGUIEvent* aEvent);
+ static void UpdateActivePointerState(WidgetMouseEvent* aEvent);
// Got/release pointer capture of the specified pointer by the content.
static void SetPointerCaptureById(uint32_t aPointerId, nsIContent* aContent);
static void ReleasePointerCaptureById(uint32_t aPointerId);
// Get the pointer captured info of the specified pointer.
static PointerCaptureInfo* GetPointerCaptureInfo(uint32_t aPointerId);
@@ -73,16 +73,20 @@ public:
// aActiveState is additional information, which shows state of pointer like
// button state for mouse.
static bool GetPointerInfo(uint32_t aPointerId, bool& aActiveState);
// CheckPointerCaptureState checks cases, when got/lostpointercapture events
// should be fired.
static void CheckPointerCaptureState(WidgetPointerEvent* aEvent);
+ // Implicitly get and release capture of current pointer for touch.
+ static void ImplicitlyCapturePointer(nsIFrame* aFrame, WidgetEvent* aEvent);
+ static void ImplicitlyReleasePointerCapture(WidgetEvent* aEvent);
+
/**
* GetPointerCapturingFrame returns a target frame of aEvent. If the event is
* a mouse or pointer event, the pointer may be captured by a content. This
* method returns the capturing content's primary frame. Otherwise,
* aFrameUnderCursor.
*
* @param aFrameUnderCursor A frame under cursor.
* @param aEvent A mouse event or pointer event.
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4433,17 +4433,18 @@ PresShell::ContentRemoved(nsIDocument *a
// Notify the ESM that the content has been removed, so that
// it can clean up any state related to the content.
// XXX_jwir3: There is no null check for aDocument necessary, since, even
// though by nsIMutationObserver, aDocument could be null, the
// precondition check that mDocument == aDocument ensures that
// aDocument will not be null (since mDocument can't be null unless
// we're still intializing).
- mPresContext->EventStateManager()->ContentRemoved(aDocument, aChild);
+ mPresContext->EventStateManager()
+ ->ContentRemoved(aDocument, aMaybeContainer, aChild);
nsAutoCauseReflowNotifier crNotifier(this);
// Call this here so it only happens for real content mutations and
// not cases when the frame constructor calls its own methods to force
// frame reconstruction.
nsIContent* oldNextSibling = container->GetChildAt(aIndexInContainer);
@@ -4452,18 +4453,16 @@ PresShell::ContentRemoved(nsIDocument *a
// After removing aChild from tree we should save information about live ancestor
if (mPointerEventTarget) {
MOZ_ASSERT(PointerEventHandler::IsPointerEventEnabled());
if (nsContentUtils::ContentIsDescendantOf(mPointerEventTarget, aChild)) {
mPointerEventTarget = aMaybeContainer;
}
}
- PointerEventHandler::ReleaseIfCaptureByDescendant(aChild);
-
mFrameConstructor->ContentRemoved(aMaybeContainer, aChild, oldNextSibling,
nsCSSFrameConstructor::REMOVE_CONTENT);
if (aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
MOZ_ASSERT(container == aDocument);
NotifyFontSizeInflationEnabledIsDirty();
}
@@ -6836,18 +6835,16 @@ PresShell::HandleEvent(nsIFrame* aFrame,
// If the event is consumed, cancel APZC panning by setting
// mMultipleActionsPrevented.
aEvent->mFlags.mMultipleActionsPrevented = true;
return NS_OK;
}
}
}
- PointerEventHandler::UpdateActivePointerState(aEvent);
-
if (!nsContentUtils::IsSafeToRunScript() &&
aEvent->IsAllowedToDispatchDOMEvent()) {
if (aEvent->mClass == eCompositionEventClass) {
IMEStateManager::OnCompositionEventDiscarded(
aEvent->AsCompositionEvent());
}
#ifdef DEBUG
if (aEvent->IsIMERelatedEvent()) {
@@ -7176,42 +7173,25 @@ PresShell::HandleEvent(nsIFrame* aFrame,
NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(),
"Unexpected document");
nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame();
if (capturingFrame) {
frame = capturingFrame;
}
}
- if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
- // Try to keep frame for following check, because
- // frame can be damaged during CheckPointerCaptureState.
+ // Try to keep frame for following check, because frame can be damaged
+ // during CheckPointerCaptureState.
+ {
AutoWeakFrame frameKeeper(frame);
- // Handle pending pointer capture before any pointer events except
- // gotpointercapture / lostpointercapture.
- PointerEventHandler::CheckPointerCaptureState(pointerEvent);
+ PointerEventHandler::CheckPointerCaptureState(aEvent->AsPointerEvent());
// Prevent application crashes, in case damaged frame.
if (!frameKeeper.IsAlive()) {
frame = nullptr;
}
- // Implicit pointer capture for touch
- if (frame &&
- PointerEventHandler::IsPointerEventImplicitCaptureForTouchEnabled() &&
- pointerEvent->mMessage == ePointerDown &&
- pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
- nsCOMPtr<nsIContent> targetContent;
- frame->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
- while (targetContent && !targetContent->IsElement()) {
- targetContent = targetContent->GetParent();
- }
- if (targetContent) {
- PointerEventHandler::SetPointerCaptureById(pointerEvent->pointerId,
- targetContent);
- }
- }
}
frame = PointerEventHandler::GetPointerCapturingFrame(frame, aEvent);
// Suppress mouse event if it's being targeted at an element inside
// a document which needs events suppressed
if (aEvent->mClass == eMouseEventClass &&
frame->PresContext()->Document()->EventHandlingSuppressed()) {