1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/browser/frame_host/frame_tree.h" 6 7 #include <queue> 8 9 #include "base/bind.h" 10 #include "base/callback.h" 11 #include "content/browser/frame_host/frame_tree_node.h" 12 #include "content/browser/frame_host/navigator.h" 13 #include "content/browser/frame_host/render_frame_host_factory.h" 14 #include "content/browser/frame_host/render_frame_host_impl.h" 15 16 namespace content { 17 18 namespace { 19 // Used with FrameTree::ForEach() to search for the FrameTreeNode 20 // corresponding to |frame_tree_node_id|. 21 bool FrameTreeNodeForId(int64 frame_tree_node_id, 22 FrameTreeNode** out_node, 23 FrameTreeNode* node) { 24 if (node->frame_tree_node_id() == frame_tree_node_id) { 25 *out_node = node; 26 // Terminate iteration once the node has been found. 27 return false; 28 } 29 return true; 30 } 31 32 // TODO(creis): Remove this version along with FrameTreeNode::frame_id(). 33 bool FrameTreeNodeForFrameId(int64 frame_id, 34 FrameTreeNode** out_node, 35 FrameTreeNode* node) { 36 if (node->frame_id() == frame_id) { 37 *out_node = node; 38 // Terminate iteration once the node has been found. 39 return false; 40 } 41 return true; 42 } 43 44 } // namespace 45 46 FrameTree::FrameTree(Navigator* navigator, 47 RenderFrameHostDelegate* render_frame_delegate, 48 RenderViewHostDelegate* render_view_delegate, 49 RenderWidgetHostDelegate* render_widget_delegate, 50 RenderFrameHostManager::Delegate* manager_delegate) 51 : render_frame_delegate_(render_frame_delegate), 52 render_view_delegate_(render_view_delegate), 53 render_widget_delegate_(render_widget_delegate), 54 manager_delegate_(manager_delegate), 55 root_(new FrameTreeNode(navigator, 56 render_frame_delegate, 57 render_view_delegate, 58 render_widget_delegate, 59 manager_delegate, 60 FrameTreeNode::kInvalidFrameId, 61 std::string())) { 62 } 63 64 FrameTree::~FrameTree() { 65 } 66 67 FrameTreeNode* FrameTree::FindByID(int64 frame_tree_node_id) { 68 FrameTreeNode* node = NULL; 69 ForEach(base::Bind(&FrameTreeNodeForId, frame_tree_node_id, &node)); 70 return node; 71 } 72 73 void FrameTree::ForEach( 74 const base::Callback<bool(FrameTreeNode*)>& on_node) const { 75 std::queue<FrameTreeNode*> queue; 76 queue.push(root_.get()); 77 78 while (!queue.empty()) { 79 FrameTreeNode* node = queue.front(); 80 queue.pop(); 81 if (!on_node.Run(node)) 82 break; 83 84 for (size_t i = 0; i < node->child_count(); ++i) 85 queue.push(node->child_at(i)); 86 } 87 } 88 89 bool FrameTree::IsFirstNavigationAfterSwap() const { 90 return root_->frame_id() == FrameTreeNode::kInvalidFrameId; 91 } 92 93 void FrameTree::OnFirstNavigationAfterSwap(int main_frame_id) { 94 root_->set_frame_id(main_frame_id); 95 } 96 97 RenderFrameHostImpl* FrameTree::AddFrame(int render_frame_host_id, 98 int64 parent_frame_id, 99 int64 frame_id, 100 const std::string& frame_name) { 101 FrameTreeNode* parent = FindByFrameID(parent_frame_id); 102 // TODO(ajwong): Should the renderer be killed here? Would there be a race on 103 // shutdown that might make this case possible? 104 if (!parent) 105 return NULL; 106 107 scoped_ptr<FrameTreeNode> node(CreateNode( 108 frame_id, frame_name, render_frame_host_id, parent)); 109 RenderFrameHostImpl* render_frame = node->render_frame_host(); 110 parent->AddChild(node.Pass()); 111 return render_frame; 112 } 113 114 void FrameTree::RemoveFrame(RenderFrameHostImpl* render_frame_host, 115 int64 parent_frame_id, 116 int64 frame_id) { 117 // If switches::kSitePerProcess is not specified, then the FrameTree only 118 // contains a node for the root element. However, even in this case 119 // frame detachments need to be broadcast outwards. 120 // 121 // TODO(ajwong): Move this below the |parent| check after the FrameTree is 122 // guaranteed to be correctly populated even without the 123 // switches::kSitePerProcess flag. 124 FrameTreeNode* parent = FindByFrameID(parent_frame_id); 125 FrameTreeNode* child = FindByFrameID(frame_id); 126 if (!on_frame_removed_.is_null()) { 127 on_frame_removed_.Run( 128 render_frame_host->render_view_host(), frame_id); 129 } 130 131 // TODO(ajwong): Should the renderer be killed here? Would there be a race on 132 // shutdown that might make this case possible? 133 if (!parent || !child) 134 return; 135 136 parent->RemoveChild(child); 137 } 138 139 void FrameTree::SetFrameUrl(int64 frame_id, const GURL& url) { 140 FrameTreeNode* node = FindByFrameID(frame_id); 141 // TODO(ajwong): Should the renderer be killed here? Would there be a race on 142 // shutdown that might make this case possible? 143 if (!node) 144 return; 145 146 if (node) 147 node->set_current_url(url); 148 } 149 150 void FrameTree::SwapMainFrame(RenderFrameHostImpl* render_frame_host) { 151 return root_->ResetForMainFrame(render_frame_host); 152 } 153 154 RenderFrameHostImpl* FrameTree::GetMainFrame() const { 155 return root_->render_frame_host(); 156 } 157 158 void FrameTree::SetFrameRemoveListener( 159 const base::Callback<void(RenderViewHostImpl*, int64)>& on_frame_removed) { 160 on_frame_removed_ = on_frame_removed; 161 } 162 163 FrameTreeNode* FrameTree::FindByFrameID(int64 frame_id) { 164 FrameTreeNode* node = NULL; 165 ForEach(base::Bind(&FrameTreeNodeForFrameId, frame_id, &node)); 166 return node; 167 } 168 169 scoped_ptr<FrameTreeNode> FrameTree::CreateNode( 170 int64 frame_id, 171 const std::string& frame_name, 172 int render_frame_host_id, 173 FrameTreeNode* parent_node) { 174 scoped_ptr<FrameTreeNode> frame_tree_node(new FrameTreeNode( 175 parent_node->navigator(), render_frame_delegate_, render_view_delegate_, 176 render_widget_delegate_, manager_delegate_, frame_id, frame_name)); 177 178 scoped_ptr<RenderFrameHostImpl> render_frame_host( 179 RenderFrameHostFactory::Create( 180 parent_node->render_frame_host()->render_view_host(), 181 parent_node->render_frame_host()->delegate(), 182 this, 183 frame_tree_node.get(), 184 render_frame_host_id, 185 false)); 186 187 frame_tree_node->set_render_frame_host(render_frame_host.release(), true); 188 return frame_tree_node.Pass(); 189 } 190 191 } // namespace content 192