зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1420589 Part9: Dispatch pointer events to the capturing target even it's frame is destroyed. r=smaug.
MozReview-Commit-ID: DxNx3ByTdCW
This commit is contained in:
Родитель
58f49aba41
Коммит
a4f6e53467
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for triggering popup by pointer events</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="div1" style="width: 50px; height: 50px; background: green"></div>
|
||||
<div id="div2" style="width: 50px; height: 50px; background: green"></div>
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function startTest() {
|
||||
let div1 = document.getElementById("div1");
|
||||
let divEvents = [
|
||||
"pointerdown",
|
||||
"gotpointercapture",
|
||||
"pointermove",
|
||||
"pointerup",
|
||||
"lostpointercapture",
|
||||
"mousedown",
|
||||
"mousemove",
|
||||
"mouseup",
|
||||
];
|
||||
|
||||
let documentEvents = [
|
||||
"pointerdown",
|
||||
"pointermove",
|
||||
"pointerup",
|
||||
"mousedown",
|
||||
"mousemove",
|
||||
"mouseup",
|
||||
];
|
||||
|
||||
divEvents.forEach((event) => {
|
||||
div1.addEventListener(event, (e) => {
|
||||
ok(divEvents.indexOf(e.type) >= 0, " don't expect " + e.type);
|
||||
divEvents = divEvents.filter(item => item !== e.type);
|
||||
}, { once: true });
|
||||
});
|
||||
|
||||
documentEvents.forEach((event) => {
|
||||
document.addEventListener(event, (e) => {
|
||||
is(e.target, div1, e.type + " should be dispatched to div1");
|
||||
}, { once: true });
|
||||
});
|
||||
|
||||
div1.addEventListener("pointerdown", (e) => {
|
||||
div1.setPointerCapture(e.pointerId);
|
||||
});
|
||||
|
||||
div1.addEventListener("gotpointercapture", (e) => {
|
||||
div1.style.display = "none";
|
||||
});
|
||||
|
||||
synthesizeMouseAtCenter(div1, {type: "mousedown"});
|
||||
synthesizeMouseAtCenter(div2, {type: "mousemove"});
|
||||
synthesizeMouseAtCenter(div2, {type: "mouseup"});
|
||||
|
||||
ok(divEvents.length == 0, " expect " + divEvents);
|
||||
|
||||
divEvents = [
|
||||
"pointerdown",
|
||||
"gotpointercapture",
|
||||
"pointermove",
|
||||
"pointerup",
|
||||
"lostpointercapture",
|
||||
"touchstart",
|
||||
"touchmove",
|
||||
"touchend",
|
||||
];
|
||||
|
||||
documentEvents = [
|
||||
"pointerdown",
|
||||
"pointermove",
|
||||
"pointerup",
|
||||
"touchstart",
|
||||
"touchmove",
|
||||
"touchend",
|
||||
];
|
||||
divEvents.forEach((event) => {
|
||||
div1.addEventListener(event, (e) => {
|
||||
ok(divEvents.indexOf(e.type) >= 0, " don't expect " + e.type);
|
||||
divEvents = divEvents.filter(item => item !== e.type);
|
||||
}, { once: true });
|
||||
});
|
||||
|
||||
documentEvents.forEach((event) => {
|
||||
document.addEventListener(event, (e) => {
|
||||
is(e.target, div1, e.type + " should be dispatched to div1");
|
||||
}, { once: true });
|
||||
});
|
||||
|
||||
div1.style.display = "block";
|
||||
synthesizeMouseAtCenter(div1, {type: "mousemove"});
|
||||
synthesizeTouch(div1, 5, 5, { type: "touchstart" });
|
||||
synthesizeTouch(div2, 5, 5, { type: "touchmove" });
|
||||
synthesizeTouch(div2, 5, 5, { type: "touchend" });
|
||||
|
||||
ok(divEvents.length == 0, " expect " + divEvents);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(() => {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [["dom.w3c_pointer_events.enabled", true]]
|
||||
}, startTest);
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -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))) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче