1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "core/dom/ChildFrameDisconnector.h"
8 #include "core/dom/shadow/ElementShadow.h"
9 #include "core/dom/shadow/ShadowRoot.h"
10 #include "core/html/HTMLFrameOwnerElement.h"
11 #include "wtf/Assertions.h"
16 static unsigned checkConnectedSubframeCountIsConsistent(Node&);
19 void ChildFrameDisconnector::disconnect(DisconnectPolicy policy)
22 checkConnectedSubframeCountIsConsistent(root());
25 if (!root().connectedSubframeCount())
28 if (policy == RootAndDescendants) {
29 collectFrameOwners(root());
31 for (Node* child = root().firstChild(); child; child = child->nextSibling())
32 collectFrameOwners(*child);
35 disconnectCollectedFrameOwners();
38 void ChildFrameDisconnector::collectFrameOwners(Node& root)
40 if (!root.connectedSubframeCount())
43 if (root.isHTMLElement() && root.isFrameOwnerElement())
44 m_frameOwners.append(&toHTMLFrameOwnerElement(root));
46 for (Node* child = root.firstChild(); child; child = child->nextSibling())
47 collectFrameOwners(*child);
49 ElementShadow* shadow = root.isElementNode() ? toElement(root).shadow() : 0;
51 collectFrameOwners(*shadow);
54 void ChildFrameDisconnector::disconnectCollectedFrameOwners()
56 // Must disable frame loading in the subtree so an unload handler cannot
57 // insert more frames and create loaded frames in detached subtrees.
58 SubframeLoadingDisabler disabler(root());
60 for (unsigned i = 0; i < m_frameOwners.size(); ++i) {
61 HTMLFrameOwnerElement* owner = m_frameOwners[i].get();
62 // Don't need to traverse up the tree for the first owner since no
63 // script could have moved it.
64 if (!i || root().containsIncludingShadowDOM(owner))
65 owner->disconnectContentFrame();
69 void ChildFrameDisconnector::collectFrameOwners(ElementShadow& shadow)
71 for (ShadowRoot* root = shadow.youngestShadowRoot(); root; root = root->olderShadowRoot())
72 collectFrameOwners(*root);
76 static unsigned checkConnectedSubframeCountIsConsistent(Node& node)
80 if (node.isElementNode()) {
81 if (node.isFrameOwnerElement() && toHTMLFrameOwnerElement(node).contentFrame())
84 if (ElementShadow* shadow = toElement(node).shadow()) {
85 for (ShadowRoot* root = shadow->youngestShadowRoot(); root; root = root->olderShadowRoot())
86 count += checkConnectedSubframeCountIsConsistent(*root);
90 for (Node* child = node.firstChild(); child; child = child->nextSibling())
91 count += checkConnectedSubframeCountIsConsistent(*child);
93 // If we undercount there's possibly a security bug since we'd leave frames
94 // in subtrees outside the document.
95 ASSERT(node.connectedSubframeCount() >= count);
97 // If we overcount it's safe, but not optimal because it means we'll traverse
98 // through the document in ChildFrameDisconnector looking for frames that have
99 // already been disconnected.
100 ASSERT(node.connectedSubframeCount() == count);