Pointer Lock handles disconnected DOM elements
https://bugs.webkit.org/show_bug.cgi?id=77029
Reviewed by Adrienne Walker.
Source/WebCore:
Pointer Lock Controller now checks when elements or documents are
removed, and unlocks if the target element is being removed.
Tests: pointer-lock/locked-element-iframe-removed-from-dom.html
pointer-lock/locked-element-removed-from-dom.html
* dom/Document.cpp:
(WebCore::Document::detach):
* dom/Element.cpp:
(WebCore::Element::removedFrom):
(WebCore::Element::webkitRequestPointerLock):
* page/PointerLockController.cpp:
(WebCore::PointerLockController::requestPointerLock):
(WebCore::PointerLockController::elementRemoved):
(WebCore):
(WebCore::PointerLockController::documentDetached):
(WebCore::PointerLockController::didLosePointerLock):
(WebCore::PointerLockController::enqueueEvent):
* page/PointerLockController.h:
(WebCore):
(PointerLockController):
LayoutTests:
Two new tests that verify pointer lock is released when the target
is removed from the document.
* pointer-lock/locked-element-iframe-removed-from-dom-expected.txt: Added.
* pointer-lock/locked-element-iframe-removed-from-dom.html: Added.
* pointer-lock/locked-element-removed-from-dom-expected.txt: Added.
* pointer-lock/locked-element-removed-from-dom.html: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@122626 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/page/PointerLockController.cpp b/Source/WebCore/page/PointerLockController.cpp
index c250cb7..abbfc80 100644
--- a/Source/WebCore/page/PointerLockController.cpp
+++ b/Source/WebCore/page/PointerLockController.cpp
@@ -48,15 +48,12 @@
void PointerLockController::requestPointerLock(Element* target, PassRefPtr<VoidCallback> successCallback, PassRefPtr<VoidCallback> failureCallback)
{
- if (!target)
- return;
-
- if (!target->inDocument()) {
+ if (!target || !target->inDocument() || m_documentOfRemovedElementWhileWaitingForUnlock) {
enqueueEvent(eventNames().webkitpointerlockerrorEvent, target);
return;
}
- if (isLocked()) {
+ if (m_element) {
// FIXME: Keep enqueueEvent usage. (https://bugs.webkit.org/show_bug.cgi?id=84402)
enqueueEvent(eventNames().webkitpointerlockchangeEvent, target);
if (m_element->document() != target->document())
@@ -91,6 +88,25 @@
return m_page->chrome()->client()->requestPointerUnlock();
}
+void PointerLockController::elementRemoved(Element* element)
+{
+ if (m_element == element) {
+ m_documentOfRemovedElementWhileWaitingForUnlock = m_element->document();
+ // Set element null immediately to block any future interaction with it
+ // including mouse events received before the unlock completes.
+ m_element = 0;
+ requestPointerUnlock();
+ }
+}
+
+void PointerLockController::documentDetached(Document* document)
+{
+ if (m_element && m_element->document() == document) {
+ m_element = 0;
+ requestPointerUnlock();
+ }
+}
+
bool PointerLockController::isLocked()
{
return m_page->chrome()->client()->isPointerLocked();
@@ -136,11 +152,12 @@
{
// FIXME: Keep enqueueEvent usage. (https://bugs.webkit.org/show_bug.cgi?id=84402)
if (sendChangeEvent)
- enqueueEvent(eventNames().webkitpointerlockchangeEvent, m_element.get());
+ enqueueEvent(eventNames().webkitpointerlockchangeEvent, m_element ? m_element->document() : m_documentOfRemovedElementWhileWaitingForUnlock.get());
// FIXME: Remove callback usage. (https://bugs.webkit.org/show_bug.cgi?id=84402)
RefPtr<Element> elementToNotify(m_element);
m_element = 0;
+ m_documentOfRemovedElementWhileWaitingForUnlock = 0;
m_successCallback = 0;
m_failureCallback = 0;
if (elementToNotify && elementToNotify->document()->frame())
@@ -161,9 +178,14 @@
void PointerLockController::enqueueEvent(const AtomicString& type, Element* element)
{
- if (!element)
- return;
- element->document()->enqueueDocumentEvent(Event::create(type, true, false));
+ if (element)
+ enqueueEvent(type, element->document());
+}
+
+void PointerLockController::enqueueEvent(const AtomicString& type, Document* document)
+{
+ if (document)
+ document->enqueueDocumentEvent(Event::create(type, true, false));
}
} // namespace WebCore