diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/dom/ContainerNodeAlgorithms.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/dom/ContainerNodeAlgorithms.cpp')
-rw-r--r-- | Source/WebCore/dom/ContainerNodeAlgorithms.cpp | 211 |
1 files changed, 172 insertions, 39 deletions
diff --git a/Source/WebCore/dom/ContainerNodeAlgorithms.cpp b/Source/WebCore/dom/ContainerNodeAlgorithms.cpp index 9750df147..2958ec28f 100644 --- a/Source/WebCore/dom/ContainerNodeAlgorithms.cpp +++ b/Source/WebCore/dom/ContainerNodeAlgorithms.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * Copyright (C) 2012 Google Inc. All rights reserved. @@ -26,75 +26,204 @@ #include "config.h" #include "ContainerNodeAlgorithms.h" +#include "HTMLFrameOwnerElement.h" +#include "HTMLTextAreaElement.h" +#include "InspectorInstrumentation.h" +#include "NoEventDispatchAssertion.h" +#include "ShadowRoot.h" namespace WebCore { -void ChildNodeInsertionNotifier::notifyDescendantInsertedIntoDocument(ContainerNode& node) +static void notifyNodeInsertedIntoTree(ContainerNode& insertionPoint, ContainerNode&, NodeVector& postInsertionNotificationTargets); +static void notifyNodeInsertedIntoDocument(ContainerNode& insertionPoint, Node&, NodeVector& postInsertionNotificationTargets); +static void notifyNodeRemovedFromTree(ContainerNode& insertionPoint, ContainerNode&); +static void notifyNodeRemovedFromDocument(ContainerNode& insertionPoint, Node&); + +static void notifyDescendantInsertedIntoDocument(ContainerNode& insertionPoint, ContainerNode& node, NodeVector& postInsertionNotificationTargets) { ChildNodesLazySnapshot snapshot(node); while (RefPtr<Node> child = snapshot.nextNode()) { // If we have been removed from the document during this loop, then // we don't want to tell the rest of our children that they've been // inserted into the document because they haven't. - if (node.inDocument() && child->parentNode() == &node) - notifyNodeInsertedIntoDocument(*child.get()); + if (node.isConnected() && child->parentNode() == &node) + notifyNodeInsertedIntoDocument(insertionPoint, *child, postInsertionNotificationTargets); } - if (!node.isElementNode()) + if (!is<Element>(node)) return; - if (RefPtr<ShadowRoot> root = toElement(node).shadowRoot()) { - if (node.inDocument() && root->hostElement() == &node) - notifyNodeInsertedIntoDocument(*root.get()); + if (RefPtr<ShadowRoot> root = downcast<Element>(node).shadowRoot()) { + if (node.isConnected() && root->host() == &node) + notifyNodeInsertedIntoDocument(insertionPoint, *root, postInsertionNotificationTargets); } } -void ChildNodeInsertionNotifier::notifyDescendantInsertedIntoTree(ContainerNode& node) +static void notifyDescendantInsertedIntoTree(ContainerNode& insertionPoint, ContainerNode& node, NodeVector& postInsertionNotificationTargets) { for (Node* child = node.firstChild(); child; child = child->nextSibling()) { - if (child->isContainerNode()) - notifyNodeInsertedIntoTree(*toContainerNode(child)); + if (is<ContainerNode>(*child)) + notifyNodeInsertedIntoTree(insertionPoint, downcast<ContainerNode>(*child), postInsertionNotificationTargets); } if (ShadowRoot* root = node.shadowRoot()) - notifyNodeInsertedIntoTree(*root); + notifyNodeInsertedIntoTree(insertionPoint, *root, postInsertionNotificationTargets); +} + +void notifyNodeInsertedIntoDocument(ContainerNode& insertionPoint, Node& node, NodeVector& postInsertionNotificationTargets) +{ + ASSERT(insertionPoint.isConnected()); + if (node.insertedInto(insertionPoint) == Node::InsertionShouldCallFinishedInsertingSubtree) + postInsertionNotificationTargets.append(node); + if (is<ContainerNode>(node)) + notifyDescendantInsertedIntoDocument(insertionPoint, downcast<ContainerNode>(node), postInsertionNotificationTargets); } -void ChildNodeRemovalNotifier::notifyDescendantRemovedFromDocument(ContainerNode& node) +void notifyNodeInsertedIntoTree(ContainerNode& insertionPoint, ContainerNode& node, NodeVector& postInsertionNotificationTargets) { + NoEventDispatchAssertion assertNoEventDispatch; + ASSERT(!insertionPoint.isConnected()); + + if (node.insertedInto(insertionPoint) == Node::InsertionShouldCallFinishedInsertingSubtree) + postInsertionNotificationTargets.append(node); + notifyDescendantInsertedIntoTree(insertionPoint, node, postInsertionNotificationTargets); +} + +void notifyChildNodeInserted(ContainerNode& insertionPoint, Node& node, NodeVector& postInsertionNotificationTargets) +{ + ASSERT_WITH_SECURITY_IMPLICATION(NoEventDispatchAssertion::isEventDispatchAllowedInSubtree(insertionPoint)); + + InspectorInstrumentation::didInsertDOMNode(node.document(), node); + + Ref<Document> protectDocument(node.document()); + Ref<Node> protectNode(node); + + if (insertionPoint.isConnected()) + notifyNodeInsertedIntoDocument(insertionPoint, node, postInsertionNotificationTargets); + else if (is<ContainerNode>(node)) + notifyNodeInsertedIntoTree(insertionPoint, downcast<ContainerNode>(node), postInsertionNotificationTargets); +} + +void notifyNodeRemovedFromDocument(ContainerNode& insertionPoint, Node& node) +{ + ASSERT(insertionPoint.isConnected()); + node.removedFrom(insertionPoint); + + if (!is<ContainerNode>(node)) + return; ChildNodesLazySnapshot snapshot(node); while (RefPtr<Node> child = snapshot.nextNode()) { // If we have been added to the document during this loop, then we // don't want to tell the rest of our children that they've been // removed from the document because they haven't. - if (!node.inDocument() && child->parentNode() == &node) - notifyNodeRemovedFromDocument(*child.get()); + if (!node.isConnected() && child->parentNode() == &node) + notifyNodeRemovedFromDocument(insertionPoint, *child.get()); } - if (!node.isElementNode()) + if (!is<Element>(node)) return; if (node.document().cssTarget() == &node) - node.document().setCSSTarget(0); + node.document().setCSSTarget(nullptr); - if (RefPtr<ShadowRoot> root = toElement(node).shadowRoot()) { - if (!node.inDocument() && root->hostElement() == &node) - notifyNodeRemovedFromDocument(*root.get()); + if (RefPtr<ShadowRoot> root = downcast<Element>(node).shadowRoot()) { + if (!node.isConnected() && root->host() == &node) + notifyNodeRemovedFromDocument(insertionPoint, *root.get()); } } -void ChildNodeRemovalNotifier::notifyDescendantRemovedFromTree(ContainerNode& node) +void notifyNodeRemovedFromTree(ContainerNode& insertionPoint, ContainerNode& node) { + NoEventDispatchAssertion assertNoEventDispatch; + ASSERT(!insertionPoint.isConnected()); + + node.removedFrom(insertionPoint); + for (Node* child = node.firstChild(); child; child = child->nextSibling()) { - if (child->isContainerNode()) - notifyNodeRemovedFromTree(*toContainerNode(child)); + if (is<ContainerNode>(*child)) + notifyNodeRemovedFromTree(insertionPoint, downcast<ContainerNode>(*child)); } - if (!node.isElementNode()) + if (!is<Element>(node)) return; - if (RefPtr<ShadowRoot> root = toElement(node).shadowRoot()) - notifyNodeRemovedFromTree(*root.get()); + if (RefPtr<ShadowRoot> root = downcast<Element>(node).shadowRoot()) + notifyNodeRemovedFromTree(insertionPoint, *root.get()); +} + +void notifyChildNodeRemoved(ContainerNode& insertionPoint, Node& child) +{ + if (!child.isConnected()) { + if (is<ContainerNode>(child)) + notifyNodeRemovedFromTree(insertionPoint, downcast<ContainerNode>(child)); + return; + } + notifyNodeRemovedFromDocument(insertionPoint, child); +} + +void addChildNodesToDeletionQueue(Node*& head, Node*& tail, ContainerNode& container) +{ + // We have to tell all children that their parent has died. + Node* next = nullptr; + for (auto* node = container.firstChild(); node; node = next) { + ASSERT(!node->m_deletionHasBegun); + + next = node->nextSibling(); + node->setNextSibling(nullptr); + node->setParentNode(nullptr); + container.setFirstChild(next); + if (next) + next->setPreviousSibling(nullptr); + + if (!node->refCount()) { +#ifndef NDEBUG + node->m_deletionHasBegun = true; +#endif + // Add the node to the list of nodes to be deleted. + // Reuse the nextSibling pointer for this purpose. + if (tail) + tail->setNextSibling(node); + else + head = node; + + tail = node; + } else { + Ref<Node> protect(*node); // removedFromDocument may remove remove all references to this node. + if (Document* containerDocument = container.ownerDocument()) + containerDocument->adoptIfNeeded(*node); + if (node->isInTreeScope()) + notifyChildNodeRemoved(container, *node); + } + } + + container.setLastChild(nullptr); +} + +void removeDetachedChildrenInContainer(ContainerNode& container) +{ + // List of nodes to be deleted. + Node* head = nullptr; + Node* tail = nullptr; + + addChildNodesToDeletionQueue(head, tail, container); + + Node* node; + Node* next; + while ((node = head)) { + ASSERT(node->m_deletionHasBegun); + + next = node->nextSibling(); + node->setNextSibling(nullptr); + + head = next; + if (!next) + tail = nullptr; + + if (is<ContainerNode>(*node)) + addChildNodesToDeletionQueue(head, tail, downcast<ContainerNode>(*node)); + + delete node; + } } #ifndef NDEBUG @@ -102,11 +231,11 @@ static unsigned assertConnectedSubrameCountIsConsistent(ContainerNode& node) { unsigned count = 0; - if (node.isElementNode()) { - if (node.isFrameOwnerElement() && toHTMLFrameOwnerElement(node).contentFrame()) - count++; + if (is<Element>(node)) { + if (is<HTMLFrameOwnerElement>(node) && downcast<HTMLFrameOwnerElement>(node).contentFrame()) + ++count; - if (ShadowRoot* root = toElement(node).shadowRoot()) + if (ShadowRoot* root = downcast<Element>(node).shadowRoot()) count += assertConnectedSubrameCountIsConsistent(*root); } @@ -138,8 +267,8 @@ static void collectFrameOwners(Vector<Ref<HTMLFrameOwnerElement>>& frameOwners, continue; } - if (element.isHTMLElement() && element.isFrameOwnerElement()) - frameOwners.append(toHTMLFrameOwnerElement(element)); + if (is<HTMLFrameOwnerElement>(element)) + frameOwners.append(downcast<HTMLFrameOwnerElement>(element)); if (ShadowRoot* shadowRoot = element.shadowRoot()) collectFrameOwners(frameOwners, *shadowRoot); @@ -157,22 +286,26 @@ void disconnectSubframes(ContainerNode& root, SubframeDisconnectPolicy policy) Vector<Ref<HTMLFrameOwnerElement>> frameOwners; if (policy == RootAndDescendants) { - if (root.isHTMLElement() && root.isFrameOwnerElement()) - frameOwners.append(toHTMLFrameOwnerElement(root)); + if (is<HTMLFrameOwnerElement>(root)) + frameOwners.append(downcast<HTMLFrameOwnerElement>(root)); } collectFrameOwners(frameOwners, root); + if (auto* shadowRoot = root.shadowRoot()) + collectFrameOwners(frameOwners, *shadowRoot); + // Must disable frame loading in the subtree so an unload handler cannot // insert more frames and create loaded frames in detached subtrees. - SubframeLoadingDisabler disabler(root); + SubframeLoadingDisabler disabler(&root); - for (unsigned i = 0; i < frameOwners.size(); ++i) { - auto& owner = frameOwners[i].get(); + bool isFirst = true; + for (auto& owner : frameOwners) { // Don't need to traverse up the tree for the first owner since no // script could have moved it. - if (!i || root.containsIncludingShadowDOM(&owner)) - owner.disconnectContentFrame(); + if (isFirst || root.containsIncludingShadowDOM(&owner.get())) + owner.get().disconnectContentFrame(); + isFirst = false; } } |