Make Range::nodeWillBeRemoved() to accept removed node

This patch changes Range::nodeWillBeRemoved() to accept remove node by replacing ASSERT to if-statement. Range::nodeWillBeRemoved() might be called with removed node, Node::parentNode() == nullptr, when DOMNodeRemovedFromDocument event handler calls removeChild(), directly or indirectly, for node being removed.

This patch is a part of fixing issue 240594 for reproducing the reported situation.

BUG=240594
TEST=LayoutTests/fast/dom/Range/remove-twice-crash.html
R=tkent@chromium.org

Review URL: https://codereview.chromium.org/23709004

git-svn-id: svn://svn.chromium.org/blink/trunk@157193 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/LayoutTests/fast/dom/Range/remove-twice-crash-expected.txt b/LayoutTests/fast/dom/Range/remove-twice-crash-expected.txt
new file mode 100644
index 0000000..66146b5
--- /dev/null
+++ b/LayoutTests/fast/dom/Range/remove-twice-crash-expected.txt
@@ -0,0 +1 @@
+PASS; NOT CRASHED
diff --git a/LayoutTests/fast/dom/Range/remove-twice-crash.html b/LayoutTests/fast/dom/Range/remove-twice-crash.html
new file mode 100644
index 0000000..2d3d2ac
--- /dev/null
+++ b/LayoutTests/fast/dom/Range/remove-twice-crash.html
@@ -0,0 +1,29 @@
+<div id="container">
+<div id="sample">foo</div>
+</div>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+function $(id) { return document.getElementById(id); }
+
+var done = false;
+document.addEventListener("DOMNodeRemovedFromDocument", function () {
+    if (done)
+        return;
+    done = true;
+    var beingRemoved = event.srcElement;
+    beingRemoved.parentNode.removeChild(beingRemoved);
+}, true);
+
+var range = document.createRange();
+range.selectNode($('sample'));
+
+try {
+    $('sample').parentNode.removeChild($('sample'));
+} catch (e) {
+    // We get 'NotFoundError'.
+}
+
+$('container').outerHTML = 'PASS; NOT CRASHED';
+</script>
diff --git a/Source/core/dom/Range.cpp b/Source/core/dom/Range.cpp
index a1867ed..6b7b24a 100644
--- a/Source/core/dom/Range.cpp
+++ b/Source/core/dom/Range.cpp
@@ -1705,7 +1705,11 @@
     ASSERT(node);
     ASSERT(&node->document() == m_ownerDocument);
     ASSERT(node != m_ownerDocument);
-    ASSERT(node->parentNode());
+
+    // FIXME: Once DOMNodeRemovedFromDocument mutation event removed, we
+    // should change following if-statement to ASSERT(!node->parentNode).
+    if (!node->parentNode())
+        return;
     boundaryNodeWillBeRemoved(m_start, node);
     boundaryNodeWillBeRemoved(m_end, node);
 }