| Index: content/browser/frame_host/render_frame_host_manager.cc
|
| diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
|
| index 50c8a599a34f0e5aab5f8bab5697b8daba1f02e1..140bf3f096c2bc896146e3b036d0f55670531710 100644
|
| --- a/content/browser/frame_host/render_frame_host_manager.cc
|
| +++ b/content/browser/frame_host/render_frame_host_manager.cc
|
| @@ -47,6 +47,44 @@
|
|
|
| namespace content {
|
|
|
| +namespace {
|
| +
|
| +// Helper function to add the FrameTree of the given node's opener to the list
|
| +// of |opener_trees|, if it doesn't exist there already. |visited_index|
|
| +// indicates which FrameTrees in |opener_trees| have already been visited
|
| +// (i.e., those at indices less than |visited_index|). |nodes_with_back_links|
|
| +// collects FrameTreeNodes with openers in FrameTrees that have already been
|
| +// visited (such as those with cycles). This function is intended to be used
|
| +// with FrameTree::ForEach, so it always returns true to visit all nodes in the
|
| +// tree.
|
| +bool OpenerForFrameTreeNode(
|
| + size_t visited_index,
|
| + std::vector<FrameTree*>* opener_trees,
|
| + base::hash_set<FrameTreeNode*>* nodes_with_back_links,
|
| + FrameTreeNode* node) {
|
| + if (!node->opener())
|
| + return true;
|
| +
|
| + FrameTree* opener_tree = node->opener()->frame_tree();
|
| +
|
| + const auto& existing_tree_it =
|
| + std::find(opener_trees->begin(), opener_trees->end(), opener_tree);
|
| + if (existing_tree_it == opener_trees->end()) {
|
| + // This is a new opener tree that we will need to process.
|
| + opener_trees->push_back(opener_tree);
|
| + } else {
|
| + // If this tree is already on our processing list *and* we have visited it,
|
| + // then this node's opener is a back link. This means the node will need
|
| + // special treatment to process its opener.
|
| + size_t position = std::distance(opener_trees->begin(), existing_tree_it);
|
| + if (position < visited_index)
|
| + nodes_with_back_links->insert(node);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| // A helper class to hold all frame proxies and register as a
|
| // RenderProcessHostObserver for them.
|
| class RenderFrameHostManager::RenderFrameProxyHostMap
|
| @@ -2398,22 +2436,55 @@ void RenderFrameHostManager::CreateOpenerProxiesIfNeeded(
|
| if (!opener)
|
| return;
|
|
|
| + // TODO(alexmos): This should process all openers in the current frame tree,
|
| + // not just current node's opener.
|
| +
|
| // Create proxies for the opener chain.
|
| opener->render_manager()->CreateOpenerProxies(instance);
|
| }
|
|
|
| +void RenderFrameHostManager::CollectOpenerFrameTrees(
|
| + std::vector<FrameTree*>* opener_frame_trees,
|
| + base::hash_set<FrameTreeNode*>* nodes_with_back_links) {
|
| + CHECK(opener_frame_trees);
|
| + opener_frame_trees->push_back(frame_tree_node_->frame_tree());
|
| +
|
| + size_t visited_index = 0;
|
| + while (visited_index < opener_frame_trees->size()) {
|
| + FrameTree* frame_tree = (*opener_frame_trees)[visited_index];
|
| + visited_index++;
|
| + frame_tree->ForEach(base::Bind(&OpenerForFrameTreeNode, visited_index,
|
| + opener_frame_trees, nodes_with_back_links));
|
| + }
|
| +}
|
| +
|
| void RenderFrameHostManager::CreateOpenerProxies(SiteInstance* instance) {
|
| - // If this tab has an opener, recursively create proxies for the nodes on its
|
| - // frame tree.
|
| - // TODO(alexmos): Once we allow frame openers to be updated (which can happen
|
| - // via window.open(url, "target_frame")), this will need to be resilient to
|
| - // cycles. It will also need to handle tabs that have multiple openers (e.g.,
|
| - // main frame and subframe could have different openers, each of which must
|
| - // be traversed).
|
| - FrameTreeNode* opener = frame_tree_node_->opener();
|
| - if (opener)
|
| - opener->render_manager()->CreateOpenerProxies(instance);
|
| + std::vector<FrameTree*> opener_frame_trees;
|
| + base::hash_set<FrameTreeNode*> nodes_with_back_links;
|
| +
|
| + CollectOpenerFrameTrees(&opener_frame_trees, &nodes_with_back_links);
|
|
|
| + // Create opener proxies for frame trees, processing furthest openers from
|
| + // this node first and this node last. In the common case without cycles,
|
| + // this will ensure that each tree's openers are created before the tree's
|
| + // nodes need to reference them.
|
| + for (int i = opener_frame_trees.size() - 1; i >= 0; i--) {
|
| + opener_frame_trees[i]
|
| + ->root()
|
| + ->render_manager()
|
| + ->CreateOpenerProxiesForFrameTree(instance);
|
| + }
|
| +
|
| + // TODO(alexmos): Set openers for nodes in |nodes_with_back_links| in a
|
| + // second pass. The proxies created at these FrameTreeNodes in
|
| + // CreateOpenerProxiesForFrameTree won't have their opener routing ID
|
| + // available when created due to cycles or back links in the opener chain.
|
| + // They must have their openers updated as a separate step after proxy
|
| + // creation.
|
| +}
|
| +
|
| +void RenderFrameHostManager::CreateOpenerProxiesForFrameTree(
|
| + SiteInstance* instance) {
|
| // If any of the RenderViewHosts (current, pending, or swapped out) for this
|
| // FrameTree has the same SiteInstance, then we can return early, since
|
| // proxies for other nodes in the tree should also exist (when in
|
|
|