Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / frame_host / frame_tree.cc
blobde6c69b59bd06e46c839dbcff6e67ef7012d55b7
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.
5 #include "content/browser/frame_host/frame_tree.h"
7 #include <queue>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/containers/hash_tables.h"
12 #include "base/lazy_instance.h"
13 #include "content/browser/frame_host/frame_tree_node.h"
14 #include "content/browser/frame_host/navigator.h"
15 #include "content/browser/frame_host/render_frame_host_factory.h"
16 #include "content/browser/frame_host/render_frame_host_impl.h"
17 #include "content/browser/renderer_host/render_view_host_factory.h"
18 #include "content/browser/renderer_host/render_view_host_impl.h"
19 #include "content/public/browser/browser_thread.h"
21 namespace content {
23 namespace {
25 // This is a global map between frame_tree_node_ids and pointer to
26 // FrameTreeNodes.
27 typedef base::hash_map<int64, FrameTreeNode*> FrameTreeNodeIDMap;
29 base::LazyInstance<FrameTreeNodeIDMap> g_frame_tree_node_id_map =
30 LAZY_INSTANCE_INITIALIZER;
32 // Used with FrameTree::ForEach() to search for the FrameTreeNode
33 // corresponding to |frame_tree_node_id| whithin a specific FrameTree.
34 bool FrameTreeNodeForId(int64 frame_tree_node_id,
35 FrameTreeNode** out_node,
36 FrameTreeNode* node) {
37 if (node->frame_tree_node_id() == frame_tree_node_id) {
38 *out_node = node;
39 // Terminate iteration once the node has been found.
40 return false;
42 return true;
45 bool FrameTreeNodeForRoutingId(int routing_id,
46 int process_id,
47 FrameTreeNode** out_node,
48 FrameTreeNode* node) {
49 // TODO(creis): Look through the swapped out RFHs as well.
50 if (node->current_frame_host()->GetProcess()->GetID() == process_id &&
51 node->current_frame_host()->GetRoutingID() == routing_id) {
52 *out_node = node;
53 // Terminate iteration once the node has been found.
54 return false;
56 return true;
59 // Iterate over the FrameTree to reset any node affected by the loss of the
60 // given RenderViewHost's process.
61 bool ResetNodesForNewProcess(RenderViewHost* render_view_host,
62 FrameTreeNode* node) {
63 if (render_view_host == node->current_frame_host()->render_view_host())
64 node->ResetForNewProcess();
65 return true;
68 bool CreateProxyForSiteInstance(FrameTreeNode* source_node,
69 const scoped_refptr<SiteInstance>& instance,
70 FrameTreeNode* node) {
71 // Skip the node that initiated the creation.
72 if (source_node == node)
73 return true;
75 node->render_manager()->CreateRenderFrameProxy(instance.get());
76 return true;
79 } // namespace
81 FrameTree::FrameTree(Navigator* navigator,
82 RenderFrameHostDelegate* render_frame_delegate,
83 RenderViewHostDelegate* render_view_delegate,
84 RenderWidgetHostDelegate* render_widget_delegate,
85 RenderFrameHostManager::Delegate* manager_delegate)
86 : render_frame_delegate_(render_frame_delegate),
87 render_view_delegate_(render_view_delegate),
88 render_widget_delegate_(render_widget_delegate),
89 manager_delegate_(manager_delegate),
90 root_(new FrameTreeNode(this,
91 navigator,
92 render_frame_delegate,
93 render_view_delegate,
94 render_widget_delegate,
95 manager_delegate,
96 std::string())),
97 focused_frame_tree_node_id_(-1) {
98 std::pair<FrameTreeNodeIDMap::iterator, bool> result =
99 g_frame_tree_node_id_map.Get().insert(
100 std::make_pair(root_->frame_tree_node_id(), root_.get()));
101 CHECK(result.second);
104 FrameTree::~FrameTree() {
105 g_frame_tree_node_id_map.Get().erase(root_->frame_tree_node_id());
108 // static
109 FrameTreeNode* FrameTree::GloballyFindByID(int64 frame_tree_node_id) {
110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
111 FrameTreeNodeIDMap* nodes = g_frame_tree_node_id_map.Pointer();
112 FrameTreeNodeIDMap::iterator it = nodes->find(frame_tree_node_id);
113 return it == nodes->end() ? NULL : it->second;
116 FrameTreeNode* FrameTree::FindByID(int64 frame_tree_node_id) {
117 FrameTreeNode* node = NULL;
118 ForEach(base::Bind(&FrameTreeNodeForId, frame_tree_node_id, &node));
119 return node;
122 FrameTreeNode* FrameTree::FindByRoutingID(int routing_id, int process_id) {
123 FrameTreeNode* node = NULL;
124 ForEach(
125 base::Bind(&FrameTreeNodeForRoutingId, routing_id, process_id, &node));
126 return node;
129 void FrameTree::ForEach(
130 const base::Callback<bool(FrameTreeNode*)>& on_node) const {
131 std::queue<FrameTreeNode*> queue;
132 queue.push(root_.get());
134 while (!queue.empty()) {
135 FrameTreeNode* node = queue.front();
136 queue.pop();
137 if (!on_node.Run(node))
138 break;
140 for (size_t i = 0; i < node->child_count(); ++i)
141 queue.push(node->child_at(i));
145 RenderFrameHostImpl* FrameTree::AddFrame(FrameTreeNode* parent,
146 int new_routing_id,
147 const std::string& frame_name) {
148 scoped_ptr<FrameTreeNode> node(new FrameTreeNode(
149 this, parent->navigator(), render_frame_delegate_, render_view_delegate_,
150 render_widget_delegate_, manager_delegate_, frame_name));
151 std::pair<FrameTreeNodeIDMap::iterator, bool> result =
152 g_frame_tree_node_id_map.Get().insert(
153 std::make_pair(node->frame_tree_node_id(), node.get()));
154 CHECK(result.second);
155 FrameTreeNode* node_ptr = node.get();
156 // AddChild is what creates the RenderFrameHost.
157 parent->AddChild(node.Pass(), new_routing_id);
158 return node_ptr->current_frame_host();
161 void FrameTree::RemoveFrame(FrameTreeNode* child) {
162 FrameTreeNode* parent = child->parent();
163 if (!parent) {
164 NOTREACHED() << "Unexpected RemoveFrame call for main frame.";
165 return;
168 // Notify observers of the frame removal.
169 RenderFrameHostImpl* render_frame_host = child->current_frame_host();
170 if (!on_frame_removed_.is_null()) {
171 on_frame_removed_.Run(render_frame_host);
173 g_frame_tree_node_id_map.Get().erase(child->frame_tree_node_id());
174 parent->RemoveChild(child);
177 void FrameTree::CreateProxiesForSiteInstance(
178 FrameTreeNode* source,
179 SiteInstance* site_instance) {
180 // Create the swapped out RVH for the new SiteInstance. This will create
181 // a top-level swapped out RFH as well, which will then be wrapped by a
182 // RenderFrameProxyHost.
183 if (!source->IsMainFrame()) {
184 RenderViewHostImpl* render_view_host =
185 source->frame_tree()->GetRenderViewHost(site_instance);
186 if (!render_view_host) {
187 root()->render_manager()->CreateRenderFrame(site_instance,
188 MSG_ROUTING_NONE,
189 true,
190 false,
191 true);
195 scoped_refptr<SiteInstance> instance(site_instance);
196 ForEach(base::Bind(&CreateProxyForSiteInstance, source, instance));
199 void FrameTree::ResetForMainFrameSwap() {
200 root_->ResetForNewProcess();
201 focused_frame_tree_node_id_ = -1;
204 void FrameTree::RenderProcessGone(RenderViewHost* render_view_host) {
205 // Walk the full tree looking for nodes that may be affected. Once a frame
206 // crashes, all of its child FrameTreeNodes go away.
207 // Note that the helper function may call ResetForNewProcess on a node, which
208 // clears its children before we iterate over them. That's ok, because
209 // ForEach does not add a node's children to the queue until after visiting
210 // the node itself.
211 ForEach(base::Bind(&ResetNodesForNewProcess, render_view_host));
214 RenderFrameHostImpl* FrameTree::GetMainFrame() const {
215 return root_->current_frame_host();
218 FrameTreeNode* FrameTree::GetFocusedFrame() {
219 return FindByID(focused_frame_tree_node_id_);
222 void FrameTree::SetFocusedFrame(FrameTreeNode* node) {
223 focused_frame_tree_node_id_ = node->frame_tree_node_id();
226 void FrameTree::SetFrameRemoveListener(
227 const base::Callback<void(RenderFrameHost*)>& on_frame_removed) {
228 on_frame_removed_ = on_frame_removed;
231 RenderViewHostImpl* FrameTree::CreateRenderViewHost(SiteInstance* site_instance,
232 int routing_id,
233 int main_frame_routing_id,
234 bool swapped_out,
235 bool hidden) {
236 DCHECK(main_frame_routing_id != MSG_ROUTING_NONE);
237 RenderViewHostMap::iterator iter =
238 render_view_host_map_.find(site_instance->GetId());
239 if (iter != render_view_host_map_.end()) {
240 // If a RenderViewHost is pending shutdown for this |site_instance|, put it
241 // in the map of RenderViewHosts pending shutdown. Otherwise return the
242 // existing RenderViewHost for the SiteInstance.
243 if (iter->second->rvh_state() ==
244 RenderViewHostImpl::STATE_PENDING_SHUTDOWN) {
245 render_view_host_pending_shutdown_map_.insert(
246 std::pair<int, RenderViewHostImpl*>(site_instance->GetId(),
247 iter->second));
248 render_view_host_map_.erase(iter);
249 } else {
250 return iter->second;
253 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
254 RenderViewHostFactory::Create(site_instance,
255 render_view_delegate_,
256 render_widget_delegate_,
257 routing_id,
258 main_frame_routing_id,
259 swapped_out,
260 hidden));
262 render_view_host_map_[site_instance->GetId()] = rvh;
263 return rvh;
266 RenderViewHostImpl* FrameTree::GetRenderViewHost(SiteInstance* site_instance) {
267 RenderViewHostMap::iterator iter =
268 render_view_host_map_.find(site_instance->GetId());
269 // TODO(creis): Mirror the frame tree so this check can't fail.
270 if (iter == render_view_host_map_.end())
271 return NULL;
272 return iter->second;
275 void FrameTree::RegisterRenderFrameHost(
276 RenderFrameHostImpl* render_frame_host) {
277 SiteInstance* site_instance =
278 render_frame_host->render_view_host()->GetSiteInstance();
279 RenderViewHostMap::iterator iter =
280 render_view_host_map_.find(site_instance->GetId());
281 CHECK(iter != render_view_host_map_.end());
283 iter->second->increment_ref_count();
286 void FrameTree::UnregisterRenderFrameHost(
287 RenderFrameHostImpl* render_frame_host) {
288 SiteInstance* site_instance =
289 render_frame_host->render_view_host()->GetSiteInstance();
290 int32 site_instance_id = site_instance->GetId();
291 RenderViewHostMap::iterator iter =
292 render_view_host_map_.find(site_instance_id);
293 if (iter != render_view_host_map_.end() &&
294 iter->second == render_frame_host->render_view_host()) {
295 // Decrement the refcount and shutdown the RenderViewHost if no one else is
296 // using it.
297 CHECK_GT(iter->second->ref_count(), 0);
298 iter->second->decrement_ref_count();
299 if (iter->second->ref_count() == 0) {
300 iter->second->Shutdown();
301 render_view_host_map_.erase(iter);
303 } else {
304 // The RenderViewHost should be in the list of RenderViewHosts pending
305 // shutdown.
306 bool render_view_host_found = false;
307 std::pair<RenderViewHostMultiMap::iterator,
308 RenderViewHostMultiMap::iterator> result =
309 render_view_host_pending_shutdown_map_.equal_range(site_instance_id);
310 for (RenderViewHostMultiMap::iterator multi_iter = result.first;
311 multi_iter != result.second;
312 ++multi_iter) {
313 if (multi_iter->second != render_frame_host->render_view_host())
314 continue;
315 render_view_host_found = true;
316 RenderViewHostImpl* rvh = multi_iter->second;
317 // Decrement the refcount and shutdown the RenderViewHost if no one else
318 // is using it.
319 CHECK_GT(rvh->ref_count(), 0);
320 rvh->decrement_ref_count();
321 if (rvh->ref_count() == 0) {
322 rvh->Shutdown();
323 render_view_host_pending_shutdown_map_.erase(multi_iter);
325 break;
327 CHECK(render_view_host_found);
331 } // namespace content