Diff
Modified: trunk/LayoutTests/ChangeLog (122625 => 122626)
--- trunk/LayoutTests/ChangeLog 2012-07-13 20:35:39 UTC (rev 122625)
+++ trunk/LayoutTests/ChangeLog 2012-07-13 20:37:50 UTC (rev 122626)
@@ -1,3 +1,18 @@
+2012-07-13 Vincent Scheib <[email protected]>
+
+ Pointer Lock handles disconnected DOM elements
+ https://bugs.webkit.org/show_bug.cgi?id=77029
+
+ Reviewed by Adrienne Walker.
+
+ 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.
+
2012-07-13 W. James MacLean <[email protected]>
[chromium] Unreviewed gardening. storage/indexeddb/cursor-key-order.html has starting crashing on occassion.
Added: trunk/LayoutTests/pointer-lock/locked-element-iframe-removed-from-dom-expected.txt (0 => 122626)
--- trunk/LayoutTests/pointer-lock/locked-element-iframe-removed-from-dom-expected.txt (rev 0)
+++ trunk/LayoutTests/pointer-lock/locked-element-iframe-removed-from-dom-expected.txt 2012-07-13 20:37:50 UTC (rev 122626)
@@ -0,0 +1,18 @@
+Test removing an iframe containing a locked element causes lock to be released.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+ Lock target in iframe. (main document handler)
+ Lock target in iframe. (iframe handler)
+PASS onwebkitpointerlockchange received after: Lock target in iframe. (iframe handler)
+PASS document.webkitPointerLockElement is targetDiv1
+PASS targetDiv1.parentElement.parentElement is targetIframe1.contentDocument.body
+ Remove iframe & immediately lock target2. (main document handler)
+ Remove iframe & immediately lock target2. (iframe handler)
+PASS document.webkitPointerLockElement is targetDiv2
+PASS onwebkitpointerlockchange received after: Remove iframe & immediately lock target2. (main document handler)
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Property changes on: trunk/LayoutTests/pointer-lock/locked-element-iframe-removed-from-dom-expected.txt
___________________________________________________________________
Added: svn:eol-style
Added: trunk/LayoutTests/pointer-lock/locked-element-iframe-removed-from-dom.html (0 => 122626)
--- trunk/LayoutTests/pointer-lock/locked-element-iframe-removed-from-dom.html (rev 0)
+++ trunk/LayoutTests/pointer-lock/locked-element-iframe-removed-from-dom.html 2012-07-13 20:37:50 UTC (rev 122626)
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<div>
+ <iframe id="iframe1"></iframe>
+ <div id="target2"></div>
+</div>
+<script>
+ description("Test removing an iframe containing a locked element causes lock to be released.")
+ window.jsTestIsAsync = true;
+
+ targetIframe1 = document.getElementById("iframe1");
+ targetDiv2 = document.getElementById("target2");
+
+ todo = [
+ function () {
+ // Load a blank iframe.
+ targetIframe1.src = ""
+ targetIframe1._onload_ = function () { doNextStepWithUserGesture(); }
+ },
+ function () {
+ // Nest target element into iframe document.
+ targetIframe1.contentDocument.body.innerHTML ="<div><div></div></div>";
+ targetDiv1 = targetIframe1.contentDocument.body.firstChild.firstChild
+ expectNoEvents("Lock target in iframe. (main document handler)");
+ expectOnlyChangeEvent("Lock target in iframe. (iframe handler)", targetIframe1.contentDocument);
+ targetDiv1.webkitRequestPointerLock();
+ // doNextStep called by event handler.
+ },
+ function () {
+ shouldBe("document.webkitPointerLockElement", "targetDiv1");
+ shouldBe("targetDiv1.parentElement.parentElement", "targetIframe1.contentDocument.body");
+ expectOnlyChangeEvent("Remove iframe & immediately lock target2. (main document handler)");
+ expectNoEvents("Remove iframe & immediately lock target2. (iframe handler)", targetIframe1.contentDocument);
+ targetIframe1.parentElement.removeChild(targetIframe1);
+ targetDiv2.webkitRequestPointerLock();
+ shouldBe("document.webkitPointerLockElement", "targetDiv2");
+ // doNextStep called by event handler.
+ },
+ ];
+ doNextStep();
+</script>
+<script src=""
+</body>
+</html>
Property changes on: trunk/LayoutTests/pointer-lock/locked-element-iframe-removed-from-dom.html
___________________________________________________________________
Added: svn:eol-style
Added: trunk/LayoutTests/pointer-lock/locked-element-removed-from-dom-expected.txt (0 => 122626)
--- trunk/LayoutTests/pointer-lock/locked-element-removed-from-dom-expected.txt (rev 0)
+++ trunk/LayoutTests/pointer-lock/locked-element-removed-from-dom-expected.txt 2012-07-13 20:37:50 UTC (rev 122626)
@@ -0,0 +1,21 @@
+Test removing a locked element from a document causes lock to be released.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+ Lock target in iframe. (main document handler).
+ Lock target in iframe. (iframe handler)
+PASS onwebkitpointerlockchange received after: Lock target in iframe. (iframe handler)
+PASS document.webkitPointerLockElement is targetDiv1
+PASS targetDiv1.parentElement.parentElement is targetIframe1.contentDocument.body
+ Remove targetDiv1's parent from iframe & immediately lock target2. (main document handler)
+ Remove targetDiv1's parent from iframe & immediately lock target2. (iframe handler)
+PASS document.webkitPointerLockElement is null
+PASS targetDiv1.parentElement.parentElement is null
+PASS onwebkitpointerlockerror received after: Remove targetDiv1's parent from iframe & immediately lock target2. (main document handler)
+PASS onwebkitpointerlockchange received after: Remove targetDiv1's parent from iframe & immediately lock target2. (iframe handler)
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+
Property changes on: trunk/LayoutTests/pointer-lock/locked-element-removed-from-dom-expected.txt
___________________________________________________________________
Added: svn:eol-style
Added: trunk/LayoutTests/pointer-lock/locked-element-removed-from-dom.html (0 => 122626)
--- trunk/LayoutTests/pointer-lock/locked-element-removed-from-dom.html (rev 0)
+++ trunk/LayoutTests/pointer-lock/locked-element-removed-from-dom.html 2012-07-13 20:37:50 UTC (rev 122626)
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<div>
+ <iframe id="iframe1"></iframe>
+ <div id="target2"></div>
+</div>
+<script>
+ description("Test removing a locked element from a document causes lock to be released.")
+ window.jsTestIsAsync = true;
+
+ targetIframe1 = document.getElementById("iframe1");
+ targetDiv2 = document.getElementById("target2");
+
+ todo = [
+ function () {
+ // Load a blank iframe.
+ targetIframe1.src = ""
+ targetIframe1._onload_ = function () { doNextStepWithUserGesture(); }
+ },
+ function () {
+ // Nest target element into iframe document.
+ targetIframe1.contentDocument.body.innerHTML ="<div><div></div></div>";
+ targetDiv1 = targetIframe1.contentDocument.body.firstChild.firstChild
+ expectNoEvents("Lock target in iframe. (main document handler).");
+ expectOnlyChangeEvent("Lock target in iframe. (iframe handler)", targetIframe1.contentDocument);
+ targetDiv1.webkitRequestPointerLock();
+ // doNextStep called by event handler.
+ },
+ function () {
+ shouldBe("document.webkitPointerLockElement", "targetDiv1");
+ shouldBe("targetDiv1.parentElement.parentElement", "targetIframe1.contentDocument.body");
+ expectOnlyErrorEvent("Remove targetDiv1's parent from iframe & immediately lock target2. (main document handler)");
+ expectOnlyChangeEvent("Remove targetDiv1's parent from iframe & immediately lock target2. (iframe handler)", targetIframe1.contentDocument);
+ targetDiv1.parentElement.parentElement.removeChild(targetDiv1.parentElement);
+ targetDiv2.webkitRequestPointerLock();
+ shouldBe("document.webkitPointerLockElement", "null");
+ shouldBe("targetDiv1.parentElement.parentElement", "null");
+ // doNextStep called by event handler.
+ },
+ ];
+ doNextStep();
+</script>
+<script src=""
+</body>
+</html>
Property changes on: trunk/LayoutTests/pointer-lock/locked-element-removed-from-dom.html
___________________________________________________________________
Added: svn:eol-style
Modified: trunk/Source/WebCore/ChangeLog (122625 => 122626)
--- trunk/Source/WebCore/ChangeLog 2012-07-13 20:35:39 UTC (rev 122625)
+++ trunk/Source/WebCore/ChangeLog 2012-07-13 20:37:50 UTC (rev 122626)
@@ -1,3 +1,32 @@
+2012-07-13 Vincent Scheib <[email protected]>
+
+ Pointer Lock handles disconnected DOM elements
+ https://bugs.webkit.org/show_bug.cgi?id=77029
+
+ Reviewed by Adrienne Walker.
+
+ 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):
+
2012-07-13 Ryosuke Niwa <[email protected]>
HTMLCollection should use DynamicNodeList's invalidation model
Modified: trunk/Source/WebCore/dom/Document.cpp (122625 => 122626)
--- trunk/Source/WebCore/dom/Document.cpp 2012-07-13 20:35:39 UTC (rev 122625)
+++ trunk/Source/WebCore/dom/Document.cpp 2012-07-13 20:37:50 UTC (rev 122626)
@@ -2080,6 +2080,11 @@
ASSERT(attached());
ASSERT(!m_inPageCache);
+#if ENABLE(POINTER_LOCK)
+ if (page())
+ page()->pointerLockController()->documentDetached(this);
+#endif
+
if (this == topDocument())
clearAXObjectCache();
Modified: trunk/Source/WebCore/dom/Element.cpp (122625 => 122626)
--- trunk/Source/WebCore/dom/Element.cpp 2012-07-13 20:35:39 UTC (rev 122625)
+++ trunk/Source/WebCore/dom/Element.cpp 2012-07-13 20:37:50 UTC (rev 122626)
@@ -913,6 +913,10 @@
if (containsFullScreenElement())
setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
#endif
+#if ENABLE(POINTER_LOCK)
+ if (document()->page())
+ document()->page()->pointerLockController()->elementRemoved(this);
+#endif
setSavedLayerScrollOffset(IntSize());
@@ -1890,7 +1894,8 @@
#if ENABLE(POINTER_LOCK)
void Element::webkitRequestPointerLock()
{
- document()->frame()->page()->pointerLockController()->requestPointerLock(this, 0, 0);
+ if (document()->page())
+ document()->page()->pointerLockController()->requestPointerLock(this, 0, 0);
}
#endif
Modified: trunk/Source/WebCore/page/PointerLockController.cpp (122625 => 122626)
--- trunk/Source/WebCore/page/PointerLockController.cpp 2012-07-13 20:35:39 UTC (rev 122625)
+++ trunk/Source/WebCore/page/PointerLockController.cpp 2012-07-13 20:37:50 UTC (rev 122626)
@@ -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,11 +178,16 @@
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
#endif // ENABLE(POINTER_LOCK)
Modified: trunk/Source/WebCore/page/PointerLockController.h (122625 => 122626)
--- trunk/Source/WebCore/page/PointerLockController.h 2012-07-13 20:35:39 UTC (rev 122625)
+++ trunk/Source/WebCore/page/PointerLockController.h 2012-07-13 20:37:50 UTC (rev 122626)
@@ -33,6 +33,7 @@
namespace WebCore {
class Element;
+class Document;
class Page;
class PlatformMouseEvent;
class VoidCallback;
@@ -45,7 +46,9 @@
void requestPointerLock(Element* target, PassRefPtr<VoidCallback> successCallback, PassRefPtr<VoidCallback> failureCallback);
void requestPointerUnlock();
- bool isLocked();
+ void elementRemoved(Element*);
+ void documentDetached(Document*);
+ bool isLocked(); // FIXME: Rename to isClientLocked and move to private when removing old API. (https://bugs.webkit.org/show_bug.cgi?id=84402)
Element* element() const;
void didAcquirePointerLock();
@@ -56,8 +59,10 @@
private:
explicit PointerLockController(Page*);
void enqueueEvent(const AtomicString& type, Element*);
+ void enqueueEvent(const AtomicString& type, Document*);
Page* m_page;
RefPtr<Element> m_element;
+ RefPtr<Document> m_documentOfRemovedElementWhileWaitingForUnlock;
// FIXME: Remove callback usage. (https://bugs.webkit.org/show_bug.cgi?id=84402)
RefPtr<VoidCallback> m_successCallback;