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..4e5cf7be7cceaad710f46060a3e95f572405bb75 100644 | 
| --- a/content/browser/frame_host/render_frame_host_manager.cc | 
| +++ b/content/browser/frame_host/render_frame_host_manager.cc | 
| @@ -169,6 +169,43 @@ bool RenderFrameHostManager::ClearRFHsPendingShutdown(FrameTreeNode* node) { | 
| return true; | 
| } | 
| +namespace { | 
| 
 
Charlie Reis
2015/08/05 23:59:09
Nit: This should go above the RFHM:: stuff above.
 
alexmos
2015/08/06 17:05:39
Done.
 
 | 
| + | 
| +// Helper function to add the FrameTree of the current node's opener | 
| 
 
Charlie Reis
2015/08/05 23:59:09
s/current/given/
 
alexmos
2015/08/06 17:05:39
Done.
 
 | 
| +// 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 (those at indexes less than |visited_index|). | 
| 
 
Charlie Reis
2015/08/05 23:59:09
nit: (i.e., those at indices...
 
alexmos
2015/08/06 17:05:39
Done.
 
 | 
| +// |nodes_with_back_links|, if not null, collects FrameTreeNodes with openers | 
| 
 
Charlie Reis
2015/08/05 23:59:09
Why would it be null?  I don't see a case where th
 
alexmos
2015/08/06 17:05:39
Removed from description and the if statement belo
 
 | 
| +// that point to FrameTrees that have already been visited (such as those with | 
| 
 
Charlie Reis
2015/08/05 23:59:09
nit: with openers in FrameTrees that...
 
alexmos
2015/08/06 17:05:39
Done.
 
 | 
| +// cycles). | 
| +bool OpenerForFrameTreeNode( | 
| 
 
Charlie Reis
2015/08/05 23:59:09
Does this need to return a bool?  Looks like it al
 
alexmos
2015/08/06 17:05:39
Done.  Yes, it's returning true just so it visits
 
 | 
| + size_t visited_index, | 
| + std::vector<FrameTree*>* opener_trees, | 
| + base::hash_set<FrameTreeNode*>* nodes_with_back_links, | 
| + FrameTreeNode* node) { | 
| 
 
Charlie Reis
2015/08/05 23:59:09
nit: Let's list |node| first, since it's the main
 
alexmos
2015/08/06 17:05:39
Hmm, I can't do that given how FrameTree::ForEach
 
Charlie Reis
2015/08/06 17:35:06
Acknowledged.
 
 | 
| + 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 (nodes_with_back_links) { | 
| + // 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 | 
| + | 
| RenderFrameHostManager::RenderFrameHostManager( | 
| FrameTreeNode* frame_tree_node, | 
| RenderFrameHostDelegate* render_frame_delegate, | 
| @@ -2398,22 +2435,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. | 
| 
 
alexmos
2015/08/05 17:45:05
I noticed that this actually has a bug today: if A
 
Charlie Reis
2015/08/05 23:59:09
Nice catch.  Yes, a separate CL is fine, either be
 
alexmos
2015/08/06 17:05:39
OK, will do in a later CL.
 
 | 
| + | 
| // 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 |