summaryrefslogtreecommitdiff
path: root/dom
diff options
context:
space:
mode:
authorMartok <martok@martoks-place.de>2022-11-27 16:35:25 +0100
committerMartok <martok@martoks-place.de>2022-11-27 16:35:25 +0100
commit814fa6e3baf41cd493f75a39f458ecd9a5c5508f (patch)
tree207735c3904213f98983084e8c997b5b001df25c /dom
parent541508cd83eb4214895ad4b00f606e31a151bc36 (diff)
downloaduxp-814fa6e3baf41cd493f75a39f458ecd9a5c5508f.tar.gz
Issue #2030 - (chore) refactor event dispatch functions
Based on selected bits of M-C 1461708: - EventStateManager::CheckForAndDispatchClick() to early-return style - split EventStateManager::CheckForAndDispatchClick() into: EventCausesClickEvents, PostHandleMouseUp, DispatchClickEvents - Move implementation of UIEvent::GetRangeParent() and UIEvent::RangeOffset() to nsLayoutUtils
Diffstat (limited to 'dom')
-rw-r--r--dom/events/EventStateManager.cpp210
-rw-r--r--dom/events/EventStateManager.h71
-rw-r--r--dom/events/UIEvent.cpp39
3 files changed, 223 insertions, 97 deletions
diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp
index 9f06deb2ba..3dcc6cef47 100644
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -3171,14 +3171,11 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
case eMouseUp:
{
ClearGlobalActiveContent(this);
- WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
- if (mouseEvent && mouseEvent->IsReal()) {
- if (!mCurrentTarget) {
- GetEventTarget();
- }
+ WidgetMouseEvent* mouseUpEvent = aEvent->AsMouseEvent();
+ if (mouseUpEvent && EventCausesClickEvents(*mouseUpEvent)) {
// Make sure to dispatch the click even if there is no frame for
// the current target element. This is required for Web compatibility.
- ret = CheckForAndDispatchClick(mouseEvent, aStatus);
+ ret = PostHandleMouseUp(mouseUpEvent, aStatus);
}
nsIPresShell *shell = presContext->GetPresShell();
@@ -4645,89 +4642,160 @@ EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
return NS_OK;
}
+// static
+bool
+EventStateManager::EventCausesClickEvents(const WidgetMouseEvent& aMouseEvent)
+{
+ if (NS_WARN_IF(aMouseEvent.mMessage != eMouseUp)) {
+ return false;
+ }
+ // If the mouseup event is synthesized event, we don't need to dispatch
+ // click events.
+ if (!aMouseEvent.IsReal()) {
+ return false;
+ }
+ // If mouse is still over same element, clickcount will be > 1.
+ // If it has moved it will be zero, so no click.
+ if (!aMouseEvent.mClickCount) {
+ return false;
+ }
+ // Check that the window isn't disabled before firing a click
+ // (see bug 366544).
+ return !(aMouseEvent.mWidget && !aMouseEvent.mWidget->IsEnabled());
+}
+
nsresult
-EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
+EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aMouseUpEvent,
nsEventStatus* aStatus,
EventMessage aMessage,
nsIPresShell* aPresShell,
- nsIContent* aMouseTarget,
+ nsIContent* aMouseUpContent,
nsWeakFrame aCurrentTarget,
bool aNoContentDispatch)
{
- WidgetMouseEvent event(aEvent->IsTrusted(), aMessage,
- aEvent->mWidget, WidgetMouseEvent::eReal);
-
- event.mRefPoint = aEvent->mRefPoint;
- event.mClickCount = aEvent->mClickCount;
- event.mModifiers = aEvent->mModifiers;
- event.buttons = aEvent->buttons;
- event.mTime = aEvent->mTime;
- event.mTimeStamp = aEvent->mTimeStamp;
+ MOZ_ASSERT(aMouseUpEvent);
+ MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent));
+ MOZ_ASSERT(aMouseUpContent || aCurrentTarget || aOverrideClickTarget);
+
+ WidgetMouseEvent event(aMouseUpEvent->IsTrusted(), aMessage,
+ aMouseUpEvent->mWidget, WidgetMouseEvent::eReal);
+ event.mRefPoint = aMouseUpEvent->mRefPoint;
+ event.mClickCount = aMouseUpEvent->mClickCount;
+ event.mModifiers = aMouseUpEvent->mModifiers;
+ event.buttons = aMouseUpEvent->buttons;
+ event.mTime = aMouseUpEvent->mTime;
+ event.mTimeStamp = aMouseUpEvent->mTimeStamp;
event.mFlags.mNoContentDispatch = aNoContentDispatch;
- event.button = aEvent->button;
- event.inputSource = aEvent->inputSource;
+ event.button = aMouseUpEvent->button;
+ event.inputSource = aMouseUpEvent->inputSource;
- return aPresShell->HandleEventWithTarget(&event, aCurrentTarget,
- aMouseTarget, aStatus);
+ // Use local event status for each click event dispatching since it'll be
+ // cleared by EventStateManager::PreHandleEvent(). Therefore, dispatching
+ // an event means that previous event status will be ignored.
+ nsEventStatus status = nsEventStatus_eIgnore;
+ nsresult rv = aPresShell->HandleEventWithTarget(&event, aCurrentTarget,
+ aMouseUpContent, &status);
+ // If current status is nsEventStatus_eConsumeNoDefault, we don't need to
+ // overwrite it.
+ if (*aStatus == nsEventStatus_eConsumeNoDefault) {
+ return rv;
+ }
+ // If new status is nsEventStatus_eConsumeNoDefault or
+ // nsEventStatus_eConsumeDoDefault, use it.
+ if (status == nsEventStatus_eConsumeNoDefault ||
+ status == nsEventStatus_eConsumeDoDefault) {
+ *aStatus = status;
+ return rv;
+ }
+ // Otherwise, keep the original status.
+ return rv;
}
nsresult
-EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
- nsEventStatus* aStatus)
+EventStateManager::PostHandleMouseUp(WidgetMouseEvent* aMouseUpEvent,
+ nsEventStatus* aStatus)
{
- nsresult ret = NS_OK;
+ MOZ_ASSERT(aMouseUpEvent);
+ MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent));
+ MOZ_ASSERT(aStatus);
+
+ nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
+ if (!presShell) {
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsIContent> mouseUpContent = GetEventTargetContent(aMouseUpEvent);
+ // Click events apply to *elements* not nodes. At this point the target
+ // content may have been reset to some non-element content, and so we need
+ // to walk up the closest ancestor element, just like we do in
+ // nsPresShell::HandlePositionedEvent.
+ while (mouseUpContent && !mouseUpContent->IsElement()) {
+ mouseUpContent = mouseUpContent->GetFlattenedTreeParent();
+ }
+
+ if (!mouseUpContent && !mCurrentTarget) {
+ return NS_OK;
+ }
+
+ // Fire click events if the event target is still available.
+ nsresult rv = DispatchClickEvents(presShell, aMouseUpEvent, aStatus,
+ mouseUpContent);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ return NS_OK;
+}
+
+nsresult
+EventStateManager::DispatchClickEvents(nsIPresShell* aPresShell,
+ WidgetMouseEvent* aMouseUpEvent,
+ nsEventStatus* aStatus,
+ nsIContent* aMouseUpContent)
+{
+ MOZ_ASSERT(aPresShell);
+ MOZ_ASSERT(aMouseUpEvent);
+ MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent));
+ MOZ_ASSERT(aStatus);
+ MOZ_ASSERT(aMouseUpContent || mCurrentTarget || aOverrideClickTarget);
+
+ bool notDispatchToContents =
+ (aMouseUpEvent->button == WidgetMouseEvent::eMiddleButton ||
+ aMouseUpEvent->button == WidgetMouseEvent::eRightButton);
+
+ bool fireAuxClick = notDispatchToContents;
+
- //If mouse is still over same element, clickcount will be > 1.
- //If it has moved it will be zero, so no click.
- if (aEvent->mClickCount) {
- //Check that the window isn't disabled before firing a click
- //(see bug 366544).
- if (aEvent->mWidget && !aEvent->mWidget->IsEnabled()) {
+ // HandleEvent clears out mCurrentTarget which we might need again
+ nsWeakFrame currentTarget = mCurrentTarget;
+ nsresult ret =
+ InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseClick,
+ aPresShell, aMouseUpContent, currentTarget,
+ notDispatchToContents);
+ if (NS_WARN_IF(NS_FAILED(ret))) {
+ return ret;
+ }
+
+ // Fire double click event if click count is 2.
+ if (aMouseUpEvent->mClickCount == 2 &&
+ aMouseUpContent && aMouseUpContent->IsInComposedDoc()) {
+ ret = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseDoubleClick,
+ aPresShell, aMouseUpContent, currentTarget,
+ notDispatchToContents);
+ if (NS_WARN_IF(NS_FAILED(ret))) {
return ret;
- }
- //fire click
- bool notDispatchToContents =
- (aEvent->button == WidgetMouseEvent::eMiddleButton ||
- aEvent->button == WidgetMouseEvent::eRightButton);
-
- bool fireAuxClick = notDispatchToContents;
-
- nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
- if (presShell) {
- nsCOMPtr<nsIContent> mouseContent = GetEventTargetContent(aEvent);
- // Click events apply to *elements* not nodes. At this point the target
- // content may have been reset to some non-element content, and so we need
- // to walk up the closest ancestor element, just like we do in
- // nsPresShell::HandlePositionedEvent.
- while (mouseContent && !mouseContent->IsElement()) {
- mouseContent = mouseContent->GetParent();
- }
- if (!mouseContent && !mCurrentTarget) {
- return NS_OK;
- }
+ }
+ }
- // HandleEvent clears out mCurrentTarget which we might need again
- nsWeakFrame currentTarget = mCurrentTarget;
- ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseClick,
- presShell, mouseContent, currentTarget,
- notDispatchToContents);
-
- if (NS_SUCCEEDED(ret) && aEvent->mClickCount == 2 &&
- mouseContent && mouseContent->IsInComposedDoc()) {
- //fire double click
- ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseDoubleClick,
- presShell, mouseContent, currentTarget,
- notDispatchToContents);
- }
- if (NS_SUCCEEDED(ret) && mouseContent && fireAuxClick &&
- mouseContent->IsInComposedDoc()) {
- ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseAuxClick,
- presShell, mouseContent, currentTarget,
- false);
- }
- }
+ // Fire auxclick even if necessary.
+ if (fireAuxClick &&
+ aMouseUpContent && aMouseUpContent->IsInComposedDoc()) {
+ ret = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseAuxClick,
+ aPresShell, aMouseUpContent, currentTarget,
+ false);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(ret), "Failed to dispatch eMouseAuxClick");
}
+
return ret;
}
diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h
index 819c93b602..6bf457b842 100644
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -414,16 +414,79 @@ protected:
*/
void UpdateDragDataTransfer(WidgetDragEvent* dragEvent);
- static nsresult InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
+ /**
+ * InitAndDispatchClickEvent() dispatches a click event.
+ *
+ * @param aMouseUpEvent eMouseUp event which causes the click event.
+ * EventCausesClickEvents() must return true
+ * if this event is set to it.
+ * @param aStatus Returns the result of click event.
+ * If the status indicates consumed, the
+ * value won't be overwritten with
+ * nsEventStatus_eIgnore.
+ * @param aMessage Should be eMouseClick, eMouseDoubleClick or
+ * eMouseAuxClick.
+ * @param aPresShell The PresShell.
+ * @param aMouseUpContent The event target of aMouseUpEvent.
+ * @param aCurrentTarget Current target of the caller.
+ * @param aNoContentDispatch true if the event shouldn't be exposed to
+ * web contents (although will be fired on
+ * document and window).
+ * @param aOverrideClickTarget Preferred click event target. If this is
+ * not nullptr, aMouseUpContent and
+ * aCurrentTarget are ignored.
+ */
+ static nsresult InitAndDispatchClickEvent(WidgetMouseEvent* aMouseUpEvent,
nsEventStatus* aStatus,
EventMessage aMessage,
nsIPresShell* aPresShell,
- nsIContent* aMouseTarget,
+ nsIContent* aMouseUpContent,
nsWeakFrame aCurrentTarget,
bool aNoContentDispatch);
nsresult SetClickCount(WidgetMouseEvent* aEvent, nsEventStatus* aStatus);
- nsresult CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
- nsEventStatus* aStatus);
+
+ /**
+ * EventCausesClickEvents() returns true when aMouseEvent is an eMouseUp
+ * event and it should cause eMouseClick, eMouseDoubleClick and/or
+ * eMouseAuxClick events. Note that this method assumes that
+ * aMouseEvent.mClickCount has already been initialized with SetClickCount().
+ */
+ static bool EventCausesClickEvents(const WidgetMouseEvent& aMouseEvent);
+
+ /**
+ * PostHandleMouseUp() handles default actions of eMouseUp event.
+ *
+ * @param aMouseUpEvent eMouseUp event which causes the click event.
+ * EventCausesClickEvents() must return true
+ * if this event is set to it.
+ * @param aStatus Returns the result of event status.
+ * If one of dispatching event is consumed or
+ * this does something as default action,
+ * returns nsEventStatus_eConsumeNoDefault.
+ */
+ nsresult PostHandleMouseUp(WidgetMouseEvent* aMouseUpEvent,
+ nsEventStatus* aStatus);
+
+ /**
+ * DispatchClickEvents() dispatches eMouseClick, eMouseDoubleClick and
+ * eMouseAuxClick events for aMouseUpEvent. aMouseUpEvent should cause
+ * click event.
+ *
+ * @param aPresShell The PresShell.
+ * @param aMouseUpEvent eMouseUp event which causes the click event.
+ * EventCausesClickEvents() must return true
+ * if this event is set to it.
+ * @param aStatus Returns the result of event status.
+ * If one of dispatching click event is
+ * consumed, returns
+ * nsEventStatus_eConsumeNoDefault.
+ * @param aMouseUpContent The event target of aMouseUpEvent.
+ */
+ nsresult DispatchClickEvents(nsIPresShell* aPresShell,
+ WidgetMouseEvent* aMouseUpEvent,
+ nsEventStatus* aStatus,
+ nsIContent* aMouseUpContent);
+
void EnsureDocument(nsPresContext* aPresContext);
void FlushPendingEvents(nsPresContext* aPresContext);
diff --git a/dom/events/UIEvent.cpp b/dom/events/UIEvent.cpp
index 09544f0b81..40015f65eb 100644
--- a/dom/events/UIEvent.cpp
+++ b/dom/events/UIEvent.cpp
@@ -228,26 +228,20 @@ UIEvent::GetWhich(uint32_t* aWhich)
already_AddRefed<nsINode>
UIEvent::GetRangeParent()
{
- nsIFrame* targetFrame = nullptr;
-
- if (mPresContext) {
- targetFrame = mPresContext->EventStateManager()->GetEventTarget();
+ if (NS_WARN_IF(!mPresContext)) {
+ return nullptr;
}
- if (targetFrame) {
- nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent,
- targetFrame);
- nsCOMPtr<nsIContent> parent = targetFrame->GetContentOffsetsFromPoint(pt).content;
- if (parent) {
- if (parent->ChromeOnlyAccess() &&
- !nsContentUtils::CanAccessNativeAnon()) {
- return nullptr;
- }
- return parent.forget();
- }
+ nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
+ if (NS_WARN_IF(!presShell)) {
+ return nullptr;
}
- return nullptr;
+ nsCOMPtr<nsIContent> container;
+ nsLayoutUtils::GetContainerAndOffsetAtEvent(presShell, mEvent,
+ getter_AddRefs(container),
+ nullptr);
+ return container.forget();
}
NS_IMETHODIMP
@@ -273,18 +267,19 @@ UIEvent::GetRangeOffset(int32_t* aRangeOffset)
int32_t
UIEvent::RangeOffset() const
{
- if (!mPresContext) {
+ if (NS_WARN_IF(!mPresContext)) {
return 0;
}
- nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
- if (!targetFrame) {
+ nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
+ if (NS_WARN_IF(!presShell)) {
return 0;
}
- nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent,
- targetFrame);
- return targetFrame->GetContentOffsetsFromPoint(pt).offset;
+ int32_t offset = 0;
+ nsLayoutUtils::GetContainerAndOffsetAtEvent(presShell, mEvent,
+ nullptr, &offset);
+ return offset;
}
nsIntPoint