summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/core/dom/ChildFrameDisconnector.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/dom/ChildFrameDisconnector.cpp')
-rw-r--r--chromium/third_party/WebKit/Source/core/dom/ChildFrameDisconnector.cpp106
1 files changed, 106 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/core/dom/ChildFrameDisconnector.cpp b/chromium/third_party/WebKit/Source/core/dom/ChildFrameDisconnector.cpp
new file mode 100644
index 00000000000..555da1cd3b9
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/dom/ChildFrameDisconnector.cpp
@@ -0,0 +1,106 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/dom/ChildFrameDisconnector.h"
+
+#include "core/dom/shadow/ElementShadow.h"
+#include "core/dom/shadow/ShadowRoot.h"
+#include "core/html/HTMLFrameOwnerElement.h"
+#include "wtf/Assertions.h"
+
+namespace WebCore {
+
+#ifndef NDEBUG
+static unsigned checkConnectedSubframeCountIsConsistent(Node&);
+#endif
+
+void ChildFrameDisconnector::disconnect(DisconnectPolicy policy)
+{
+#ifndef NDEBUG
+ checkConnectedSubframeCountIsConsistent(m_root);
+#endif
+
+ if (!m_root.connectedSubframeCount())
+ return;
+
+ if (policy == RootAndDescendants) {
+ collectFrameOwners(m_root);
+ } else {
+ for (Node* child = m_root.firstChild(); child; child = child->nextSibling())
+ collectFrameOwners(*child);
+ }
+
+ disconnectCollectedFrameOwners();
+}
+
+void ChildFrameDisconnector::collectFrameOwners(Node& root)
+{
+ if (!root.connectedSubframeCount())
+ return;
+
+ if (root.isHTMLElement() && root.isFrameOwnerElement())
+ m_frameOwners.append(&toHTMLFrameOwnerElement(root));
+
+ for (Node* child = root.firstChild(); child; child = child->nextSibling())
+ collectFrameOwners(*child);
+
+ ElementShadow* shadow = root.isElementNode() ? toElement(root).shadow() : 0;
+ if (shadow)
+ collectFrameOwners(*shadow);
+}
+
+void ChildFrameDisconnector::disconnectCollectedFrameOwners()
+{
+ // Must disable frame loading in the subtree so an unload handler cannot
+ // insert more frames and create loaded frames in detached subtrees.
+ SubframeLoadingDisabler disabler(m_root);
+
+ for (unsigned i = 0; i < m_frameOwners.size(); ++i) {
+ HTMLFrameOwnerElement* owner = m_frameOwners[i].get();
+ // Don't need to traverse up the tree for the first owner since no
+ // script could have moved it.
+ if (!i || m_root.containsIncludingShadowDOM(owner))
+ owner->disconnectContentFrame();
+ }
+}
+
+void ChildFrameDisconnector::collectFrameOwners(ElementShadow& shadow)
+{
+ for (ShadowRoot* root = shadow.youngestShadowRoot(); root; root = root->olderShadowRoot())
+ collectFrameOwners(*root);
+}
+
+#ifndef NDEBUG
+static unsigned checkConnectedSubframeCountIsConsistent(Node& node)
+{
+ unsigned count = 0;
+
+ if (node.isElementNode()) {
+ if (node.isFrameOwnerElement() && toHTMLFrameOwnerElement(node).contentFrame())
+ count++;
+
+ if (ElementShadow* shadow = toElement(node).shadow()) {
+ for (ShadowRoot* root = shadow->youngestShadowRoot(); root; root = root->olderShadowRoot())
+ count += checkConnectedSubframeCountIsConsistent(*root);
+ }
+ }
+
+ for (Node* child = node.firstChild(); child; child = child->nextSibling())
+ count += checkConnectedSubframeCountIsConsistent(*child);
+
+ // If we undercount there's possibly a security bug since we'd leave frames
+ // in subtrees outside the document.
+ ASSERT(node.connectedSubframeCount() >= count);
+
+ // If we overcount it's safe, but not optimal because it means we'll traverse
+ // through the document in ChildFrameDisconnector looking for frames that have
+ // already been disconnected.
+ ASSERT(node.connectedSubframeCount() == count);
+
+ return count;
+}
+#endif
+
+}