зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1284788 - Allow change target of pointer lock when the pointer has been locked in the document. r=smaug
MozReview-Commit-ID: HiPkCPrQQr0 --HG-- extra : rebase_source : ce3826834065242a4e99b82d52ac65ddc205ae61
This commit is contained in:
Родитель
90c16684c7
Коммит
834c029b00
|
@ -12369,6 +12369,39 @@ GetPointerLockError(Element* aElement, Element* aCurrentLock,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
static void
|
||||
ChangePointerLockedElement(Element* aElement, nsIDocument* aDocument,
|
||||
Element* aPointerLockedElement)
|
||||
{
|
||||
// aDocument here is not really necessary, as it is the uncomposed
|
||||
// document of both aElement and aPointerLockedElement as far as one
|
||||
// is not nullptr, and they wouldn't both be nullptr in any case.
|
||||
// But since the caller of this function should have known what the
|
||||
// document is, we just don't try to figure out what it should be.
|
||||
MOZ_ASSERT(aDocument);
|
||||
MOZ_ASSERT(aElement != aPointerLockedElement);
|
||||
if (aPointerLockedElement) {
|
||||
MOZ_ASSERT(aPointerLockedElement->GetUncomposedDoc() == aDocument);
|
||||
aPointerLockedElement->ClearPointerLock();
|
||||
}
|
||||
if (aElement) {
|
||||
MOZ_ASSERT(aElement->GetUncomposedDoc() == aDocument);
|
||||
aElement->SetPointerLock();
|
||||
EventStateManager::sPointerLockedElement = do_GetWeakReference(aElement);
|
||||
EventStateManager::sPointerLockedDoc = do_GetWeakReference(aDocument);
|
||||
NS_ASSERTION(EventStateManager::sPointerLockedElement &&
|
||||
EventStateManager::sPointerLockedDoc,
|
||||
"aElement and this should support weak references!");
|
||||
} else {
|
||||
EventStateManager::sPointerLockedElement = nullptr;
|
||||
EventStateManager::sPointerLockedDoc = nullptr;
|
||||
}
|
||||
// Retarget all events to aElement via capture or
|
||||
// stop retargeting if aElement is nullptr.
|
||||
nsIPresShell::SetCapturingContent(aElement, CAPTURE_POINTERLOCK);
|
||||
DispatchPointerLockChange(aDocument);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PointerLockRequest::Run()
|
||||
{
|
||||
|
@ -12390,6 +12423,12 @@ PointerLockRequest::Run()
|
|||
}
|
||||
// Note, we must bypass focus change, so pass true as the last parameter!
|
||||
error = GetPointerLockError(e, pointerLockedElement, true);
|
||||
// Another element in the same document is requesting pointer lock,
|
||||
// just grant it without user input check.
|
||||
if (!error && pointerLockedElement) {
|
||||
ChangePointerLockedElement(e, d, pointerLockedElement);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// If it is neither user input initiated, nor requested in fullscreen,
|
||||
// it should be rejected.
|
||||
|
@ -12404,18 +12443,10 @@ PointerLockRequest::Run()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
e->SetPointerLock();
|
||||
EventStateManager::sPointerLockedElement = do_GetWeakReference(e);
|
||||
EventStateManager::sPointerLockedDoc = do_GetWeakReference(doc);
|
||||
NS_ASSERTION(EventStateManager::sPointerLockedElement &&
|
||||
EventStateManager::sPointerLockedDoc,
|
||||
"aElement and this should support weak references!");
|
||||
|
||||
ChangePointerLockedElement(e, d, nullptr);
|
||||
nsContentUtils::DispatchEventOnlyToChrome(
|
||||
doc, ToSupports(e), NS_LITERAL_STRING("MozDOMPointerLock:Entered"),
|
||||
/* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
|
||||
|
||||
DispatchPointerLockChange(d);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -12507,19 +12538,12 @@ nsDocument::UnlockPointer(nsIDocument* aDoc)
|
|||
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
if (pointerLockedElement) {
|
||||
pointerLockedElement->ClearPointerLock();
|
||||
}
|
||||
|
||||
EventStateManager::sPointerLockedElement = nullptr;
|
||||
EventStateManager::sPointerLockedDoc = nullptr;
|
||||
ChangePointerLockedElement(nullptr, doc, pointerLockedElement);
|
||||
|
||||
nsContentUtils::DispatchEventOnlyToChrome(
|
||||
doc, ToSupports(pointerLockedElement),
|
||||
NS_LITERAL_STRING("MozDOMPointerLock:Exited"),
|
||||
/* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
|
||||
|
||||
DispatchPointerLockChange(pointerLockedDoc);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -4346,9 +4346,6 @@ EventStateManager::SetPointerLock(nsIWidget* aWidget,
|
|||
aWidget->SynthesizeNativeMouseMove(
|
||||
sLastRefPoint + aWidget->WidgetToScreenOffset(), nullptr);
|
||||
|
||||
// Retarget all events to this element via capture.
|
||||
nsIPresShell::SetCapturingContent(aElement, CAPTURE_POINTERLOCK);
|
||||
|
||||
// Suppress DnD
|
||||
if (dragService) {
|
||||
dragService->Suppress();
|
||||
|
@ -4367,9 +4364,6 @@ EventStateManager::SetPointerLock(nsIWidget* aWidget,
|
|||
mPreLockPoint + aWidget->WidgetToScreenOffset(), nullptr);
|
||||
}
|
||||
|
||||
// Don't retarget events to this element any more.
|
||||
nsIPresShell::SetCapturingContent(nullptr, CAPTURE_POINTERLOCK);
|
||||
|
||||
// Unsuppress DnD
|
||||
if (dragService) {
|
||||
dragService->Unsuppress();
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1284788</title>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="pointerlock_utils.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
|
||||
<style>
|
||||
#block1, #block2, #block3 {
|
||||
background: blue;
|
||||
width: 50px; height: 50px;
|
||||
margin: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="block1"></div>
|
||||
<div id="block2"></div>
|
||||
<div id="block3"></div>
|
||||
<div id="test">
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestFlakyTimeout("For changing pointer lock element not in a valid user event handler");
|
||||
|
||||
var block1 = document.getElementById("block1");
|
||||
var block2 = document.getElementById("block2");
|
||||
var block3 = document.getElementById("block3");
|
||||
|
||||
class ClickTester {
|
||||
constructor(target) {
|
||||
this._target = target;
|
||||
this._callback = null;
|
||||
document.addEventListener("click", this);
|
||||
}
|
||||
|
||||
synthesize(callback) {
|
||||
ok(!this._callback, "No callback should have been hooked");
|
||||
this._callback = callback;
|
||||
synthesizeMouseAtCenter(this._target, {}, window);
|
||||
}
|
||||
|
||||
handleEvent(e) {
|
||||
ok(!!this._callback, "Should have hooked a callback");
|
||||
var callback = this._callback;
|
||||
this._callback = null;
|
||||
callback(e);
|
||||
}
|
||||
};
|
||||
|
||||
var tester = new ClickTester(block3);
|
||||
// It would be called in handler of load event in pointerlock_utils.js
|
||||
function start() {
|
||||
tester.synthesize(firstClick);
|
||||
}
|
||||
|
||||
function firstClick(e) {
|
||||
is(e.target, block3, "Click is triggered inside block3");
|
||||
document.addEventListener("mozpointerlockchange", lockedPointerOnBlock1);
|
||||
block1.mozRequestPointerLock();
|
||||
}
|
||||
|
||||
function lockedPointerOnBlock1() {
|
||||
document.removeEventListener("mozpointerlockchange", lockedPointerOnBlock1);
|
||||
is(document.mozPointerLockElement, block1, "Pointer should be locked on #block1");
|
||||
SimpleTest.executeSoon(() => {
|
||||
tester.synthesize(secondClick);
|
||||
});
|
||||
}
|
||||
|
||||
function secondClick(e) {
|
||||
is(e.target, block1, "Event should be redirected to block1");
|
||||
// Use 2s to ensure that we never consider this as an extension of user input.
|
||||
setTimeout(() => {
|
||||
document.addEventListener("mozpointerlockchange", lockedPointerOnBlock2);
|
||||
block2.mozRequestPointerLock();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function lockedPointerOnBlock2() {
|
||||
document.removeEventListener("mozpointerlockchange", lockedPointerOnBlock2);
|
||||
is(document.mozPointerLockElement, block2, "Pointer should be locked on #block2");
|
||||
SimpleTest.executeSoon(() => {
|
||||
tester.synthesize(thirdClick);
|
||||
});
|
||||
}
|
||||
|
||||
function thirdClick(e) {
|
||||
is(e.target, block2, "Event should be redirected to block2");
|
||||
// Use 2s to ensure that we never consider this as an extension of user input.
|
||||
setTimeout(() => {
|
||||
document.addEventListener("mozpointerlockchange", lockedPointerOnBlock1Again);
|
||||
block1.mozRequestPointerLock();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function lockedPointerOnBlock1Again() {
|
||||
document.removeEventListener("mozpointerlockchange", lockedPointerOnBlock1Again);
|
||||
is(document.mozPointerLockElement, block1, "Pointer should be locked on #block1 again");
|
||||
SimpleTest.executeSoon(() => {
|
||||
tester.synthesize(fourthClick);
|
||||
});
|
||||
}
|
||||
|
||||
function fourthClick(e) {
|
||||
is(e.target, block1, "Event should be redirected to block1 again");
|
||||
document.addEventListener("mozpointerlockchange", () => SimpleTest.finish());
|
||||
document.mozExitPointerLock();
|
||||
}
|
||||
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -18,6 +18,7 @@ support-files =
|
|||
file_suppressSomeMouseEvents.html
|
||||
file_locksvgelement.html
|
||||
file_allowPointerLockSandboxFlag.html
|
||||
file_changeLockElement.html
|
||||
iframe_differentDOM.html
|
||||
|
||||
[test_pointerlock-api.html]
|
||||
|
|
|
@ -56,7 +56,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
|
|||
"file_suppressSomeMouseEvents.html",
|
||||
"file_targetOutOfFocus.html",
|
||||
"file_withoutDOM.html",
|
||||
"file_allowPointerLockSandboxFlag.html"
|
||||
"file_allowPointerLockSandboxFlag.html",
|
||||
"file_changeLockElement.html",
|
||||
];
|
||||
|
||||
var gDisableList = [
|
||||
|
|
Загрузка…
Ссылка в новой задаче