Fix crash by focusing multiple-fields input types during a unload event.

ContainerNode::removeChildren:
We should remove focus after dispatching unload events. Document::
m_focusedNode could have an element not in the document tree.

Document::implicitOpen:
Confirm that removeChildren clears m_focusedNode.

BaseMultipleFieldsDateAndTimeInputType::didBlurFromControl:
Protect element() because it might loose the last reference by
setFocus(false).

BUG=249640

Review URL: https://chromiumcodereview.appspot.com/17577013

git-svn-id: svn://svn.chromium.org/blink/trunk@152990 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-crash-by-focus-on-unload-expected.txt b/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-crash-by-focus-on-unload-expected.txt
new file mode 100644
index 0000000..fbfeed9
--- /dev/null
+++ b/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-crash-by-focus-on-unload-expected.txt
@@ -0,0 +1 @@
+PASS if not crashed.
diff --git a/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-crash-by-focus-on-unload.html b/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-crash-by-focus-on-unload.html
new file mode 100644
index 0000000..2890008
--- /dev/null
+++ b/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-crash-by-focus-on-unload.html
@@ -0,0 +1,21 @@
+<script>
+// This test requires ASAN to detect a regression.
+function runTest() {
+    document.querySelector('iframe').contentWindow.addEventListener('unload', function() {
+        document.querySelector('input').focus();
+    }, true);
+
+    if (window.testRunner)
+        testRunner.dumpAsText();
+    document.writeln('');
+    if (window.GCController)
+        GCController.collect();
+    else if (window.gc)
+        gc();
+    document.writeln('PASS if not crashed.');
+}
+</script>
+<body onload="runTest()">
+<input type="time">
+<iframe></iframe>
+</body>
diff --git a/Source/core/dom/ContainerNode.cpp b/Source/core/dom/ContainerNode.cpp
index f9ce2ee..1f9b351 100644
--- a/Source/core/dom/ContainerNode.cpp
+++ b/Source/core/dom/ContainerNode.cpp
@@ -556,9 +556,6 @@
     // The container node can be removed from event handlers.
     RefPtr<ContainerNode> protect(this);
 
-    // exclude this node when looking for removed focusedNode since only children will be removed
-    document()->removeFocusedNodeOfSubtree(this, true);
-
     if (FullscreenController* fullscreen = FullscreenController::fromIfExists(document()))
         fullscreen->removeFullScreenElementOfSubtree(this, true);
 
@@ -566,6 +563,12 @@
     // and remove... e.g. stop loading frames, fire unload events.
     willRemoveChildren(protect.get());
 
+    // Exclude this node when looking for removed focusedNode since only
+    // children will be removed.
+    // This must be later than willRemvoeChildren, which might change focus
+    // state of a child.
+    document()->removeFocusedNodeOfSubtree(this, true);
+
     NodeVector removedChildren;
     {
         WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
diff --git a/Source/core/dom/Document.cpp b/Source/core/dom/Document.cpp
index 34ad732..7f3a7be 100644
--- a/Source/core/dom/Document.cpp
+++ b/Source/core/dom/Document.cpp
@@ -2146,6 +2146,7 @@
     cancelParsing();
 
     removeChildren();
+    ASSERT(!m_focusedNode);
 
     setCompatibilityMode(NoQuirksMode);
 
diff --git a/Source/core/html/BaseMultipleFieldsDateAndTimeInputType.cpp b/Source/core/html/BaseMultipleFieldsDateAndTimeInputType.cpp
index fcf04bf..a6797f4 100644
--- a/Source/core/html/BaseMultipleFieldsDateAndTimeInputType.cpp
+++ b/Source/core/html/BaseMultipleFieldsDateAndTimeInputType.cpp
@@ -153,6 +153,7 @@
     // We don't need to call blur(). This function is called when control
     // lost focus.
 
+    RefPtr<HTMLInputElement> protector(element());
     // Remove focus ring by CSS "focus" pseudo class.
     element()->setFocus(false);
 }
@@ -163,6 +164,7 @@
     // got focus.
 
     // Add focus ring by CSS "focus" pseudo class.
+    // FIXME: Setting the focus flag to non-focused element is too tricky.
     element()->setFocus(true);
 }