diff options
author | Martok <martok@martoks-place.de> | 2022-11-27 16:35:25 +0100 |
---|---|---|
committer | Martok <martok@martoks-place.de> | 2022-11-27 16:35:25 +0100 |
commit | 814fa6e3baf41cd493f75a39f458ecd9a5c5508f (patch) | |
tree | 207735c3904213f98983084e8c997b5b001df25c /dom | |
parent | 541508cd83eb4214895ad4b00f606e31a151bc36 (diff) | |
download | uxp-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.cpp | 210 | ||||
-rw-r--r-- | dom/events/EventStateManager.h | 71 | ||||
-rw-r--r-- | dom/events/UIEvent.cpp | 39 |
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 |