summaryrefslogtreecommitdiffstats
path: root/dom/events/EventStateManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/events/EventStateManager.cpp')
-rw-r--r--dom/events/EventStateManager.cpp243
1 files changed, 188 insertions, 55 deletions
diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp
index 0ae756211b..3c24cdb30a 100644
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -227,6 +227,9 @@ static nsINode* GetCommonAncestorForMouseUp(
return parent;
}
+LazyLogModule sMouseBoundaryLog("MouseBoundaryEvents");
+LazyLogModule sPointerBoundaryLog("PointerBoundaryEvents");
+
/******************************************************************/
/* mozilla::UITimerCallback */
/******************************************************************/
@@ -264,8 +267,8 @@ UITimerCallback::Notify(nsITimer* aTimer) {
if (XRE_IsParentProcess()) {
hal::BatteryInformation batteryInfo;
hal::GetCurrentBatteryInformation(&batteryInfo);
- glean::power_battery::percentage_when_user_active.AccumulateSamples(
- {uint64_t(batteryInfo.level() * 100)});
+ glean::power_battery::percentage_when_user_active.AccumulateSingleSample(
+ uint64_t(batteryInfo.level() * 100));
}
}
mPreviousCount = gMouseOrKeyboardEventCounter;
@@ -282,10 +285,6 @@ UITimerCallback::GetName(nsACString& aName) {
/* mozilla::OverOutElementsWrapper */
/******************************************************************/
-OverOutElementsWrapper::OverOutElementsWrapper() : mLastOverFrame(nullptr) {}
-
-OverOutElementsWrapper::~OverOutElementsWrapper() = default;
-
NS_IMPL_CYCLE_COLLECTION(OverOutElementsWrapper, mDeepestEnterEventTarget,
mDispatchingOverEventTarget,
mDispatchingOutOrDeepestLeaveEventTarget)
@@ -296,6 +295,116 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OverOutElementsWrapper)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
+void OverOutElementsWrapper::ContentRemoved(nsIContent& aContent) {
+ if (!mDeepestEnterEventTarget) {
+ return;
+ }
+
+ if (!nsContentUtils::ContentIsFlattenedTreeDescendantOf(
+ mDeepestEnterEventTarget, &aContent)) {
+ return;
+ }
+
+ LogModule* const logModule = mType == BoundaryEventType::Mouse
+ ? sMouseBoundaryLog
+ : sPointerBoundaryLog;
+
+ if (!StaticPrefs::
+ dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("The last \"over\" event target (%p) is removed",
+ mDeepestEnterEventTarget.get()));
+ mDeepestEnterEventTarget = nullptr;
+ return;
+ }
+
+ if (mDispatchingOverEventTarget &&
+ (mDeepestEnterEventTarget == mDispatchingOverEventTarget ||
+ nsContentUtils::ContentIsFlattenedTreeDescendantOf(
+ mDispatchingOverEventTarget, &aContent))) {
+ if (mDispatchingOverEventTarget ==
+ mDispatchingOutOrDeepestLeaveEventTarget) {
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("The dispatching \"%s\" event target (%p) is removed",
+ mDeepestEnterEventTargetIsOverEventTarget ? "out" : "leave",
+ mDispatchingOutOrDeepestLeaveEventTarget.get()));
+ mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
+ }
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("The dispatching \"over\" event target (%p) is removed",
+ mDispatchingOverEventTarget.get()));
+ mDispatchingOverEventTarget = nullptr;
+ }
+ if (mDispatchingOutOrDeepestLeaveEventTarget &&
+ (mDeepestEnterEventTarget == mDispatchingOutOrDeepestLeaveEventTarget ||
+ nsContentUtils::ContentIsFlattenedTreeDescendantOf(
+ mDispatchingOutOrDeepestLeaveEventTarget, &aContent))) {
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("The dispatching \"%s\" event target (%p) is removed",
+ mDeepestEnterEventTargetIsOverEventTarget ? "out" : "leave",
+ mDispatchingOutOrDeepestLeaveEventTarget.get()));
+ mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
+ }
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("The last \"%s\" event target (%p) is removed and now the last "
+ "deepest enter target becomes %s(%p)",
+ mDeepestEnterEventTargetIsOverEventTarget ? "over" : "enter",
+ mDeepestEnterEventTarget.get(),
+ aContent.GetFlattenedTreeParent()
+ ? ToString(*aContent.GetFlattenedTreeParent()).c_str()
+ : "nullptr",
+ aContent.GetFlattenedTreeParent()));
+ mDeepestEnterEventTarget = aContent.GetFlattenedTreeParent();
+ mDeepestEnterEventTargetIsOverEventTarget = false;
+}
+
+void OverOutElementsWrapper::DidDispatchOverAndEnterEvent(
+ nsIContent* aOriginalOverTargetInComposedDoc) {
+ mDispatchingOverEventTarget = nullptr;
+
+ // Pointer Events define that once the `pointerover` event target is removed
+ // from the tree, `pointerout` should not be fired on that and the closest
+ // connected ancestor at the target removal should be kept as the deepest
+ // `pointerleave` target. Therefore, we don't need the special handling for
+ // `pointerout` event target if the last `pointerover` target is temporarily
+ // removed from the tree.
+ if (mType == OverOutElementsWrapper::BoundaryEventType::Pointer) {
+ return;
+ }
+
+ // Assume that the caller checks whether aOriginalOverTarget is in the
+ // original document. If we don't enable the strict mouse/pointer event
+ // boundary event dispatching by the pref (see below),
+ // mDeepestEnterEventTarget is set to nullptr when the last "over" target is
+ // removed. Therefore, we cannot check whether aOriginalOverTarget is in the
+ // original document here.
+ if (!aOriginalOverTargetInComposedDoc) {
+ return;
+ }
+ MOZ_ASSERT_IF(mDeepestEnterEventTarget,
+ mDeepestEnterEventTarget->GetComposedDoc() ==
+ aOriginalOverTargetInComposedDoc->GetComposedDoc());
+ // If the "mouseover" event target is removed temporarily while we're
+ // dispatching "mouseover" and "mouseenter" events and the target gets back
+ // under the deepest enter event target, we should restore the "mouseover"
+ // target.
+ if ((!StaticPrefs::
+ dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed() &&
+ !mDeepestEnterEventTarget) ||
+ (!mDeepestEnterEventTargetIsOverEventTarget && mDeepestEnterEventTarget &&
+ nsContentUtils::ContentIsFlattenedTreeDescendantOf(
+ aOriginalOverTargetInComposedDoc, mDeepestEnterEventTarget))) {
+ mDeepestEnterEventTarget = aOriginalOverTargetInComposedDoc;
+ mDeepestEnterEventTargetIsOverEventTarget = true;
+ LogModule* const logModule = mType == BoundaryEventType::Mouse
+ ? sMouseBoundaryLog
+ : sPointerBoundaryLog;
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("The \"over\" event target (%p) is restored",
+ mDeepestEnterEventTarget.get()));
+ }
+}
+
/******************************************************************/
/* mozilla::EventStateManager */
/******************************************************************/
@@ -2169,8 +2278,8 @@ void EventStateManager::MaybeFirePointerCancel(WidgetInputEvent* aEvent) {
WidgetPointerEvent event(aTouchEvent->IsTrusted(), ePointerCancel,
aTouchEvent->mWidget);
- PointerEventHandler::InitPointerEventFromTouch(
- event, *aTouchEvent, *aTouchEvent->mTouches[0], true);
+ PointerEventHandler::InitPointerEventFromTouch(event, *aTouchEvent,
+ *aTouchEvent->mTouches[0]);
event.convertToPointer = false;
presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
@@ -3453,6 +3562,13 @@ void EventStateManager::PostHandleKeyboardEvent(
}
}
+static bool NeedsActiveContentChange(const WidgetMouseEvent* aMouseEvent) {
+ // If the mouse event is a synthesized mouse event due to a touch, do
+ // not set/clear the activation state. Element activation is handled by APZ.
+ return !aMouseEvent ||
+ aMouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_TOUCH;
+}
+
nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
WidgetEvent* aEvent,
nsIFrame* aTargetFrame,
@@ -3696,7 +3812,9 @@ nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
}
// XXX Why do we always set this is active? Active window may be changed
// by a mousedown event listener.
- SetActiveManager(this, activeContent);
+ if (NeedsActiveContentChange(mouseEvent)) {
+ SetActiveManager(this, activeContent);
+ }
} break;
case ePointerCancel:
case ePointerUp: {
@@ -3724,10 +3842,7 @@ nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
PresShell::ReleaseCapturingContent();
WidgetMouseEvent* mouseUpEvent = aEvent->AsMouseEvent();
- // If the mouseup event is a synthesized mouse event due to a touch, do
- // not clear the activation state. Element activation is handled by APZ.
- if (!mouseUpEvent || mouseUpEvent->mInputSource !=
- dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
+ if (NeedsActiveContentChange(mouseUpEvent)) {
ClearGlobalActiveContent(this);
}
if (mouseUpEvent && EventCausesClickEvents(*mouseUpEvent)) {
@@ -4803,6 +4918,10 @@ class EnterLeaveDispatcher {
void EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
nsIContent* aMovingInto) {
+ const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
+ LogModule* const logModule =
+ isPointer ? sPointerBoundaryLog : sMouseBoundaryLog;
+
RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
// If there is no deepest "leave" event target, that means the last "over"
@@ -4816,6 +4935,11 @@ void EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
return;
}
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("NotifyMouseOut: the source event is %s (IsReal()=%s)",
+ ToChar(aMouseEvent->mMessage),
+ aMouseEvent->IsReal() ? "true" : "false"));
+
// XXX If a content node is a container of remove content, it should be
// replaced with them and its children should not be visible. Therefore,
// if the deepest "enter" target is not the last "over" target, i.e., the
@@ -4829,6 +4953,10 @@ void EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
if (RefPtr<nsPresContext> presContext = docshell->GetPresContext()) {
EventStateManager* kidESM = presContext->EventStateManager();
// Not moving into any element in this subdocument
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("Notifying child EventStateManager (%p) of \"out\" "
+ "event...",
+ kidESM));
kidESM->NotifyMouseOut(aMouseEvent, nullptr);
}
}
@@ -4846,7 +4974,6 @@ void EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
// hover state itself, and we have optimizations for hover switching between
// two nearby elements both deep in the DOM tree that would be defeated by
// switching the hover state to null here.
- bool isPointer = aMouseEvent->mClass == ePointerEventClass;
if (!aMovingInto && !isPointer) {
// Unset :hover
SetContentState(nullptr, ElementState::HOVER);
@@ -4859,12 +4986,27 @@ void EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
// "out" events hould be fired only when the deepest "leave" event target
// is the last "over" event target.
if (nsCOMPtr<nsIContent> outEventTarget = wrapper->GetOutEventTarget()) {
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("Dispatching %s event to %s (%p)",
+ isPointer ? "ePointerOut" : "eMouseOut",
+ outEventTarget ? ToString(*outEventTarget).c_str() : "nullptr",
+ outEventTarget.get()));
DispatchMouseOrPointerEvent(aMouseEvent,
isPointer ? ePointerOut : eMouseOut,
outEventTarget, aMovingInto);
}
+
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("Dispatching %s event to %s (%p) and its ancestors",
+ isPointer ? "ePointerLeave" : "eMouseLeave",
+ wrapper->GetDeepestLeaveEventTarget()
+ ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str()
+ : "nullptr",
+ wrapper->GetDeepestLeaveEventTarget()));
leaveDispatcher.Dispatch();
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("Dispatched \"out\" and/or \"leave\" events"));
wrapper->DidDispatchOutAndOrLeaveEvent();
}
@@ -4884,6 +5026,10 @@ void EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
nsIContent* aContent) {
NS_ASSERTION(aContent, "Mouse must be over something");
+ const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
+ LogModule* const logModule =
+ isPointer ? sPointerBoundaryLog : sMouseBoundaryLog;
+
RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
// If we have next "out" event target and it's the new "over" target, we don't
@@ -4897,6 +5043,11 @@ void EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
return;
}
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("NotifyMouseOver: the source event is %s (IsReal()=%s)",
+ ToChar(aMouseEvent->mMessage),
+ aMouseEvent->IsReal() ? "true" : "false"));
+
// Check to see if we're a subdocument and if so update the parent
// document's ESM state to indicate that the mouse is over the
// content associated with our subdocument.
@@ -4906,6 +5057,10 @@ void EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
if (PresShell* parentPresShell = parentDoc->GetPresShell()) {
RefPtr<EventStateManager> parentESM =
parentPresShell->GetPresContext()->EventStateManager();
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("Notifying parent EventStateManager (%p) of \"over\" "
+ "event...",
+ parentESM.get()));
parentESM->NotifyMouseOver(aMouseEvent, docContent);
}
}
@@ -4922,8 +5077,6 @@ void EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
nsCOMPtr<nsIContent> deepestLeaveEventTarget =
wrapper->GetDeepestLeaveEventTarget();
- bool isPointer = aMouseEvent->mClass == ePointerEventClass;
-
EnterLeaveDispatcher enterDispatcher(this, aContent, deepestLeaveEventTarget,
aMouseEvent,
isPointer ? ePointerEnter : eMouseEnter);
@@ -4939,12 +5092,26 @@ void EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
// Fire mouseover
// XXX If aContent has already been removed from the DOM tree, what should we
// do? At least, dispatching `mouseover` on it is odd.
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("Dispatching %s event to %s (%p)",
+ isPointer ? "ePointerOver" : "eMoustOver",
+ aContent ? ToString(*aContent).c_str() : "nullptr", aContent));
wrapper->mLastOverFrame = DispatchMouseOrPointerEvent(
aMouseEvent, isPointer ? ePointerOver : eMouseOver, aContent,
deepestLeaveEventTarget);
+
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("Dispatching %s event to %s (%p) and its ancestors",
+ isPointer ? "ePointerEnter" : "eMouseEnter",
+ aContent ? ToString(*aContent).c_str() : "nullptr", aContent));
enterDispatcher.Dispatch();
- wrapper->DidDispatchOverAndEnterEvent();
+ MOZ_LOG(logModule, LogLevel::Info,
+ ("Dispatched \"over\" and \"enter\" events (the original \"over\" "
+ "event target was in the document %p, and now in %p)",
+ aContent->GetComposedDoc(), mDocument.get()));
+ wrapper->DidDispatchOverAndEnterEvent(
+ aContent->GetComposedDoc() == mDocument ? aContent : nullptr);
}
// Returns the center point of the window's client area. This is
@@ -5135,11 +5302,13 @@ OverOutElementsWrapper* EventStateManager::GetWrapperByEventID(
if (!pointer) {
MOZ_ASSERT(aEvent->AsMouseEvent() != nullptr);
if (!mMouseEnterLeaveHelper) {
- mMouseEnterLeaveHelper = new OverOutElementsWrapper();
+ mMouseEnterLeaveHelper = new OverOutElementsWrapper(
+ OverOutElementsWrapper::BoundaryEventType::Mouse);
}
return mMouseEnterLeaveHelper;
}
- return mPointersEnterLeaveHelper.GetOrInsertNew(pointer->pointerId);
+ return mPointersEnterLeaveHelper.GetOrInsertNew(
+ pointer->pointerId, OverOutElementsWrapper::BoundaryEventType::Pointer);
}
/* static */
@@ -6895,40 +7064,4 @@ bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
}
-void OverOutElementsWrapper::ContentRemoved(nsIContent& aContent) {
- if (!mDeepestEnterEventTarget) {
- return;
- }
-
- if (!nsContentUtils::ContentIsFlattenedTreeDescendantOf(
- mDeepestEnterEventTarget, &aContent)) {
- return;
- }
-
- if (!StaticPrefs::
- dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
- mDeepestEnterEventTarget = nullptr;
- return;
- }
-
- if (mDispatchingOverEventTarget &&
- (mDeepestEnterEventTarget == mDispatchingOverEventTarget ||
- nsContentUtils::ContentIsFlattenedTreeDescendantOf(
- mDispatchingOverEventTarget, &aContent))) {
- if (mDispatchingOverEventTarget ==
- mDispatchingOutOrDeepestLeaveEventTarget) {
- mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
- }
- mDispatchingOverEventTarget = nullptr;
- }
- if (mDispatchingOutOrDeepestLeaveEventTarget &&
- (mDeepestEnterEventTarget == mDispatchingOutOrDeepestLeaveEventTarget ||
- nsContentUtils::ContentIsFlattenedTreeDescendantOf(
- mDispatchingOutOrDeepestLeaveEventTarget, &aContent))) {
- mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
- }
- mDeepestEnterEventTarget = aContent.GetFlattenedTreeParent();
- mDeepestEnterEventTargetIsOverEventTarget = false;
-}
-
} // namespace mozilla