Bug 1294335 - [Pointer Event] Refine setPointerCapture / releasePointerCapture to follow the algorithm defined in the spec. f=bevistseng, r=smaug

This commit is contained in:
Stone Shih 2016-08-12 09:49:31 +08:00
Родитель 3ead7f93ab
Коммит b6697d07aa
18 изменённых файлов: 740 добавлений и 78 удалений

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

@ -746,28 +746,16 @@ public:
return;
}
nsIPresShell::PointerCaptureInfo* pointerCaptureInfo = nullptr;
if (nsIPresShell::gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) && pointerCaptureInfo) {
// Call ReleasePointerCapture only on correct element
// (on element that have status pointer capture override
// or on element that have status pending pointer capture)
if (pointerCaptureInfo->mOverrideContent == this) {
if (nsIPresShell::gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) &&
pointerCaptureInfo && pointerCaptureInfo->mPendingContent == this) {
nsIPresShell::ReleasePointerCapturingContent(aPointerId);
} else if (pointerCaptureInfo->mPendingContent == this) {
nsIPresShell::ReleasePointerCapturingContent(aPointerId);
}
}
}
bool HasPointerCapture(long aPointerId)
{
bool activeState = false;
if (!nsIPresShell::GetPointerInfo(aPointerId, activeState)) {
return false;
}
nsIPresShell::PointerCaptureInfo* pointerCaptureInfo = nullptr;
if (nsIPresShell::gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) &&
pointerCaptureInfo && !pointerCaptureInfo->mReleaseContent &&
(pointerCaptureInfo->mOverrideContent == this ||
pointerCaptureInfo->mPendingContent == this)) {
pointerCaptureInfo && pointerCaptureInfo->mPendingContent == this) {
return true;
}
return false;

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

@ -21,6 +21,8 @@ support-files =
disabled = should be investigated
[test_pointerevent_element_haspointercapture-manual.html]
support-files = pointerevent_element_haspointercapture-manual.html
[test_pointerevent_element_haspointercapture_release_pending_capture-manual.html]
support-files = pointerevent_element_haspointercapture_release_pending_capture-manual.html
[test_pointerevent_gotpointercapture_before_first_pointerevent-manual.html]
support-files = pointerevent_gotpointercapture_before_first_pointerevent-manual.html
[test_pointerevent_lostpointercapture_for_disconnected_node-manual.html]
@ -106,6 +108,8 @@ support-files =
support-files = pointerevent_releasepointercapture_onpointercancel_touch-manual.html
[test_pointerevent_releasepointercapture_onpointerup_mouse-manual.html]
support-files = pointerevent_releasepointercapture_onpointerup_mouse-manual.html
[test_pointerevent_releasepointercapture_release_right_after_capture-manual.html]
support-files = pointerevent_releasepointercapture_release_right_after_capture-manual.html
[test_pointerevent_setpointercapture_disconnected-manual.html]
support-files = pointerevent_setpointercapture_disconnected-manual.html
[test_pointerevent_setpointercapture_inactive_button_mouse-manual.html]
@ -113,8 +117,12 @@ support-files =
disabled = should be investigated
[test_pointerevent_setpointercapture_invalid_pointerid-manual.html]
support-files = pointerevent_setpointercapture_invalid_pointerid-manual.html
[test_pointerevent_setpointercapture_override_pending_capture_element-manual.html]
support-files = pointerevent_setpointercapture_override_pending_capture_element-manual.html
[test_pointerevent_setpointercapture_relatedtarget-manual.html]
support-files = pointerevent_setpointercapture_relatedtarget-manual.html
[test_pointerevent_setpointercapture_to_same_element_twice-manual.html]
support-files = pointerevent_setpointercapture_to_same_element_twice-manual.html
[test_pointerevent_suppress_compat_events_on_click.html]
support-files = pointerevent_suppress_compat_events_on_click.html
disabled = should be investigated

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

@ -0,0 +1,76 @@
<!doctype html>
<html>
<head>
<title>Element.hasPointerCapture test after the pending pointer capture element releases pointer capture</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<!--script src="/resources/testharnessreport.js"></script-->
<script type="text/javascript" src="pointerevent_support.js"></script>
<script type="text/javascript" src="mochitest_support_internal.js"></script>
<script>
var detected_pointertypes = {};
add_completion_callback(showPointerTypes);
var test_pointerEvent = async_test("hasPointerCapture test after the pending pointer capture element releases pointer capture");
function run() {
var target0 = document.getElementById("target0");
var target1 = document.getElementById("target1");
on_event(target0, "pointerdown", function (e) {
detected_pointertypes[e.pointerType] = true;
target0.setPointerCapture(e.pointerId);
test_pointerEvent.step(function () {
assert_equals(target0.hasPointerCapture(e.pointerId), true, "After target0.setPointerCapture, target0.hasPointerCapture should return true");
});
});
on_event(target0, "gotpointercapture", function (e) {
test_pointerEvent.step(function () {
assert_equals(target0.hasPointerCapture(e.pointerId), true, "After target0 received gotpointercapture, target0.hasPointerCapture should return true");
});
target1.setPointerCapture(e.pointerId);
test_pointerEvent.step(function () {
assert_equals(target0.hasPointerCapture(e.pointerId), false, "After target1.setPointerCapture, target0.hasPointerCapture should return false");
assert_equals(target1.hasPointerCapture(e.pointerId), true, "After target1.setPointerCapture, target1.hasPointerCapture should return true");
});
target1.releasePointerCapture(e.pointerId);
test_pointerEvent.step(function () {
assert_equals(target0.hasPointerCapture(e.pointerId), false, "After target1.releasePointerCapture, target0.hasPointerCapture should be false");
assert_equals(target1.hasPointerCapture(e.pointerId), false, "After target1.releasePointerCapture, target1.hasPointerCapture should be false");
});
});
on_event(target1, "gotpointercapture", function (e) {
test_pointerEvent.step(function () {
assert_true(false, "target1 should never receive gotpointercapture in this test");
});
});
on_event(target0, "lostpointercapture", function (e) {
test_pointerEvent.done();
});
}
</script>
</head>
<body onload="run()">
<h1>Element.hasPointerCapture test after the pending pointer capture element releases pointer capture</h1>
<!--
<h4>
Test Description: This test checks if Element.hasPointerCapture returns value correctly after the pending pointer capture element releases pointer capture
<ol>
<li> Press black rectangle and do not release
<li> Move your pointer to purple rectangle
<li> Release the pointer
</ol>
</h4>
-->
<p>
<div id="target0" touch-action:none></div>
<div id="target1" touch-action:none></div>
<div id="complete-notice">
<p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
</div>
<div id="log"></div>
</body>
</html>

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

@ -0,0 +1,64 @@
<!doctype html>
<html>
<head>
<title>Release pointer capture right after setpointercapture</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<!--script src="/resources/testharnessreport.js"></script-->
<script src="pointerevent_support.js"></script>
<script src="mochitest_support_internal.js"></script>
<script type="text/javascript">
var detected_pointertypes = {};
add_completion_callback(showPointerTypes);
var test_setPointerCapture = async_test("Release pointer capture right after setpointercapture");
function run() {
var target0 = document.getElementById("target0");
var target1 = document.getElementById("target1");
on_event(target0, "pointerdown", function (event) {
detected_pointertypes[event.pointerType] = true;
target0.setPointerCapture(event.pointerId);
target0.releasePointerCapture(event.pointerId);
assert_equals(target0.hasPointerCapture(e.pointerId), false, "After target0.releasePointerCapture, target0.hasPointerCapture should be false");
});
on_event(target0, "gotpointercapture", function (event) {
test_setPointerCapture.step(function () {
assert_true(false, "target0 shouldn't receive gotpointercapture");
});
});
on_event(target0, "lostpointercapture", function (event) {
test_setPointerCapture.step(function () {
assert_true(false, "target0 shouldn't receive lostpointercapture");
});
});
on_event(target0, "pointerup", function (event) {
test_setPointerCapture.done();
});
}
</script>
</head>
<body onload="run()">
<h1>Release pointer capture right after setpointercapture</h1>
<!--
<h4>Test Description:
When calling releasePointer right after setPointerCapture method is invoked, the pending pointer capture should be cleared and no element should receive gotpointercapture and lostpointercapture events
<ol>
<li>Press and hold left mouse button over black box
<li>Move mouse and release mouse button
</ol>
</h4>
-->
<br>
<div id="target0" touch-action:none></div>
<div id="target1" touch-action:none></div>
<div id="complete-notice">
<p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
</div>
<div id="log"></div>
</body>
</html>

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

@ -0,0 +1,66 @@
<!doctype html>
<html>
<head>
<title>Test overriding the pending pointer capture element</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<!--script src="/resources/testharnessreport.js"></script-->
<script src="pointerevent_support.js"></script>
<script src="mochitest_support_internal.js"></script>
<script type="text/javascript">
var detected_pointertypes = {};
add_completion_callback(showPointerTypes);
var test_setPointerCapture = async_test("setPointerCapture: override the pending pointer capture element");
function run() {
var target0 = document.getElementById("target0");
var target1 = document.getElementById("target1");
on_event(target0, "pointerdown", function (event) {
detected_pointertypes[event.pointerType] = true;
target0.setPointerCapture(event.pointerId);
test_setPointerCapture.step(function () {
assert_equals(target0.hasPointerCapture(event.pointerId), true, "Set capture to target0, target0.hasPointerCapture should be true");
});
target1.setPointerCapture(event.pointerId);
test_setPointerCapture.step(function () {
assert_equals(target0.hasPointerCapture(event.pointerId), false, "Set capture to target1, target0.hasPointerCapture should be false");
assert_equals(target1.hasPointerCapture(event.pointerId), true, "Set capture to target1, target1.hasPointerCapture should be true");
});
});
on_event(target0, "gotpointercapture", function (event) {
assert_true(false, "target0 shouldn't receive gotpointercapture");
});
on_event(target1, "gotpointercapture", function (event) {
assert_true(true, "target1 should receive gotpointercapture");
});
on_event(target1, "pointerup", function (event) {
test_setPointerCapture.done();
});
}
</script>
</head>
<body onload="run()">
<h1>Pointer Event: Test overriding the pending pointer capture element</h1>
<!--
<h4>Test Description:
After an element setPointerCapture, if another element also setPointerCapture and override it, the old pending pointer capture element shouldn't receive any gotpointercapture or lostpointercapture event
<ol>
<li>Press and hold left mouse button over black box
<li>Move mouse and release mouse button
</ol>
</h4>
-->
<br>
<div id="target0" touch-action:none></div>
<div id="target1" touch-action:none></div>
<div id="complete-notice">
<p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
</div>
<div id="log"></div>
</body>
</html>

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

@ -0,0 +1,65 @@
<!doctype html>
<html>
<head>
<title>setPointerCapture() to the element which already captured the pointer</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<!--script src="/resources/testharnessreport.js"></script-->
<script src="pointerevent_support.js"></script>
<script src="mochitest_support_internal.js"></script>
<script type="text/javascript">
var detected_pointertypes = {};
add_completion_callback(showPointerTypes);
var test_setPointerCapture = async_test("setPointerCapture: set to the element which already captured the pointer");
var got_pointer_capture = false;
function run() {
var target0 = document.getElementById("target0");
var target1 = document.getElementById("target1");
on_event(target0, "pointerdown", function (event) {
detected_pointertypes[event.pointerType] = true;
target0.setPointerCapture(event.pointerId);
});
on_event(target0, "gotpointercapture", function (event) {
test_setPointerCapture.step(function () {
assert_equals(got_pointer_capture, false, "Target0 should receive gotpointercapture at the first time it captured the pointer");
assert_equals(target0.hasPointerCapture(event.pointerId), true, "Target 0 received gotpointercapture, target0.hasPointerCapture should be true");
});
got_pointer_capture = true;
target0.setPointerCapture(event.pointerId);
test_setPointerCapture.step(function () {
assert_equals(target0.hasPointerCapture(event.pointerId), true, "Set capture to target0, target0.hasPointerCapture should be true");
assert_equals(target1.hasPointerCapture(event.pointerId), false, "Set capture to target0, target1.hasPointerCapture should be false");
});
});
on_event(target0, "pointerup", function (event) {
test_setPointerCapture.done();
});
}
</script>
</head>
<body onload="run()">
<h1>Pointer Event: setPointerCapture to the element which already captured the pointer</h1>
<!--
<h4>Test Description:
When the setPointerCapture method is invoked, if the target element had already captured the pointer, it should not trigger any gotpointercapture or lostpointercapture event
<ol>
<li>Press and hold left mouse button over black box
<li>Move mouse and release mouse button
</ol>
</h4>
-->
<br>
<div id="target0" touch-action:none></div>
<div id="target1" touch-action:none></div>
<div id="complete-notice">
<p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
</div>
<div id="log"></div>
</body>
</html>

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

@ -0,0 +1,32 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1000870</title>
<meta name="author" content="Maksim Lebedev" />
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="mochitest_support_external.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
function startTest() {
var iframe = document.getElementById("testFrame");
iframe.src = "pointerevent_element_haspointercapture_release_pending_capture-manual.html";
}
function executeTest(int_win) {
sendMouseEvent(int_win, "target0", "mousemove");
sendMouseEvent(int_win, "target0", "mousedown", {button:0});
sendMouseEvent(int_win, "target0", "mousemove", {button:0});
sendMouseEvent(int_win, "target1", "mousemove", {button:0});
sendMouseEvent(int_win, "target1", "mouseup", {button:0});
}
</script>
</head>
<body>
<iframe id="testFrame" height="800" width="1000"></iframe>
</body>
</html>

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

@ -0,0 +1,32 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1000870</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="mochitest_support_external.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
function startTest() {
var iframe = document.getElementById("testFrame");
iframe.src = "pointerevent_releasepointercapture_release_right_after_capture-manual.html";
}
function executeTest(int_win) {
sendMouseEvent(int_win, "target0", "mousemove");
sendMouseEvent(int_win, "target0", "mousedown", {button:0});
sendMouseEvent(int_win, "target0", "mousemove", {button:0});
sendMouseEvent(int_win, "target0", "mousemove", {button:0});
sendMouseEvent(int_win, "target0", "mousemove", {button:0});
sendMouseEvent(int_win, "target0", "mouseup", {button:0});
}
</script>
</head>
<body>
<iframe id="testFrame" height="800" width="1000"></iframe>
</body>
</html>

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

@ -0,0 +1,33 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1000870</title>
<meta name="author" content="Maksim Lebedev" />
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="mochitest_support_external.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
function startTest() {
var iframe = document.getElementById("testFrame");
iframe.src = "pointerevent_setpointercapture_override_pending_capture_element-manual.html";
}
function executeTest(int_win) {
sendMouseEvent(int_win, "target0", "mousemove");
sendMouseEvent(int_win, "target0", "mousedown", {button:0});
sendMouseEvent(int_win, "target0", "mousemove", {button:0});
sendMouseEvent(int_win, "target0", "mousemove", {button:0});
sendMouseEvent(int_win, "target0", "mousemove", {button:0});
sendMouseEvent(int_win, "target0", "mouseup", {button:0});
}
</script>
</head>
<body>
<iframe id="testFrame" height="800" width="1000"></iframe>
</body>
</html>

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

@ -0,0 +1,33 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1000870</title>
<meta name="author" content="Maksim Lebedev" />
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="mochitest_support_external.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
function startTest() {
var iframe = document.getElementById("testFrame");
iframe.src = "pointerevent_setpointercapture_to_same_element_twice-manual.html";
}
function executeTest(int_win) {
sendMouseEvent(int_win, "target0", "mousemove");
sendMouseEvent(int_win, "target0", "mousedown", {button:0});
sendMouseEvent(int_win, "target0", "mousemove", {button:0});
sendMouseEvent(int_win, "target0", "mousemove", {button:0});
sendMouseEvent(int_win, "target0", "mousemove", {button:0});
sendMouseEvent(int_win, "target0", "mouseup", {button:0});
}
</script>
</head>
<body>
<iframe id="testFrame" height="800" width="1000"></iframe>
</body>
</html>

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

@ -1265,11 +1265,10 @@ public:
{
nsCOMPtr<nsIContent> mPendingContent;
nsCOMPtr<nsIContent> mOverrideContent;
bool mReleaseContent;
bool mPrimaryState;
explicit PointerCaptureInfo(nsIContent* aPendingContent, bool aPrimaryState) :
mPendingContent(aPendingContent), mReleaseContent(false), mPrimaryState(aPrimaryState)
mPendingContent(aPendingContent), mPrimaryState(aPrimaryState)
{
MOZ_COUNT_CTOR(PointerCaptureInfo);
}
@ -1311,8 +1310,7 @@ public:
static nsIContent* GetPointerCapturingContent(uint32_t aPointerId);
// CheckPointerCaptureState checks cases, when got/lostpointercapture events should be fired.
// Function returns true, if any of events was fired; false, if no one event was fired.
static bool CheckPointerCaptureState(uint32_t aPointerId,
static void CheckPointerCaptureState(uint32_t aPointerId,
uint16_t aPointerType, bool aIsPrimary);
// GetPointerInfo returns true if pointer with aPointerId is situated in device, false otherwise.

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

@ -4432,9 +4432,8 @@ PresShell::ContentRemoved(nsIDocument *aDocument,
// If it does we should release the pointer capture for the elements.
for (auto iter = gPointerCaptureList->Iter(); !iter.Done(); iter.Next()) {
nsIPresShell::PointerCaptureInfo* data = iter.UserData();
if (data && data->mOverrideContent &&
nsContentUtils::ContentIsDescendantOf(data->mOverrideContent,
aChild)) {
if (data && data->mPendingContent &&
nsContentUtils::ContentIsDescendantOf(data->mPendingContent, aChild)) {
nsIPresShell::ReleasePointerCapturingContent(iter.Key());
}
}
@ -6696,17 +6695,15 @@ nsIPresShell::SetCapturingContent(nsIContent* aContent, uint8_t aFlags)
nsIPresShell::SetPointerCapturingContent(uint32_t aPointerId, nsIContent* aContent)
{
PointerCaptureInfo* pointerCaptureInfo = nullptr;
gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo);
nsIContent* content = pointerCaptureInfo ?
pointerCaptureInfo->mOverrideContent.get() : nullptr;
MOZ_ASSERT(aContent != nullptr);
if (!content && (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId))) {
if (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId)) {
SetCapturingContent(aContent, CAPTURE_PREVENTDRAG);
}
if (pointerCaptureInfo) {
if (gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) &&
pointerCaptureInfo) {
pointerCaptureInfo->mPendingContent = aContent;
pointerCaptureInfo->mReleaseContent = false;
} else {
gPointerCaptureList->Put(aPointerId,
new PointerCaptureInfo(aContent, GetPointerPrimaryState(aPointerId)));
@ -6716,14 +6713,14 @@ nsIPresShell::SetPointerCapturingContent(uint32_t aPointerId, nsIContent* aConte
/* static */ void
nsIPresShell::ReleasePointerCapturingContent(uint32_t aPointerId)
{
if (gActivePointersIds->Get(aPointerId)) {
if (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId)) {
SetCapturingContent(nullptr, CAPTURE_PREVENTDRAG);
}
PointerCaptureInfo* pointerCaptureInfo = nullptr;
if (gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) && pointerCaptureInfo) {
// Set flag to asyncronously release capture for given pointer.
pointerCaptureInfo->mReleaseContent = true;
if (gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) &&
pointerCaptureInfo) {
pointerCaptureInfo->mPendingContent = nullptr;
}
}
@ -6737,50 +6734,32 @@ nsIPresShell::GetPointerCapturingContent(uint32_t aPointerId)
return nullptr;
}
/* static */ bool
/* static */ void
nsIPresShell::CheckPointerCaptureState(uint32_t aPointerId,
uint16_t aPointerType, bool aIsPrimary)
{
bool didDispatchEvent = false;
PointerCaptureInfo* pointerCaptureInfo = nullptr;
if (gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) && pointerCaptureInfo) {
// If pendingContent exist or anybody calls element.releasePointerCapture
// we should dispatch lostpointercapture event to overrideContent if it exist
if (pointerCaptureInfo->mPendingContent || pointerCaptureInfo->mReleaseContent) {
if (pointerCaptureInfo->mOverrideContent) {
nsCOMPtr<nsIContent> content;
pointerCaptureInfo->mOverrideContent.swap(content);
if (pointerCaptureInfo->mReleaseContent) {
pointerCaptureInfo->mPendingContent = nullptr;
PointerCaptureInfo* captureInfo = nullptr;
if (gPointerCaptureList->Get(aPointerId, &captureInfo) && captureInfo &&
captureInfo->mPendingContent != captureInfo->mOverrideContent) {
// cache captureInfo->mPendingContent since it may be changed in the pointer
// event listener
nsIContent* pendingContent = captureInfo->mPendingContent.get();
if (captureInfo->mOverrideContent) {
DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ false,
aPointerId, aPointerType, aIsPrimary,
captureInfo->mOverrideContent);
}
if (pointerCaptureInfo->Empty()) {
if (pendingContent) {
DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ true, aPointerId,
aPointerType, aIsPrimary,
pendingContent);
}
captureInfo->mOverrideContent = pendingContent;
if (captureInfo->Empty()) {
gPointerCaptureList->Remove(aPointerId);
}
DispatchGotOrLostPointerCaptureEvent(false, aPointerId, aPointerType,
aIsPrimary, content);
didDispatchEvent = true;
} else if (pointerCaptureInfo->mPendingContent && pointerCaptureInfo->mReleaseContent) {
// If anybody calls element.releasePointerCapture
// We should clear overrideContent and pendingContent
pointerCaptureInfo->mPendingContent = nullptr;
pointerCaptureInfo->mReleaseContent = false;
}
}
}
if (gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) && pointerCaptureInfo) {
// If pendingContent exist we should dispatch gotpointercapture event to it
if (pointerCaptureInfo && pointerCaptureInfo->mPendingContent) {
pointerCaptureInfo->mOverrideContent = pointerCaptureInfo->mPendingContent;
pointerCaptureInfo->mPendingContent = nullptr;
pointerCaptureInfo->mReleaseContent = false;
DispatchGotOrLostPointerCaptureEvent(true, aPointerId, aPointerType,
aIsPrimary,
pointerCaptureInfo->mOverrideContent);
didDispatchEvent = true;
}
}
return didDispatchEvent;
}
/* static */ uint16_t
nsIPresShell::GetPointerType(uint32_t aPointerId)

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

@ -20,7 +20,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=977003
var test_down_got = false;
var test_mediator_got = false;
var test_mediator_lost = false;
var test_listener = false;
var test_listener_got = false;
var test_listener_lost = false;
function TargetDownHandler(event) {
logger("Target receive event: " + event.type);
@ -41,9 +42,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=977003
logger("Mediator receive event: " + event.type);
test_mediator_lost = true;
}
function ListenerHandler(event) {
logger("Receive event on Listener: " + event.type);
test_listener = true;
function ListenerGotHandler(event) {
test_listener_got = true;
}
function ListenerLostHandler(event) {
test_listener_lost = true;
}
function logger(message) {
console.log(message);
@ -63,19 +66,21 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=977003
target.addEventListener("pointerdown", TargetDownHandler, false);
mediator.addEventListener("gotpointercapture", MediatorGotPCHandler, false);
mediator.addEventListener("lostpointercapture", MediatorLostPCHandler, false);
listener.addEventListener("gotpointercapture", ListenerHandler, false);
listener.addEventListener("lostpointercapture", ListenerHandler, false);
listener.addEventListener("gotpointercapture", ListenerGotHandler, false);
listener.addEventListener("lostpointercapture", ListenerLostHandler, false);
var rect = target.getBoundingClientRect();
synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointerdown"});
synthesizePointer(target, rect.width/3, rect.height/3, {type: "pointermove"});
synthesizePointer(target, rect.width/4, rect.height/4, {type: "pointermove"});
synthesizePointer(target, rect.width/4, rect.height/4, {type: "pointerup"});
finishTest();
}
function finishTest() {
parent.is(test_down_got, true, "Part 4: pointerdown event should be received");
parent.is(test_mediator_got, true, "Part 4: gotpointercapture event should be received by Mediator");
parent.is(test_mediator_lost, true, "Part 4: lostpointercapture event should be received by Mediator");
parent.is(test_listener, false, "Part 4: listener should not receive any events");
parent.is(test_listener_got, true, "Part 4: gotpointercapture event should be received by listener");
parent.is(test_listener_lost, true, "Part 4: lostpointercapture event should be received by listener");
logger("finishTest");
parent.finishTest();
}

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

@ -37599,6 +37599,30 @@
"path": "pointerevents/pointerevent_element_haspointercapture-manual.html",
"url": "/pointerevents/pointerevent_element_haspointercapture-manual.html"
}
],
"pointerevents/pointerevent_element_haspointercapture_release_pending_capture-manual.html": [
{
"path": "pointerevents/pointerevent_element_haspointercapture_release_pending_capture-manual.html",
"url": "/pointerevents/pointerevent_element_haspointercapture_release_pending_capture-manual.html"
}
],
"pointerevents/pointerevent_releasepointercapture_release_right_after_capture-manual.html": [
{
"path": "pointerevents/pointerevent_releasepointercapture_release_right_after_capture-manual.html",
"url": "/pointerevents/pointerevent_releasepointercapture_release_right_after_capture-manual.html"
}
],
"pointerevents/pointerevent_setpointercapture_override_pending_capture_element-manual.html": [
{
"path": "pointerevents/pointerevent_setpointercapture_override_pending_capture_element-manual.html",
"url": "/pointerevents/pointerevent_setpointercapture_override_pending_capture_element-manual.html"
}
],
"pointerevents/pointerevent_setpointercapture_to_same_element_twice-manual.html": [
{
"path": "pointerevents/pointerevent_setpointercapture_to_same_element_twice-manual.html",
"url": "/pointerevents/pointerevent_setpointercapture_to_same_element_twice-manual.html"
}
]
},
"reftest": {

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

@ -0,0 +1,73 @@
<!doctype html>
<html>
<head>
<title>Element.hasPointerCapture test after the pending pointer capture element releases pointer capture</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script type="text/javascript" src="pointerevent_support.js"></script>
<script>
var detected_pointertypes = {};
add_completion_callback(showPointerTypes);
var test_pointerEvent = async_test("hasPointerCapture test after the pending pointer capture element releases pointer capture");
function run() {
var target0 = document.getElementById("target0");
var target1 = document.getElementById("target1");
on_event(target0, "pointerdown", function (e) {
detected_pointertypes[e.pointerType] = true;
target0.setPointerCapture(e.pointerId);
test_pointerEvent.step(function () {
assert_equals(target0.hasPointerCapture(e.pointerId), true, "After target0.setPointerCapture, target0.hasPointerCapture should return true");
});
});
on_event(target0, "gotpointercapture", function (e) {
test_pointerEvent.step(function () {
assert_equals(target0.hasPointerCapture(e.pointerId), true, "After target0 received gotpointercapture, target0.hasPointerCapture should return true");
});
target1.setPointerCapture(e.pointerId);
test_pointerEvent.step(function () {
assert_equals(target0.hasPointerCapture(e.pointerId), false, "After target1.setPointerCapture, target0.hasPointerCapture should return false");
assert_equals(target1.hasPointerCapture(e.pointerId), true, "After target1.setPointerCapture, target1.hasPointerCapture should return true");
});
target1.releasePointerCapture(e.pointerId);
test_pointerEvent.step(function () {
assert_equals(target0.hasPointerCapture(e.pointerId), false, "After target1.releasePointerCapture, target0.hasPointerCapture should be false");
assert_equals(target1.hasPointerCapture(e.pointerId), false, "After target1.releasePointerCapture, target1.hasPointerCapture should be false");
});
});
on_event(target1, "gotpointercapture", function (e) {
test_pointerEvent.step(function () {
assert_true(false, "target1 should never receive gotpointercapture in this test");
});
});
on_event(target0, "lostpointercapture", function (e) {
test_pointerEvent.done();
});
}
</script>
</head>
<body onload="run()">
<h1>Element.hasPointerCapture test after the pending pointer capture element releases pointer capture</h1>
<h4>
Test Description: This test checks if Element.hasPointerCapture returns value correctly after the pending pointer capture element releases pointer capture
<ol>
<li> Press black rectangle and do not release
<li> Move your pointer to purple rectangle
<li> Release the pointer
</ol>
</h4>
<p>
<div id="target0" touch-action:none></div>
<div id="target1" touch-action:none></div>
<div id="complete-notice">
<p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
</div>
<div id="log"></div>
</body>
</html>

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

@ -0,0 +1,61 @@
<!doctype html>
<html>
<head>
<title>Release pointer capture right after setpointercapture</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="pointerevent_support.js"></script>
<script type="text/javascript">
var detected_pointertypes = {};
add_completion_callback(showPointerTypes);
var test_setPointerCapture = async_test("Release pointer capture right after setpointercapture");
function run() {
var target0 = document.getElementById("target0");
var target1 = document.getElementById("target1");
on_event(target0, "pointerdown", function (event) {
detected_pointertypes[event.pointerType] = true;
target0.setPointerCapture(event.pointerId);
target0.releasePointerCapture(event.pointerId);
assert_equals(target0.hasPointerCapture(e.pointerId), false, "After target0.releasePointerCapture, target0.hasPointerCapture should be false");
});
on_event(target0, "gotpointercapture", function (event) {
test_setPointerCapture.step(function () {
assert_true(false, "target0 shouldn't receive gotpointercapture");
});
});
on_event(target0, "lostpointercapture", function (event) {
test_setPointerCapture.step(function () {
assert_true(false, "target0 shouldn't receive lostpointercapture");
});
});
on_event(target0, "pointerup", function (event) {
test_setPointerCapture.done();
});
}
</script>
</head>
<body onload="run()">
<h1>Release pointer capture right after setpointercapture</h1>
<h4>Test Description:
When calling releasePointer right after setPointerCapture method is invoked, the pending pointer capture should be cleared and no element should receive gotpointercapture and lostpointercapture events
<ol>
<li>Press and hold left mouse button over black box
<li>Move mouse and release mouse button
</ol>
</h4>
<br>
<div id="target0" touch-action:none></div>
<div id="target1" touch-action:none></div>
<div id="complete-notice">
<p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
</div>
<div id="log"></div>
</body>
</html>

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

@ -0,0 +1,63 @@
<!doctype html>
<html>
<head>
<title>Test overriding the pending pointer capture element</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="pointerevent_support.js"></script>
<script type="text/javascript">
var detected_pointertypes = {};
add_completion_callback(showPointerTypes);
var test_setPointerCapture = async_test("setPointerCapture: override the pending pointer capture element");
function run() {
var target0 = document.getElementById("target0");
var target1 = document.getElementById("target1");
on_event(target0, "pointerdown", function (event) {
detected_pointertypes[event.pointerType] = true;
target0.setPointerCapture(event.pointerId);
test_setPointerCapture.step(function () {
assert_equals(target0.hasPointerCapture(event.pointerId), true, "Set capture to target0, target0.hasPointerCapture should be true");
});
target1.setPointerCapture(event.pointerId);
test_setPointerCapture.step(function () {
assert_equals(target0.hasPointerCapture(event.pointerId), false, "Set capture to target1, target0.hasPointerCapture should be false");
assert_equals(target1.hasPointerCapture(event.pointerId), true, "Set capture to target1, target1.hasPointerCapture should be true");
});
});
on_event(target0, "gotpointercapture", function (event) {
assert_true(false, "target0 shouldn't receive gotpointercapture");
});
on_event(target1, "gotpointercapture", function (event) {
assert_true(true, "target1 should receive gotpointercapture");
});
on_event(target1, "pointerup", function (event) {
test_setPointerCapture.done();
});
}
</script>
</head>
<body onload="run()">
<h1>Pointer Event: Test overriding the pending pointer capture element</h1>
<h4>Test Description:
After an element setPointerCapture, if another element also setPointerCapture and override it, the old pending pointer capture element shouldn't receive any gotpointercapture or lostpointercapture event
<ol>
<li>Press and hold left mouse button over black box
<li>Move mouse and release mouse button
</ol>
</h4>
<br>
<div id="target0" touch-action:none></div>
<div id="target1" touch-action:none></div>
<div id="complete-notice">
<p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
</div>
<div id="log"></div>
</body>
</html>

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

@ -0,0 +1,62 @@
<!doctype html>
<html>
<head>
<title>setPointerCapture() to the element which already captured the pointer</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="pointerevent_support.js"></script>
<script type="text/javascript">
var detected_pointertypes = {};
add_completion_callback(showPointerTypes);
var test_setPointerCapture = async_test("setPointerCapture: set to the element which already captured the pointer");
var got_pointer_capture = false;
function run() {
var target0 = document.getElementById("target0");
var target1 = document.getElementById("target1");
on_event(target0, "pointerdown", function (event) {
detected_pointertypes[event.pointerType] = true;
target0.setPointerCapture(event.pointerId);
});
on_event(target0, "gotpointercapture", function (event) {
test_setPointerCapture.step(function () {
assert_equals(got_pointer_capture, false, "Target0 should receive gotpointercapture at the first time it captured the pointer");
assert_equals(target0.hasPointerCapture(event.pointerId), true, "Target 0 received gotpointercapture, target0.hasPointerCapture should be true");
});
got_pointer_capture = true;
target0.setPointerCapture(event.pointerId);
test_setPointerCapture.step(function () {
assert_equals(target0.hasPointerCapture(event.pointerId), true, "Set capture to target0, target0.hasPointerCapture should be true");
assert_equals(target1.hasPointerCapture(event.pointerId), false, "Set capture to target0, target1.hasPointerCapture should be false");
});
});
on_event(target0, "pointerup", function (event) {
test_setPointerCapture.done();
});
}
</script>
</head>
<body onload="run()">
<h1>Pointer Event: setPointerCapture to the element which already captured the pointer</h1>
<h4>Test Description:
When the setPointerCapture method is invoked, if the target element had already captured the pointer, it should not trigger any gotpointercapture or lostpointercapture event
<ol>
<li>Press and hold left mouse button over black box
<li>Move mouse and release mouse button
</ol>
</h4>
<br>
<div id="target0" touch-action:none></div>
<div id="target1" touch-action:none></div>
<div id="complete-notice">
<p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
</div>
<div id="log"></div>
</body>
</html>