Bug 1461708 - part 2: Split EventStateManager::CheckForAndDispatchClick() r=smaug

This patch splits EventStateManager::CheckForAndDispatchClick().  One is for
handling default action of eMouseUp, the other is for dispatching click events.

This makes it easier to add other default actions after dispatching click
events.

Differential Revision: https://phabricator.services.mozilla.com/D7849

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2018-10-10 12:01:57 +00:00
Родитель 423736e78f
Коммит bfb564efb0
2 изменённых файлов: 168 добавлений и 60 удалений

Просмотреть файл

@ -3378,17 +3378,14 @@ 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.
RefPtr<EventStateManager> esm =
ESMFromContentOrThis(aOverrideClickTarget);
ret = esm->CheckForAndDispatchClick(mouseEvent, aStatus,
aOverrideClickTarget);
ret = esm->PostHandleMouseUp(mouseUpEvent, aStatus,
aOverrideClickTarget);
}
nsIPresShell *shell = presContext->GetPresShell();
@ -4955,30 +4952,56 @@ 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,
AutoWeakFrame aCurrentTarget,
bool aNoContentDispatch,
nsIContent* aOverrideClickTarget)
{
WidgetMouseEvent event(aEvent->IsTrusted(), aMessage,
aEvent->mWidget, WidgetMouseEvent::eReal);
MOZ_ASSERT(aMouseUpEvent);
MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent));
MOZ_ASSERT(aMouseUpContent || aCurrentTarget || aOverrideClickTarget);
event.mRefPoint = aEvent->mRefPoint;
event.mClickCount = aEvent->mClickCount;
event.mModifiers = aEvent->mModifiers;
event.buttons = aEvent->buttons;
event.mTime = aEvent->mTime;
event.mTimeStamp = aEvent->mTimeStamp;
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.pointerId = aEvent->pointerId;
event.inputSource = aEvent->inputSource;
nsIContent* target = aMouseTarget;
event.button = aMouseUpEvent->button;
event.pointerId = aMouseUpEvent->pointerId;
event.inputSource = aMouseUpEvent->inputSource;
nsIContent* target = aMouseUpContent;
nsIFrame* targetFrame = aCurrentTarget;
if (aOverrideClickTarget) {
target = aOverrideClickTarget;
@ -4990,52 +5013,65 @@ EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
}
nsresult
EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
nsEventStatus* aStatus,
nsIContent* aOverrideClickTarget)
EventStateManager::PostHandleMouseUp(WidgetMouseEvent* aMouseUpEvent,
nsEventStatus* aStatus,
nsIContent* aOverrideClickTarget)
{
// 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) {
return NS_OK;
}
// Check that the window isn't disabled before firing a click
// (see bug 366544).
if (aEvent->mWidget && !aEvent->mWidget->IsEnabled()) {
return NS_OK;
}
// Fire click events if the event target is still available.
bool notDispatchToContents =
(aEvent->button == WidgetMouseEvent::eMiddleButton ||
aEvent->button == WidgetMouseEvent::eRightButton);
bool fireAuxClick = notDispatchToContents;
MOZ_ASSERT(aMouseUpEvent);
MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent));
MOZ_ASSERT(aStatus);
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
if (!presShell) {
return NS_OK;
}
nsCOMPtr<nsIContent> mouseContent = GetEventTargetContent(aEvent);
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::HandleEvent.
while (mouseContent && !mouseContent->IsElement()) {
mouseContent = mouseContent->GetFlattenedTreeParent();
while (mouseUpContent && !mouseUpContent->IsElement()) {
mouseUpContent = mouseUpContent->GetFlattenedTreeParent();
}
if (!mouseContent && !mCurrentTarget && !aOverrideClickTarget) {
if (!mouseUpContent && !mCurrentTarget && !aOverrideClickTarget) {
return NS_OK;
}
// Fire click events if the event target is still available.
nsresult rv = DispatchClickEvents(presShell, aMouseUpEvent, aStatus,
mouseUpContent, aOverrideClickTarget);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsresult
EventStateManager::DispatchClickEvents(nsIPresShell* aPresShell,
WidgetMouseEvent* aMouseUpEvent,
nsEventStatus* aStatus,
nsIContent* aMouseUpContent,
nsIContent* aOverrideClickTarget)
{
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;
// HandleEvent clears out mCurrentTarget which we might need again
AutoWeakFrame currentTarget = mCurrentTarget;
nsresult rv =
InitAndDispatchClickEvent(aEvent, aStatus, eMouseClick,
presShell, mouseContent, currentTarget,
InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseClick,
aPresShell, aMouseUpContent, currentTarget,
notDispatchToContents,
aOverrideClickTarget);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -5043,10 +5079,10 @@ EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
}
// Fire double click event if click count is 2.
if (aEvent->mClickCount == 2 &&
mouseContent && mouseContent->IsInComposedDoc()) {
rv = InitAndDispatchClickEvent(aEvent, aStatus, eMouseDoubleClick,
presShell, mouseContent, currentTarget,
if (aMouseUpEvent->mClickCount == 2 &&
aMouseUpContent && aMouseUpContent->IsInComposedDoc()) {
rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseDoubleClick,
aPresShell, aMouseUpContent, currentTarget,
notDispatchToContents,
aOverrideClickTarget);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -5056,9 +5092,9 @@ EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
// Fire auxclick even if necessary.
if (fireAuxClick &&
mouseContent && mouseContent->IsInComposedDoc()) {
rv = InitAndDispatchClickEvent(aEvent, aStatus, eMouseAuxClick,
presShell, mouseContent, currentTarget,
aMouseUpContent && aMouseUpContent->IsInComposedDoc()) {
rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseAuxClick,
aPresShell, aMouseUpContent, currentTarget,
false, aOverrideClickTarget);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to dispatch eMouseAuxClick");
}

Просмотреть файл

@ -112,6 +112,7 @@ public:
* also contain any centralized event processing which must occur after
* DOM and frame processing.
*/
MOZ_CAN_RUN_SCRIPT_BOUNDARY
nsresult PostHandleEvent(nsPresContext* aPresContext,
WidgetEvent* aEvent,
nsIFrame* aTargetFrame,
@ -461,19 +462,90 @@ 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.
* @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.
*/
MOZ_CAN_RUN_SCRIPT
static nsresult InitAndDispatchClickEvent(WidgetMouseEvent* aMouseUpEvent,
nsEventStatus* aStatus,
EventMessage aMessage,
nsIPresShell* aPresShell,
nsIContent* aMouseTarget,
nsIContent* aMouseUpContent,
AutoWeakFrame aCurrentTarget,
bool aNoContentDispatch,
nsIContent* aOverrideClickTarget);
nsresult SetClickCount(WidgetMouseEvent* aEvent, nsEventStatus* aStatus,
nsIContent* aOverrideClickTarget = nullptr);
nsresult CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
nsEventStatus* aStatus,
nsIContent* aOverrideClickTarget);
/**
* 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.
* @param aOverrideClickTarget Preferred click event target. If nullptr,
* aMouseUpEvent target and current target
* are used.
*/
MOZ_CAN_RUN_SCRIPT
nsresult PostHandleMouseUp(WidgetMouseEvent* aMouseUpEvent,
nsEventStatus* aStatus,
nsIContent* aOverrideClickTarget);
/**
* 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.
* @param aOverrideClickTarget Preferred click event target. If this is
* not nullptr, aMouseUpContent and
* current target frame of the ESM are ignored.
*/
MOZ_CAN_RUN_SCRIPT
nsresult DispatchClickEvents(nsIPresShell* aPresShell,
WidgetMouseEvent* aMouseUpEvent,
nsEventStatus* aStatus,
nsIContent* aMouseUpContent,
nsIContent* aOverrideClickTarget);
void EnsureDocument(nsPresContext* aPresContext);
void FlushPendingEvents(nsPresContext* aPresContext);