Chromium Code Reviews| 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..e55383051cffd4f329f5645235c580f4a4e93cd9 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 current node's opener to the |
|
Charlie Reis
2015/08/06 17:35:06
nit: s/current/given/
alexmos
2015/08/06 17:42:57
Done.
|
| +// 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 |