blob: 972e1442504cc0432f1df1f2d56f699b93d1ec23 [file] [log] [blame]
// 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 "third_party/blink/renderer/core/dom/child_frame_disconnector.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
namespace blink {
#if DCHECK_IS_ON()
static unsigned CheckConnectedSubframeCountIsConsistent(Node&);
#endif
void ChildFrameDisconnector::Disconnect(DisconnectPolicy policy) {
#if DCHECK_IS_ON()
CheckConnectedSubframeCountIsConsistent(Root());
#endif
if (!Root().ConnectedSubframeCount())
return;
if (policy == kRootAndDescendants) {
CollectFrameOwners(Root());
} else {
for (Node* child = Root().firstChild(); child; child = child->nextSibling())
CollectFrameOwners(*child);
}
DisconnectCollectedFrameOwners();
}
void ChildFrameDisconnector::CollectFrameOwners(Node& root) {
if (!root.ConnectedSubframeCount())
return;
if (root.IsHTMLElement() && root.IsFrameOwnerElement())
frame_owners_.push_back(&ToHTMLFrameOwnerElement(root));
for (Node* child = root.firstChild(); child; child = child->nextSibling())
CollectFrameOwners(*child);
if (ShadowRoot* shadow_root = root.GetShadowRoot())
CollectFrameOwners(*shadow_root);
}
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(Root());
for (unsigned i = 0; i < frame_owners_.size(); ++i) {
HTMLFrameOwnerElement* owner = frame_owners_[i].Get();
// Don't need to traverse up the tree for the first owner since no
// script could have moved it.
if (!i || Root().IsShadowIncludingInclusiveAncestorOf(owner))
owner->DisconnectContentFrame();
}
}
#if DCHECK_IS_ON()
static unsigned CheckConnectedSubframeCountIsConsistent(Node& node) {
unsigned count = 0;
if (node.IsElementNode()) {
if (node.IsFrameOwnerElement() &&
ToHTMLFrameOwnerElement(node).ContentFrame())
count++;
if (ShadowRoot* root = ToElement(node).GetShadowRoot())
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.
DCHECK_GE(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.
DCHECK_EQ(node.ConnectedSubframeCount(), count);
return count;
}
#endif
} // namespace blink