Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / frame_host / frame_tree.cc
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 "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/frame_host/render_frame_proxy_host.h"
18 #include "content/browser/renderer_host/render_view_host_factory.h"
19 #include "content/browser/renderer_host/render_view_host_impl.h"
20 #include "content/public/browser/browser_thread.h"
21
22 namespace content {
23
24 namespace {
25
26 // This is a global map between frame_tree_node_ids and pointer to
27 // FrameTreeNodes.
28 typedef base::hash_map<int64, FrameTreeNode*> FrameTreeNodeIDMap;
29
30 base::LazyInstance<FrameTreeNodeIDMap> g_frame_tree_node_id_map =
31     LAZY_INSTANCE_INITIALIZER;
32
33 // Used with FrameTree::ForEach() to search for the FrameTreeNode
34 // corresponding to |frame_tree_node_id| whithin a specific FrameTree.
35 bool FrameTreeNodeForId(int64 frame_tree_node_id,
36                         FrameTreeNode** out_node,
37                         FrameTreeNode* node) {
38   if (node->frame_tree_node_id() == frame_tree_node_id) {
39     *out_node = node;
40     // Terminate iteration once the node has been found.
41     return false;
42   }
43   return true;
44 }
45
46 // Iterate over the FrameTree to reset any node affected by the loss of the
47 // given RenderViewHost's process.
48 bool ResetNodesForNewProcess(RenderViewHost* render_view_host,
49                              FrameTreeNode* node) {
50   if (render_view_host == node->current_frame_host()->render_view_host())
51     node->ResetForNewProcess();
52   return true;
53 }
54
55 bool CreateProxyForSiteInstance(FrameTreeNode* source_node,
56                                 const scoped_refptr<SiteInstance>& instance,
57                                 FrameTreeNode* node) {
58   // Skip the node that initiated the creation.
59   if (source_node == node)
60     return true;
61
62   node->render_manager()->CreateRenderFrameProxy(instance.get());
63   return true;
64 }
65
66 }  // namespace
67
68 FrameTree::FrameTree(Navigator* navigator,
69                      RenderFrameHostDelegate* render_frame_delegate,
70                      RenderViewHostDelegate* render_view_delegate,
71                      RenderWidgetHostDelegate* render_widget_delegate,
72                      RenderFrameHostManager::Delegate* manager_delegate)
73     : render_frame_delegate_(render_frame_delegate),
74       render_view_delegate_(render_view_delegate),
75       render_widget_delegate_(render_widget_delegate),
76       manager_delegate_(manager_delegate),
77       root_(new FrameTreeNode(this,
78                               navigator,
79                               render_frame_delegate,
80                               render_view_delegate,
81                               render_widget_delegate,
82                               manager_delegate,
83                               std::string())),
84       focused_frame_tree_node_id_(-1) {
85     std::pair<FrameTreeNodeIDMap::iterator, bool> result =
86         g_frame_tree_node_id_map.Get().insert(
87             std::make_pair(root_->frame_tree_node_id(), root_.get()));
88     CHECK(result.second);
89 }
90
91 FrameTree::~FrameTree() {
92   g_frame_tree_node_id_map.Get().erase(root_->frame_tree_node_id());
93 }
94
95 // static
96 FrameTreeNode* FrameTree::GloballyFindByID(int64 frame_tree_node_id) {
97   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
98   FrameTreeNodeIDMap* nodes = g_frame_tree_node_id_map.Pointer();
99   FrameTreeNodeIDMap::iterator it = nodes->find(frame_tree_node_id);
100   return it == nodes->end() ? NULL : it->second;
101 }
102
103 FrameTreeNode* FrameTree::FindByID(int64 frame_tree_node_id) {
104   FrameTreeNode* node = NULL;
105   ForEach(base::Bind(&FrameTreeNodeForId, frame_tree_node_id, &node));
106   return node;
107 }
108
109 FrameTreeNode* FrameTree::FindByRoutingID(int routing_id, int process_id) {
110   RenderFrameHostImpl* render_frame_host =
111       RenderFrameHostImpl::FromID(process_id, routing_id);
112   if (render_frame_host) {
113     FrameTreeNode* result = render_frame_host->frame_tree_node();
114     if (this == result->frame_tree())
115       return result;
116   }
117
118   RenderFrameProxyHost* render_frame_proxy_host =
119       RenderFrameProxyHost::FromID(process_id, routing_id);
120   if (render_frame_proxy_host) {
121     FrameTreeNode* result = render_frame_proxy_host->frame_tree_node();
122     if (this == result->frame_tree())
123       return result;
124   }
125
126   return NULL;
127 }
128
129 void FrameTree::ForEach(
130     const base::Callback<bool(FrameTreeNode*)>& on_node) const {
131   std::queue<FrameTreeNode*> queue;
132   queue.push(root_.get());
133
134   while (!queue.empty()) {
135     FrameTreeNode* node = queue.front();
136     queue.pop();
137     if (!on_node.Run(node))
138       break;
139
140     for (size_t i = 0; i < node->child_count(); ++i)
141       queue.push(node->child_at(i));
142   }
143 }
144
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();
159 }
160
161 void FrameTree::RemoveFrame(FrameTreeNode* child) {
162   FrameTreeNode* parent = child->parent();
163   if (!parent) {
164     NOTREACHED() << "Unexpected RemoveFrame call for main frame.";
165     return;
166   }
167
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);
172   }
173   g_frame_tree_node_id_map.Get().erase(child->frame_tree_node_id());
174   parent->RemoveChild(child);
175 }
176
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);
192     }
193   }
194
195   scoped_refptr<SiteInstance> instance(site_instance);
196   ForEach(base::Bind(&CreateProxyForSiteInstance, source, instance));
197 }
198
199 void FrameTree::ResetForMainFrameSwap() {
200   root_->ResetForNewProcess();
201   focused_frame_tree_node_id_ = -1;
202 }
203
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));
212 }
213
214 RenderFrameHostImpl* FrameTree::GetMainFrame() const {
215   return root_->current_frame_host();
216 }
217
218 FrameTreeNode* FrameTree::GetFocusedFrame() {
219   return FindByID(focused_frame_tree_node_id_);
220 }
221
222 void FrameTree::SetFocusedFrame(FrameTreeNode* node) {
223   focused_frame_tree_node_id_ = node->frame_tree_node_id();
224 }
225
226 void FrameTree::SetFrameRemoveListener(
227     const base::Callback<void(RenderFrameHost*)>& on_frame_removed) {
228   on_frame_removed_ = on_frame_removed;
229 }
230
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;
251     }
252   }
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));
261
262   render_view_host_map_[site_instance->GetId()] = rvh;
263   return rvh;
264 }
265
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;
273 }
274
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());
282
283   iter->second->increment_ref_count();
284 }
285
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);
302     }
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);
324       }
325       break;
326     }
327     CHECK(render_view_host_found);
328   }
329 }
330
331 }  // namespace content