Bug 1216087 - Unlock pointer whenever the element is unbound from the tree. r=smaug
authorXidorn Quan <quanxunzhen@gmail.com>
Tue, 20 Oct 2015 10:02:03 +1100
changeset 303594 272319a15188085adf710590289cf84b8192ca1a
parent 303593 d273e971464c1b76f0566602e2f0bdcee88d1726
child 303595 668563c7fab88c1fdcef3aad6ff2a42f13196652
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1216087
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1216087 - Unlock pointer whenever the element is unbound from the tree. r=smaug
dom/base/Element.cpp
dom/tests/mochitest/pointerlock/file_removedFromDOM.html
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1715,30 +1715,30 @@ Element::UnbindFromTree(bool aDeep, bool
                   "kids!");
 
   RemoveFromIdTable();
 
   // Make sure to unbind this node before doing the kids
   nsIDocument* document =
     HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetComposedDoc();
 
+  if (HasPointerLock()) {
+    nsIDocument::UnlockPointer();
+  }
   if (aNullParent) {
     if (IsFullScreenAncestor()) {
       // The element being removed is an ancestor of the full-screen element,
       // exit full-screen state.
       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                       NS_LITERAL_CSTRING("DOM"), OwnerDoc(),
                                       nsContentUtils::eDOM_PROPERTIES,
                                       "RemovedFullScreenElement");
       // Fully exit full-screen.
       nsIDocument::ExitFullscreenInDocTree(OwnerDoc());
     }
-    if (HasPointerLock()) {
-      nsIDocument::UnlockPointer();
-    }
 
     if (GetParent() && GetParent()->IsInUncomposedDoc()) {
       // Update the editable descendant count in the ancestors before we
       // lose the reference to the parent.
       int32_t editableDescendantChange = -1 * EditableInclusiveDescendantCount(this);
       if (editableDescendantChange != 0) {
         nsIContent* parent = GetParent();
         while (parent) {
--- a/dom/tests/mochitest/pointerlock/file_removedFromDOM.html
+++ b/dom/tests/mochitest/pointerlock/file_removedFromDOM.html
@@ -1,68 +1,95 @@
 <!DOCTYPE HTML>
 <html>
   <!--
   https://bugzilla.mozilla.org/show_bug.cgi?id=633602
 
   Test DOM tree in full screen
   -->
-  <head>
-    <title>Bug 633602 - file_DOMtree.html</title>
-    <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js">
-    </script>
-    <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
-    </script>
-    <script type="application/javascript" src="pointerlock_utils.js"></script>
-    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-    <style>
-    </style>
-  </head>
-  <body>
-    <a target="_blank"
-       href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
-      Mozilla Bug 633602
-    </a>
-    <div id="div"></div>
-    <pre id="test">
-      <script type="text/javascript">
-        /*
-         * Test for Bug 633602
-         * Checks if pointer is unlocked when element is removed from
-         * the DOM Tree
-         */
+<head>
+<title>Bug 633602 - file_DOMtree.html</title>
+<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="pointerlock_utils.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank"
+    href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
+  Mozilla Bug 633602
+</a>
+<div id="div"></div>
+<div id="outer"><div id="inner"></div></div>
+<pre id="test">
+<script type="text/javascript">
+/*
+  * Test for Bug 633602
+  * Checks if pointer is unlocked when element is removed from
+  * the DOM Tree
+  */
 
-        SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForExplicitFinish();
+
+var div = document.getElementById("div");
+var outer = document.getElementById("outer");
+var inner = document.getElementById("inner");
 
-        var div = document.getElementById("div")
-          , removedDOM = false;
+function listenOneDocEvent(type, handler) {
+  function callback(event) {
+    document.removeEventListener(type, callback);
+    SimpleTest.executeSoon(() => handler(event));
+  }
+  document.addEventListener(type, callback);
+}
 
-        function runTests() {
-          ok(removedDOM, "Pointer should be unlocked when " +
-            "an element is removed the DOM Tree");
-        }
+function checkPointerLockElement(elem) {
+  if (elem) {
+    is(document.mozPointerLockElement, elem,
+       `#${elem.id} should have locked the pointer`);
+  } else {
+    ok(!document.mozPointerLockElement, "Pointer should have been unlocked");
+  }
+}
 
-        document.addEventListener("mozpointerlockchange", function (e) {
-          if (document.mozPointerLockElement === div) {
-            document.body.removeChild(div);
-            removedDOM = !document.mozPointerLockElement;
-            document.mozCancelFullScreen();
-          }
+function start() {
+  listenOneDocEvent("mozfullscreenchange", enteredFullscreen);
+  document.documentElement.mozRequestFullScreen();
+}
 
-        }, false);
+function enteredFullscreen() {
+  is(document.mozFullScreenElement, document.documentElement,
+     "Root element should have entered fullscreen");
+  listenOneDocEvent("mozpointerlockchange", lockedPointerOnDiv);
+  div.mozRequestPointerLock();
+}
 
-        document.addEventListener("mozfullscreenchange", function (e) {
-          if (document.mozFullScreenElement === div) {
-              div.mozRequestPointerLock();
-          }
-          else {
-            runTests();
-            SimpleTest.finish();
-          }
-        }, false);
+function lockedPointerOnDiv() {
+  checkPointerLockElement(div);
+  listenOneDocEvent("mozpointerlockchange", unlockedPointerFromDiv);
+  document.body.removeChild(div);
+}
+
+function unlockedPointerFromDiv() {
+  checkPointerLockElement(null);
+  listenOneDocEvent("mozpointerlockchange", lockedPointerOnInner);
+  inner.mozRequestPointerLock();
+}
 
-        function start() {
-          div.mozRequestFullScreen();
-        }
-      </script>
-    </pre>
-  </body>
+function lockedPointerOnInner() {
+  checkPointerLockElement(inner);
+  listenOneDocEvent("mozpointerlockchange", unlockedPointerFromInner);
+  document.body.removeChild(outer);
+}
+
+function unlockedPointerFromInner() {
+  checkPointerLockElement(null);
+  listenOneDocEvent("mozfullscreenchange", exitedFullscreen);
+  document.mozCancelFullScreen();
+}
+
+function exitedFullscreen() {
+  SimpleTest.finish();
+}
+</script>
+</pre>
+</body>
 </html>