Bug 1466208 - part 27: Create PresShell::EventHandler::HandleEventUsingCoordinates() r=smaug

Now, the block in HandleEvent(), which handles event using coordinates is
less than 200 lines.  Perhaps, this is good amount to be split to a method.

This patch just moves the block to a new method.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2019-03-02 00:03:01 +00:00
parent 10be4fc289
commit 291457b9da
2 changed files with 190 additions and 162 deletions

View File

@ -6517,168 +6517,8 @@ nsresult PresShell::EventHandler::HandleEvent(nsIFrame* aFrame,
}
if (aGUIEvent->IsUsingCoordinates()) {
// Flush pending notifications to handle the event with the latest layout.
// But if it causes destroying the frame for mPresShell, stop handling the
// event. (why?)
AutoWeakFrame weakFrame(aFrame);
MaybeFlushPendingNotifications(aGUIEvent);
if (!weakFrame.IsAlive()) {
*aEventStatus = nsEventStatus_eIgnore;
return NS_OK;
}
// XXX Retrieving capturing content here. However, some of the following
// methods allow to run script. So, isn't it possible the capturing
// content outdated?
nsCOMPtr<nsIContent> capturingContent =
EventHandler::GetCapturingContentFor(aGUIEvent);
if (GetDocument() && aGUIEvent->mClass == eTouchEventClass) {
Document::UnlockPointer();
}
nsIFrame* frameForPresShell = MaybeFlushThrottledStyles(aFrame);
if (NS_WARN_IF(!frameForPresShell)) {
return NS_OK;
}
bool isCapturingContentIgnored = false;
bool isCaptureRetargeted = false;
nsIFrame* rootFrameToHandleEvent = ComputeRootFrameToHandleEvent(
frameForPresShell, aGUIEvent, capturingContent,
&isCapturingContentIgnored, &isCaptureRetargeted);
if (isCapturingContentIgnored) {
capturingContent = nullptr;
}
// The order to generate pointer event is
// 1. check pending pointer capture.
// 2. check if there is a capturing content.
// 3. hit test
// 4. dispatch pointer events
// 5. check whether the targets of all Touch instances are in the same
// document and suppress invalid instances.
// 6. dispatch mouse or touch events.
// Try to keep frame for following check, because frame can be damaged
// during MaybeProcessPointerCapture.
{
AutoWeakFrame frameKeeper(rootFrameToHandleEvent);
PointerEventHandler::MaybeProcessPointerCapture(aGUIEvent);
// Prevent application crashes, in case damaged frame.
if (!frameKeeper.IsAlive()) {
NS_WARNING("Nothing to handle this event!");
return NS_OK;
}
}
// Only capture mouse events and pointer events.
nsCOMPtr<nsIContent> pointerCapturingContent =
PointerEventHandler::GetPointerCapturingContent(aGUIEvent);
if (pointerCapturingContent) {
rootFrameToHandleEvent = pointerCapturingContent->GetPrimaryFrame();
if (!rootFrameToHandleEvent) {
return HandleEventWithPointerCapturingContentWithoutItsFrame(
aFrame, aGUIEvent, pointerCapturingContent, aEventStatus);
}
}
WidgetMouseEvent* mouseEvent = aGUIEvent->AsMouseEvent();
bool isWindowLevelMouseExit =
(aGUIEvent->mMessage == eMouseExitFromWidget) &&
(mouseEvent && mouseEvent->mExitFrom == WidgetMouseEvent::eTopLevel);
// Get the frame at the event point. However, don't do this if we're
// capturing and retargeting the event because the captured frame will
// be used instead below. Also keep using the root frame if we're dealing
// with a window-level mouse exit event since we want to start sending
// mouse out events at the root EventStateManager.
EventTargetData eventTargetData(mPresShell, rootFrameToHandleEvent);
if (!isCaptureRetargeted && !isWindowLevelMouseExit &&
!pointerCapturingContent) {
if (!ComputeEventTargetFrameAndPresShellAtEventPoint(
rootFrameToHandleEvent, aGUIEvent, &eventTargetData)) {
*aEventStatus = nsEventStatus_eIgnore;
return NS_OK;
}
}
// if a node is capturing the mouse, check if the event needs to be
// retargeted at the capturing content instead. This will be the case when
// capture retargeting is being used, no frame was found or the frame's
// content is not a descendant of the capturing content.
if (capturingContent && !pointerCapturingContent &&
(gCaptureInfo.mRetargetToElement ||
!eventTargetData.mFrame->GetContent() ||
!nsContentUtils::ContentIsCrossDocDescendantOf(
eventTargetData.mFrame->GetContent(), capturingContent))) {
// A check was already done above to ensure that capturingContent is
// in this presshell.
NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(),
"Unexpected document");
nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame();
if (capturingFrame) {
eventTargetData.SetFrameAndComputePresShell(capturingFrame);
}
}
if (NS_WARN_IF(!eventTargetData.mFrame)) {
return NS_OK;
}
// Suppress mouse event if it's being targeted at an element inside
// a document which needs events suppressed
if (MaybeDiscardOrDelayMouseEvent(eventTargetData.mFrame, aGUIEvent)) {
return NS_OK;
}
// Check if we have an active EventStateManager which isn't the
// EventStateManager of the current PresContext. If that is the case, and
// mouse is over some ancestor document, forward event handling to the
// active document. This way content can get mouse events even when mouse
// is over the chrome or outside the window.
if (eventTargetData.MaybeRetargetToActiveDocument(aGUIEvent) &&
NS_WARN_IF(!eventTargetData.mFrame)) {
return NS_OK;
}
if (!eventTargetData.ComputeElementFromFrame(aGUIEvent)) {
return NS_OK;
}
// Note that even if ComputeElementFromFrame() returns true,
// eventTargetData.mContent can be nullptr here.
// Dispatch a pointer event if Pointer Events is enabled. Note that if
// pointer event listeners change the layout, eventTargetData is
// automatically updated.
if (!DispatchPrecedingPointerEvent(
aFrame, aGUIEvent, pointerCapturingContent, aDontRetargetEvents,
&eventTargetData, aEventStatus)) {
return NS_OK;
}
// frame could be null after dispatching pointer events.
// XXX Despite of this comment, we update the event target data outside
// DispatchPrecedingPointerEvent(). Can we make it call
// UpdateTouchEventTarget()?
eventTargetData.UpdateTouchEventTarget(aGUIEvent);
// Handle the event in the correct shell.
// We pass the subshell's root frame as the frame to start from. This is
// the only correct alternative; if the event was captured then it
// must have been captured by us or some ancestor shell and we
// now ask the subshell to dispatch it normally.
eventTargetData.mPresShell->PushCurrentEventInfo(eventTargetData.mFrame,
eventTargetData.mContent);
EventHandler eventHandler(*eventTargetData.mPresShell);
nsresult rv = eventHandler.HandleEventInternal(
aGUIEvent, aEventStatus, true, eventTargetData.mOverrideClickTarget);
#ifdef DEBUG
eventTargetData.mPresShell->ShowEventTargetDebug();
#endif
eventTargetData.mPresShell->PopCurrentEventInfo();
return rv;
return HandleEventUsingCoordinates(aFrame, aGUIEvent, aEventStatus,
aDontRetargetEvents);
}
nsresult rv = NS_OK;
@ -6785,6 +6625,177 @@ nsresult PresShell::EventHandler::HandleEvent(nsIFrame* aFrame,
return rv;
}
nsresult PresShell::EventHandler::HandleEventUsingCoordinates(
nsIFrame* aFrameForPresShell, WidgetGUIEvent* aGUIEvent,
nsEventStatus* aEventStatus, bool aDontRetargetEvents) {
MOZ_ASSERT(aGUIEvent);
MOZ_ASSERT(aGUIEvent->IsUsingCoordinates());
MOZ_ASSERT(aEventStatus);
// Flush pending notifications to handle the event with the latest layout.
// But if it causes destroying the frame for mPresShell, stop handling the
// event. (why?)
AutoWeakFrame weakFrame(aFrameForPresShell);
MaybeFlushPendingNotifications(aGUIEvent);
if (!weakFrame.IsAlive()) {
*aEventStatus = nsEventStatus_eIgnore;
return NS_OK;
}
// XXX Retrieving capturing content here. However, some of the following
// methods allow to run script. So, isn't it possible the capturing
// content outdated?
nsCOMPtr<nsIContent> capturingContent =
EventHandler::GetCapturingContentFor(aGUIEvent);
if (GetDocument() && aGUIEvent->mClass == eTouchEventClass) {
Document::UnlockPointer();
}
nsIFrame* frameForPresShell = MaybeFlushThrottledStyles(aFrameForPresShell);
if (NS_WARN_IF(!frameForPresShell)) {
return NS_OK;
}
bool isCapturingContentIgnored = false;
bool isCaptureRetargeted = false;
nsIFrame* rootFrameToHandleEvent = ComputeRootFrameToHandleEvent(
frameForPresShell, aGUIEvent, capturingContent,
&isCapturingContentIgnored, &isCaptureRetargeted);
if (isCapturingContentIgnored) {
capturingContent = nullptr;
}
// The order to generate pointer event is
// 1. check pending pointer capture.
// 2. check if there is a capturing content.
// 3. hit test
// 4. dispatch pointer events
// 5. check whether the targets of all Touch instances are in the same
// document and suppress invalid instances.
// 6. dispatch mouse or touch events.
// Try to keep frame for following check, because frame can be damaged
// during MaybeProcessPointerCapture.
{
AutoWeakFrame frameKeeper(rootFrameToHandleEvent);
PointerEventHandler::MaybeProcessPointerCapture(aGUIEvent);
// Prevent application crashes, in case damaged frame.
if (!frameKeeper.IsAlive()) {
NS_WARNING("Nothing to handle this event!");
return NS_OK;
}
}
// Only capture mouse events and pointer events.
nsCOMPtr<nsIContent> pointerCapturingContent =
PointerEventHandler::GetPointerCapturingContent(aGUIEvent);
if (pointerCapturingContent) {
rootFrameToHandleEvent = pointerCapturingContent->GetPrimaryFrame();
if (!rootFrameToHandleEvent) {
return HandleEventWithPointerCapturingContentWithoutItsFrame(
aFrameForPresShell, aGUIEvent, pointerCapturingContent, aEventStatus);
}
}
WidgetMouseEvent* mouseEvent = aGUIEvent->AsMouseEvent();
bool isWindowLevelMouseExit =
(aGUIEvent->mMessage == eMouseExitFromWidget) &&
(mouseEvent && mouseEvent->mExitFrom == WidgetMouseEvent::eTopLevel);
// Get the frame at the event point. However, don't do this if we're
// capturing and retargeting the event because the captured frame will
// be used instead below. Also keep using the root frame if we're dealing
// with a window-level mouse exit event since we want to start sending
// mouse out events at the root EventStateManager.
EventTargetData eventTargetData(mPresShell, rootFrameToHandleEvent);
if (!isCaptureRetargeted && !isWindowLevelMouseExit &&
!pointerCapturingContent) {
if (!ComputeEventTargetFrameAndPresShellAtEventPoint(
rootFrameToHandleEvent, aGUIEvent, &eventTargetData)) {
*aEventStatus = nsEventStatus_eIgnore;
return NS_OK;
}
}
// if a node is capturing the mouse, check if the event needs to be
// retargeted at the capturing content instead. This will be the case when
// capture retargeting is being used, no frame was found or the frame's
// content is not a descendant of the capturing content.
if (capturingContent && !pointerCapturingContent &&
(gCaptureInfo.mRetargetToElement ||
!eventTargetData.mFrame->GetContent() ||
!nsContentUtils::ContentIsCrossDocDescendantOf(
eventTargetData.mFrame->GetContent(), capturingContent))) {
// A check was already done above to ensure that capturingContent is
// in this presshell.
NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(),
"Unexpected document");
nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame();
if (capturingFrame) {
eventTargetData.SetFrameAndComputePresShell(capturingFrame);
}
}
if (NS_WARN_IF(!eventTargetData.mFrame)) {
return NS_OK;
}
// Suppress mouse event if it's being targeted at an element inside
// a document which needs events suppressed
if (MaybeDiscardOrDelayMouseEvent(eventTargetData.mFrame, aGUIEvent)) {
return NS_OK;
}
// Check if we have an active EventStateManager which isn't the
// EventStateManager of the current PresContext. If that is the case, and
// mouse is over some ancestor document, forward event handling to the
// active document. This way content can get mouse events even when mouse
// is over the chrome or outside the window.
if (eventTargetData.MaybeRetargetToActiveDocument(aGUIEvent) &&
NS_WARN_IF(!eventTargetData.mFrame)) {
return NS_OK;
}
if (!eventTargetData.ComputeElementFromFrame(aGUIEvent)) {
return NS_OK;
}
// Note that even if ComputeElementFromFrame() returns true,
// eventTargetData.mContent can be nullptr here.
// Dispatch a pointer event if Pointer Events is enabled. Note that if
// pointer event listeners change the layout, eventTargetData is
// automatically updated.
if (!DispatchPrecedingPointerEvent(
aFrameForPresShell, aGUIEvent, pointerCapturingContent,
aDontRetargetEvents, &eventTargetData, aEventStatus)) {
return NS_OK;
}
// frame could be null after dispatching pointer events.
// XXX Despite of this comment, we update the event target data outside
// DispatchPrecedingPointerEvent(). Can we make it call
// UpdateTouchEventTarget()?
eventTargetData.UpdateTouchEventTarget(aGUIEvent);
// Handle the event in the correct shell.
// We pass the subshell's root frame as the frame to start from. This is
// the only correct alternative; if the event was captured then it
// must have been captured by us or some ancestor shell and we
// now ask the subshell to dispatch it normally.
eventTargetData.mPresShell->PushCurrentEventInfo(eventTargetData.mFrame,
eventTargetData.mContent);
EventHandler eventHandler(*eventTargetData.mPresShell);
nsresult rv = eventHandler.HandleEventInternal(
aGUIEvent, aEventStatus, true, eventTargetData.mOverrideClickTarget);
#ifdef DEBUG
eventTargetData.mPresShell->ShowEventTargetDebug();
#endif
eventTargetData.mPresShell->PopCurrentEventInfo();
return rv;
}
bool PresShell::EventHandler::MaybeFlushPendingNotifications(
WidgetGUIEvent* aGUIEvent) {
MOZ_ASSERT(aGUIEvent);

View File

@ -583,6 +583,23 @@ class PresShell final : public nsIPresShell,
static already_AddRefed<nsIURI> GetDocumentURIToCompareWithBlacklist(
PresShell& aPresShell);
/**
* HandleEventUsingCoordinates() handles aGUIEvent whose
* IsUsingCoordinates() returns true with the following helper methods.
*
* @param aFrameForPresShell The frame for mPresShell.
* @param aGUIEvent The handling event. Make sure that
* its IsUsingCoordinates() returns true.
* @param aEventStatus The status of aGUIEvent.
* @param aDontRetargetEvents true if we've already retarget document.
* Otherwise, false.
*/
MOZ_CAN_RUN_SCRIPT
nsresult HandleEventUsingCoordinates(nsIFrame* aFrameForPresShell,
WidgetGUIEvent* aGUIEvent,
nsEventStatus* aEventStatus,
bool aDontRetargetEvents);
/**
* EventTargetData struct stores a set of a PresShell (event handler),
* a frame (to handle the event) and a content (event target for the frame).