ContainerNodeAlgorithms.cpp [plain text]
#include "config.h"
#include "ContainerNodeAlgorithms.h"
namespace WebCore {
void ChildNodeInsertionNotifier::notifyDescendantInsertedIntoDocument(ContainerNode& node, NodeVector& postInsertionNotificationTargets)
{
ChildNodesLazySnapshot snapshot(node);
while (RefPtr<Node> child = snapshot.nextNode()) {
if (node.inDocument() && child->parentNode() == &node)
notifyNodeInsertedIntoDocument(*child, postInsertionNotificationTargets);
}
if (!is<Element>(node))
return;
if (RefPtr<ShadowRoot> root = downcast<Element>(node).shadowRoot()) {
if (node.inDocument() && root->hostElement() == &node)
notifyNodeInsertedIntoDocument(*root, postInsertionNotificationTargets);
}
}
void ChildNodeInsertionNotifier::notifyDescendantInsertedIntoTree(ContainerNode& node, NodeVector& postInsertionNotificationTargets)
{
for (Node* child = node.firstChild(); child; child = child->nextSibling()) {
if (is<ContainerNode>(*child))
notifyNodeInsertedIntoTree(downcast<ContainerNode>(*child), postInsertionNotificationTargets);
}
if (ShadowRoot* root = node.shadowRoot())
notifyNodeInsertedIntoTree(*root, postInsertionNotificationTargets);
}
void ChildNodeRemovalNotifier::notifyDescendantRemovedFromDocument(ContainerNode& node)
{
ChildNodesLazySnapshot snapshot(node);
while (RefPtr<Node> child = snapshot.nextNode()) {
if (!node.inDocument() && child->parentNode() == &node)
notifyNodeRemovedFromDocument(*child.get());
}
if (!is<Element>(node))
return;
if (node.document().cssTarget() == &node)
node.document().setCSSTarget(0);
if (RefPtr<ShadowRoot> root = downcast<Element>(node).shadowRoot()) {
if (!node.inDocument() && root->hostElement() == &node)
notifyNodeRemovedFromDocument(*root.get());
}
}
void ChildNodeRemovalNotifier::notifyDescendantRemovedFromTree(ContainerNode& node)
{
for (Node* child = node.firstChild(); child; child = child->nextSibling()) {
if (is<ContainerNode>(*child))
notifyNodeRemovedFromTree(downcast<ContainerNode>(*child));
}
if (!is<Element>(node))
return;
if (RefPtr<ShadowRoot> root = downcast<Element>(node).shadowRoot())
notifyNodeRemovedFromTree(*root.get());
}
#ifndef NDEBUG
static unsigned assertConnectedSubrameCountIsConsistent(ContainerNode& node)
{
unsigned count = 0;
if (is<Element>(node)) {
if (is<HTMLFrameOwnerElement>(node) && downcast<HTMLFrameOwnerElement>(node).contentFrame())
++count;
if (ShadowRoot* root = downcast<Element>(node).shadowRoot())
count += assertConnectedSubrameCountIsConsistent(*root);
}
for (auto& child : childrenOfType<Element>(node))
count += assertConnectedSubrameCountIsConsistent(child);
ASSERT(node.connectedSubframeCount() >= count);
ASSERT(node.connectedSubframeCount() == count);
return count;
}
#endif
static void collectFrameOwners(Vector<Ref<HTMLFrameOwnerElement>>& frameOwners, ContainerNode& root)
{
auto elementDescendants = descendantsOfType<Element>(root);
auto it = elementDescendants.begin();
auto end = elementDescendants.end();
while (it != end) {
Element& element = *it;
if (!element.connectedSubframeCount()) {
it.traverseNextSkippingChildren();
continue;
}
if (is<HTMLFrameOwnerElement>(element))
frameOwners.append(downcast<HTMLFrameOwnerElement>(element));
if (ShadowRoot* shadowRoot = element.shadowRoot())
collectFrameOwners(frameOwners, *shadowRoot);
++it;
}
}
void disconnectSubframes(ContainerNode& root, SubframeDisconnectPolicy policy)
{
#ifndef NDEBUG
assertConnectedSubrameCountIsConsistent(root);
#endif
ASSERT(root.connectedSubframeCount());
Vector<Ref<HTMLFrameOwnerElement>> frameOwners;
if (policy == RootAndDescendants) {
if (is<HTMLFrameOwnerElement>(root))
frameOwners.append(downcast<HTMLFrameOwnerElement>(root));
}
collectFrameOwners(frameOwners, root);
SubframeLoadingDisabler disabler(root);
bool isFirst = true;
for (auto& owner : frameOwners) {
if (isFirst || root.containsIncludingShadowDOM(&owner.get()))
owner.get().disconnectContentFrame();
isFirst = false;
}
}
}