diff --git a/dom/events/PointerEventHandler.cpp b/dom/events/PointerEventHandler.cpp index 583a6e49b9f1..db46db735508 100644 --- a/dom/events/PointerEventHandler.cpp +++ b/dom/events/PointerEventHandler.cpp @@ -331,8 +331,8 @@ PointerEventHandler::GetPointerCapturingContent(uint32_t aPointerId) return nullptr; } -/* static */ nsIFrame* -PointerEventHandler::GetPointerCapturingFrame(WidgetGUIEvent* aEvent) +/* static */ nsIContent* +PointerEventHandler::GetPointerCapturingContent(WidgetGUIEvent* aEvent) { if (!IsPointerEventEnabled() || (aEvent->mClass != ePointerEventClass && aEvent->mClass != eMouseEventClass) || @@ -346,17 +346,7 @@ PointerEventHandler::GetPointerCapturingFrame(WidgetGUIEvent* aEvent) if (!mouseEvent) { return nullptr; } - - // Find the content which captures the pointer. - nsIContent* capturingContent = - GetPointerCapturingContent(mouseEvent->pointerId); - - if (!capturingContent) { - return nullptr; - } - // Return the content's primary frame as the target frame. - nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame(); - return capturingFrame ? capturingFrame : nullptr; + return GetPointerCapturingContent(mouseEvent->pointerId); } /* static */ void diff --git a/dom/events/PointerEventHandler.h b/dom/events/PointerEventHandler.h index 85b90d0283f3..fce0a4a288f8 100644 --- a/dom/events/PointerEventHandler.h +++ b/dom/events/PointerEventHandler.h @@ -89,17 +89,16 @@ public: static void ImplicitlyReleasePointerCapture(WidgetEvent* aEvent); /** - * GetPointerCapturingFrame returns a target frame of aEvent. If the event is - * a mouse or pointer event (except mousedown and pointerdown), the pointer - * may be captured by a content. This method returns the capturing content's - * primary frame. Otherwise, nullptr. + * GetPointerCapturingContent returns a target content which captures the + * pointer. It's applied to mouse or pointer event (except mousedown and + * pointerdown). When capturing, return the content. Otherwise, nullptr. * * @param aEvent A mouse event or pointer event which may be * captured. * - * @return Target frame for aEvent. + * @return Target content for aEvent. */ - static nsIFrame* GetPointerCapturingFrame(WidgetGUIEvent* aEvent); + static nsIContent* GetPointerCapturingContent(WidgetGUIEvent* aEvent); static nsIContent* GetPointerCapturingContent(uint32_t aPointerId); diff --git a/dom/events/test/pointerevents/mochitest.ini b/dom/events/test/pointerevents/mochitest.ini index 565e2969d158..49ecd399cf29 100644 --- a/dom/events/test/pointerevents/mochitest.ini +++ b/dom/events/test/pointerevents/mochitest.ini @@ -145,6 +145,7 @@ support-files = support-files = file_test_trigger_fullscreen.html [test_trigger_popup_by_pointer_events.html] +[test_remove_frame_when_got_pointer_capture.html] [test_getCoalescedEvents.html] skip-if = !e10s support-files = diff --git a/dom/events/test/pointerevents/test_remove_frame_when_got_pointer_capture.html b/dom/events/test/pointerevents/test_remove_frame_when_got_pointer_capture.html new file mode 100644 index 000000000000..58791b63d90a --- /dev/null +++ b/dom/events/test/pointerevents/test_remove_frame_when_got_pointer_capture.html @@ -0,0 +1,116 @@ + + + + + Test for triggering popup by pointer events + + + + + +
+
+ + + diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index 3fc46a18ca53..9a83dadbf7a4 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -7188,11 +7188,35 @@ PresShell::HandleEvent(nsIFrame* aFrame, } } - nsIFrame* pointerCapturingFrame = - PointerEventHandler::GetPointerCapturingFrame(aEvent); + // Only capture mouse events and pointer events. + nsIContent* pointerCapturingContent = + PointerEventHandler::GetPointerCapturingContent(aEvent); - if (pointerCapturingFrame) { - frame = pointerCapturingFrame; + if (pointerCapturingContent) { + nsIFrame* pointerCapturingFrame = + pointerCapturingContent->GetPrimaryFrame(); + + if (!pointerCapturingFrame) { + // Dispatch events to the capturing content even it's frame is + // destroyed. + PointerEventHandler::DispatchPointerFromMouseOrTouch( + this, nullptr, pointerCapturingContent, aEvent, false, aEventStatus, + nullptr); + + PresShell* shell = GetShellForEventTarget(nullptr, + pointerCapturingContent); + + if (!shell) { + // The capturing element could be changed when dispatch pointer + // events. + return NS_OK; + } + return shell->HandleEventWithTarget(aEvent, nullptr, + pointerCapturingContent, + aEventStatus, true); + } else { + frame = pointerCapturingFrame; + } } WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); @@ -7204,7 +7228,8 @@ PresShell::HandleEvent(nsIFrame* aFrame, // 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. - if (!captureRetarget && !isWindowLevelMouseExit && !pointerCapturingFrame) { + if (!captureRetarget && !isWindowLevelMouseExit && + !pointerCapturingContent) { if (aEvent->mClass == eTouchEventClass) { frame = TouchManager::SetupTarget(aEvent->AsTouchEvent(), frame); } else { @@ -7228,7 +7253,7 @@ PresShell::HandleEvent(nsIFrame* aFrame, // 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 && !pointerCapturingFrame && + if (capturingContent && !pointerCapturingContent && (gCaptureInfo.mRetargetToElement || !frame->GetContent() || !nsContentUtils::ContentIsCrossDocDescendantOf(frame->GetContent(), capturingContent))) {