Notify nodes removal to Range/Selection after dispatching blur and mutation event

This patch changes notifying nodes removal to Range/Selection after dispatching blur and mutation event. In willRemoveChildren(), like willRemoveChild(); r115686 did same change, although it didn't change willRemoveChildren().

The issue 295010, use-after-free, is caused by setting removed node to Selection in mutation event handler.

BUG=295010
TEST=LayoutTests/fast/dom/Range/range-created-during-remove-children.html, LayoutTests/editing/selection/selection-change-in-mutation-event-by-remove-children.html, LayoutTests/editing/selection/selection-change-in-blur-event-by-remove-children.html
R=tkent@chromium.org

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

git-svn-id: svn://svn.chromium.org/blink/trunk@159007 bbb929c8-8fbe-4397-9dbb-9b2b20218538
void ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& es)
{
    ASSERT(refCount() || parentOrShadowHostNode());

    RefPtr<Node> protect(this);

    if (oldChild == newChild) // nothing to do
        return;

    if (!oldChild) {
        es.throwUninformativeAndGenericDOMException(NotFoundError);
        return;
    }

    if (!checkReplaceChild(this, newChild.get(), oldChild, es))
        return;

    if (oldChild->parentNode() != this) {
        es.throwUninformativeAndGenericDOMException(NotFoundError);
        return;
    }

    ChildListMutationScope mutation(this);

    RefPtr<Node> next = oldChild->nextSibling();

    RefPtr<Node> removedChild = oldChild;
    removeChild(oldChild, es);
    if (es.hadException())
        return;

    if (next && (next->previousSibling() == newChild || next == newChild)) // nothing to do
        return;

    if (!checkReplaceChild(this, newChild.get(), oldChild, es))
        return;

    NodeVector targets;
    collectChildrenAndRemoveFromOldParent(newChild.get(), targets, es);
    if (es.hadException())
        return;

    if (!checkReplaceChild(this, newChild.get(), oldChild, es))
        return;

    InspectorInstrumentation::willInsertDOMNode(&document(), this);

    for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
        Node* child = it->get();

        if (next && next->parentNode() != this)
            break;
        if (child->parentNode())
            break;

        treeScope().adoptIfNeeded(child);

        {
            NoEventDispatchAssertion assertNoEventDispatch;
            if (next)
                insertBeforeCommon(next.get(), child);
            else
                appendChildToContainer(child, this);
        }

        updateTreeAfterInsertion(this, child);
    }

    dispatchSubtreeModifiedEvent();
}

void ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& es)
{
    ASSERT(refCount() || parentOrShadowHostNode());

    RefPtr<Node> protect(this);

    if (oldChild == newChild) // nothing to do
        return;

    if (!oldChild) {
        es.throwUninformativeAndGenericDOMException(NotFoundError);
        return;
    }

    if (!checkReplaceChild(this, newChild.get(), oldChild, es))
        return;

    if (oldChild->parentNode() != this) {
        es.throwUninformativeAndGenericDOMException(NotFoundError);
        return;
    }

    ChildListMutationScope mutation(this);

    RefPtr<Node> next = oldChild->nextSibling();

    RefPtr<Node> removedChild = oldChild;
    removeChild(oldChild, es);
    if (es.hadException())
        return;

    if (next && (next->previousSibling() == newChild || next == newChild)) // nothing to do
        return;

    if (!checkReplaceChild(this, newChild.get(), oldChild, es))
        return;

    NodeVector targets;
    collectChildrenAndRemoveFromOldParent(newChild.get(), targets, es);
    if (es.hadException())
        return;

    if (!checkReplaceChild(this, newChild.get(), oldChild, es))
        return;

    InspectorInstrumentation::willInsertDOMNode(&document(), this);

    for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
        Node* child = it->get();

        if (next && next->parentNode() != this)
            break;
        if (child->parentNode())
            break;

        treeScope().adoptIfNeeded(child);

        {
            NoEventDispatchAssertion assertNoEventDispatch;
            if (next)
                insertBeforeCommon(next.get(), child);
            else
                appendChildToContainer(child, this);
        }

        updateTreeAfterInsertion(this, child);
    }

    dispatchSubtreeModifiedEvent();
}
