зеркало из 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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ nsIFrame*
|
/* static */ nsIContent*
|
||||||
PointerEventHandler::GetPointerCapturingFrame(WidgetGUIEvent* aEvent)
|
PointerEventHandler::GetPointerCapturingContent(WidgetGUIEvent* aEvent)
|
||||||
{
|
{
|
||||||
if (!IsPointerEventEnabled() || (aEvent->mClass != ePointerEventClass &&
|
if (!IsPointerEventEnabled() || (aEvent->mClass != ePointerEventClass &&
|
||||||
aEvent->mClass != eMouseEventClass) ||
|
aEvent->mClass != eMouseEventClass) ||
|
||||||
|
@ -346,17 +346,7 @@ PointerEventHandler::GetPointerCapturingFrame(WidgetGUIEvent* aEvent)
|
||||||
if (!mouseEvent) {
|
if (!mouseEvent) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
return GetPointerCapturingContent(mouseEvent->pointerId);
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void
|
/* static */ void
|
||||||
|
|
|
@ -89,17 +89,16 @@ public:
|
||||||
static void ImplicitlyReleasePointerCapture(WidgetEvent* aEvent);
|
static void ImplicitlyReleasePointerCapture(WidgetEvent* aEvent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetPointerCapturingFrame returns a target frame of aEvent. If the event is
|
* GetPointerCapturingContent returns a target content which captures the
|
||||||
* a mouse or pointer event (except mousedown and pointerdown), the pointer
|
* pointer. It's applied to mouse or pointer event (except mousedown and
|
||||||
* may be captured by a content. This method returns the capturing content's
|
* pointerdown). When capturing, return the content. Otherwise, nullptr.
|
||||||
* primary frame. Otherwise, nullptr.
|
|
||||||
*
|
*
|
||||||
* @param aEvent A mouse event or pointer event which may be
|
* @param aEvent A mouse event or pointer event which may be
|
||||||
* captured.
|
* 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);
|
static nsIContent* GetPointerCapturingContent(uint32_t aPointerId);
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,7 @@ support-files =
|
||||||
support-files =
|
support-files =
|
||||||
file_test_trigger_fullscreen.html
|
file_test_trigger_fullscreen.html
|
||||||
[test_trigger_popup_by_pointer_events.html]
|
[test_trigger_popup_by_pointer_events.html]
|
||||||
|
[test_remove_frame_when_got_pointer_capture.html]
|
||||||
[test_getCoalescedEvents.html]
|
[test_getCoalescedEvents.html]
|
||||||
skip-if = !e10s
|
skip-if = !e10s
|
||||||
support-files =
|
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 =
|
// Only capture mouse events and pointer events.
|
||||||
PointerEventHandler::GetPointerCapturingFrame(aEvent);
|
nsIContent* pointerCapturingContent =
|
||||||
|
PointerEventHandler::GetPointerCapturingContent(aEvent);
|
||||||
|
|
||||||
if (pointerCapturingFrame) {
|
if (pointerCapturingContent) {
|
||||||
frame = pointerCapturingFrame;
|
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();
|
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
|
// 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
|
// with a window-level mouse exit event since we want to start sending
|
||||||
// mouse out events at the root EventStateManager.
|
// mouse out events at the root EventStateManager.
|
||||||
if (!captureRetarget && !isWindowLevelMouseExit && !pointerCapturingFrame) {
|
if (!captureRetarget && !isWindowLevelMouseExit &&
|
||||||
|
!pointerCapturingContent) {
|
||||||
if (aEvent->mClass == eTouchEventClass) {
|
if (aEvent->mClass == eTouchEventClass) {
|
||||||
frame = TouchManager::SetupTarget(aEvent->AsTouchEvent(), frame);
|
frame = TouchManager::SetupTarget(aEvent->AsTouchEvent(), frame);
|
||||||
} else {
|
} else {
|
||||||
|
@ -7228,7 +7253,7 @@ PresShell::HandleEvent(nsIFrame* aFrame,
|
||||||
// retargeted at the capturing content instead. This will be the case when
|
// 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
|
// capture retargeting is being used, no frame was found or the frame's
|
||||||
// content is not a descendant of the capturing content.
|
// content is not a descendant of the capturing content.
|
||||||
if (capturingContent && !pointerCapturingFrame &&
|
if (capturingContent && !pointerCapturingContent &&
|
||||||
(gCaptureInfo.mRetargetToElement || !frame->GetContent() ||
|
(gCaptureInfo.mRetargetToElement || !frame->GetContent() ||
|
||||||
!nsContentUtils::ContentIsCrossDocDescendantOf(frame->GetContent(),
|
!nsContentUtils::ContentIsCrossDocDescendantOf(frame->GetContent(),
|
||||||
capturingContent))) {
|
capturingContent))) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче