<!doctype html>
<html>
<head>
<title>Set/Release capture when using chorded buttons</title>
<meta name="viewport" content="width=device-width">
<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1053385">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<style>
.container {
height: 500px;
width: 500px;
border: 1px solid black;
overflow: hidden;
position: relative;
}
#box {
height: 50px;
width: 50px;
background: red;
position: absolute;
}
</style>
</head>
<body>
<h1>Pointer Events Capture Test - capture should not be lost early</h1>
<h4>
Test Description: This test checks if setCapture/pointerup functions
works properly. Complete the following actions:
<ol>
<li> Put your mouse over the red box
<li> Press and hold left mouse button. Box will call setPointerCapture
<li> Press right button and release
<li> Pointer capture should not be lost
<li> Press right button again and release
<li> Pointer capture should not be lost
<li> Release left mouse button. lostpointercapture is called
</ol>
</h4>
Test passes if the proper behavior of the events is observed.
<div class="container">
<div id="box"></div>
</div>
<div id="log"></div>
</body>
<script>
var PhaseEnum = {
WaitingForDown: "down",
WaitingForUp: "up",
UpDone : "up_done"
};
var origin = {x:0, y:0};
var position = {x:0, y:0};
var deltaX = 0;
var deltaY = 0;
var box = document.getElementById("box");
var logDiv = document.getElementById("log");
var currentPhase = PhaseEnum.WaitingForDown;
var events = [];
function slide(event){
// move the target following the mouse
deltaX = event.clientX - origin.x
deltaY = event.clientY - origin.y
box.style.left = `${position.x + deltaX}px`;
box.style.top = `${position.y + deltaY}px`;
}
function addLog(message){
var messageDiv = document.createElement("div");
var textContent = document.createTextNode(message);
messageDiv.appendChild(textContent);
logDiv.appendChild(messageDiv);
}
function handle_pointerdown(e){
box.setPointerCapture(e.pointerId);
if(window.promise_test){
current_test.step(function(){
// once receiving a pointer down and the pointer is captured,
// no other mousedown should send pointerdown events during the test
assert_equals(currentPhase, PhaseEnum.WaitingForDown,
"Current Phase should be " + PhaseEnum.WaitingForDown);
currentPhase = PhaseEnum.WaitingForUp;
events.push("target@pointerdown");
});
}
origin = { x: event.clientX, y: event.clientY };
box.addEventListener("pointermove", slide);
}
function handle_pointerup(e){
box.releasePointerCapture(e.pointerId);
if(window.promise_test){
current_test.step(function(){
assert_equals(event.buttons, 0,
'pointerup should happen when all buttons are released.');
assert_equals(currentPhase, PhaseEnum.WaitingForUp,
"Current Phase should be " + PhaseEnum.WaitingForUp);
currentPhase = PhaseEnum.UpDone;
events.push("target@pointerup");
});
}
box.removeEventListener("pointermove", slide);
}
function handle_contextmenu(e){
e.preventDefault();
}
function handle_lostpointercapture(e){
if(window.promise_test){
current_test.step(function(){
events.push("target@lostpointercapture");
assert_equals(currentPhase, PhaseEnum.UpDone,
"Current Phase should be " + PhaseEnum.UpDone + "." +
'lostpointercapture should happen after pointerup event.');
assert_equals(event.buttons, 0,
'lostpointercapture should happen when all buttons are released.');
assert_array_equals(events, ["target@pointerdown",
"target@pointerup", "target@lostpointercapture"]);
resolve_test();
current_test.done();
});
}
if(event.buttons === 0){
addLog("Test Passed!");
}else{
addLog("Test Failed!");
}
}
function removeEventListeners(){
box.removeEventListener('pointerdown', handle_pointerdown);
box.removeEventListener('pointerup', handle_pointerup);
box.removeEventListener('contextmenu', handle_contextmenu);
box.removeEventListener('lostpointercapture',
handle_lostpointercapture);
}
function addEventListeners(){
box.addEventListener('pointerdown', handle_pointerdown);
box.addEventListener('pointerup', handle_pointerup);
box.addEventListener('contextmenu', handle_contextmenu);
box.addEventListener('lostpointercapture',
handle_lostpointercapture);
}
var current_test = null;
var resolve_test = null;
var reject_test = null;
// window.promise_test is only defined when running the
// test using testharness.js
// if window.promise_test is not defined we'll run the manual testing
// path
if(!window.promise_test){
addEventListeners();
}
if(window.promise_test){
promise_test(function(t){
addEventListeners();
t.add_cleanup(function(){
removeEventListeners();
currentPhase = PhaseEnum.WaitingForDown;
events = [];
});
return new Promise(function(resolve, reject){
current_test = t;
resolve_test = resolve;
reject_test = reject;
var actions = new test_driver.Actions();
var actions_promise = actions
.pointerMove(0, 0, {origin: box})
.pointerDown({button: actions.ButtonType.LEFT})
// Ensure clicking other buttons while a first button has
// captured the pointer doesn't release the capture
.pointerDown({button: actions.ButtonType.RIGHT})
.pointerUp({button: actions.ButtonType.RIGHT})
.pointerDown({button: actions.ButtonType.RIGHT})
.pointerUp({button: actions.ButtonType.RIGHT})
.pointerUp({button: actions.ButtonType.LEFT})
.send();
})
}, "Pointer Events Capture Test - capture not lost due to " +
"chorded buttons interaction");
promise_test(function(t){
addEventListeners();
t.add_cleanup(function(){
removeEventListeners();
currentPhase = PhaseEnum.WaitingForDown;
events = [];
});
return new Promise(function(resolve, reject){
current_test = t;
resolve_test = resolve;
reject_test = reject;
var actions = new test_driver.Actions();
var actions_promise = actions
.pointerMove(0, 0, {origin: box})
.pointerDown({button: actions.ButtonType.LEFT})
// Ensure clicking other buttons while a first button has
// captured the pointer doesn't release the capture
.pointerDown({button: actions.ButtonType.RIGHT})
.pointerUp({button: actions.ButtonType.LEFT})
.pointerDown({button: actions.ButtonType.LEFT})
.pointerUp({button: actions.ButtonType.RIGHT})
.pointerUp({button: actions.ButtonType.LEFT})
.send();
})
}, "Pointer Events Capture Test - capture not lost " +
"due to combination of left and right chorded buttons interaction.");
}
</script>
</html>