Update To 11.40.268.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     // Ensure that if the frame host is reused for a new RenderFrame, it will
52     // set up the Mojo connection with that frame.
53     node->current_frame_host()->InvalidateMojoConnection();
54     node->ResetForNewProcess();
55   }
56   return true;
57 }
58
59 bool CreateProxyForSiteInstance(const scoped_refptr<SiteInstance>& instance,
60                                 FrameTreeNode* node) {
61   // If a new frame is created in the current SiteInstance, other frames in
62   // that SiteInstance don't need a proxy for the new frame.
63   SiteInstance* current_instance =
64       node->render_manager()->current_frame_host()->GetSiteInstance();
65   if (current_instance != instance.get())
66     node->render_manager()->CreateRenderFrameProxy(instance.get());
67   return true;
68 }
69
70 }  // namespace
71
72 FrameTree::FrameTree(Navigator* navigator,
73                      RenderFrameHostDelegate* render_frame_delegate,
74                      RenderViewHostDelegate* render_view_delegate,
75                      RenderWidgetHostDelegate* render_widget_delegate,
76                      RenderFrameHostManager::Delegate* manager_delegate)
77     : render_frame_delegate_(render_frame_delegate),
78       render_view_delegate_(render_view_delegate),
79       render_widget_delegate_(render_widget_delegate),
80       manager_delegate_(manager_delegate),
81       root_(new FrameTreeNode(this,
82                               navigator,
83                               render_frame_delegate,
84                               render_view_delegate,
85                               render_widget_delegate,
86                               manager_delegate,
87                               std::string())),
88       focused_frame_tree_node_id_(-1) {
89     std::pair<FrameTreeNodeIDMap::iterator, bool> result =
90         g_frame_tree_node_id_map.Get().insert(
91             std::make_pair(root_->frame_tree_node_id(), root_.get()));
92     CHECK(result.second);
93 }
94
95 FrameTree::~FrameTree() {
96   g_frame_tree_node_id_map.Get().erase(root_->frame_tree_node_id());
97 }
98
99 // static
100 FrameTreeNode* FrameTree::GloballyFindByID(int64 frame_tree_node_id) {
101   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
102   FrameTreeNodeIDMap* nodes = g_frame_tree_node_id_map.Pointer();
103   FrameTreeNodeIDMap::iterator it = nodes->find(frame_tree_node_id);
104   return it == nodes->end() ? NULL : it->second;
105 }
106
107 FrameTreeNode* FrameTree::FindByID(int64 frame_tree_node_id) {
108   FrameTreeNode* node = NULL;
109   ForEach(base::Bind(&FrameTreeNodeForId, frame_tree_node_id, &node));
110   return node;
111 }
112
113 FrameTreeNode* FrameTree::FindByRoutingID(int routing_id, int process_id) {
114   RenderFrameHostImpl* render_frame_host =
115       RenderFrameHostImpl::FromID(process_id, routing_id);
116   if (render_frame_host) {
117     FrameTreeNode* result = render_frame_host->frame_tree_node();
118     if (this == result->frame_tree())
119       return result;
120   }
121
122   RenderFrameProxyHost* render_frame_proxy_host =
123       RenderFrameProxyHost::FromID(process_id, routing_id);
124   if (render_frame_proxy_host) {
125     FrameTreeNode* result = render_frame_proxy_host->frame_tree_node();
126     if (this == result->frame_tree())
127       return result;
128   }
129
130   return NULL;
131 }
132
133 void FrameTree::ForEach(
134     const base::Callback<bool(FrameTreeNode*)>& on_node) const {
135   ForEach(on_node, NULL);
136 }
137
138 void FrameTree::ForEach(
139     const base::Callback<bool(FrameTreeNode*)>& on_node,
140     FrameTreeNode* skip_this_subtree) const {
141   std::queue<FrameTreeNode*> queue;
142   queue.push(root_.get());
143
144   while (!queue.empty()) {
145     FrameTreeNode* node = queue.front();
146     queue.pop();
147     if (skip_this_subtree == node)
148       continue;
149
150     if (!on_node.Run(node))
151       break;
152
153     for (size_t i = 0; i < node->child_count(); ++i)
154       queue.push(node->child_at(i));
155   }
156 }
157
158 RenderFrameHostImpl* FrameTree::AddFrame(FrameTreeNode* parent,
159                                          int process_id,
160                                          int new_routing_id,
161                                          const std::string& frame_name) {
162   // A child frame always starts with an initial empty document, which means
163   // it is in the same SiteInstance as the parent frame. Ensure that the process
164   // which requested a child frame to be added is the same as the process of the
165   // parent node.
166   if (parent->current_frame_host()->GetProcess()->GetID() != process_id)
167     return nullptr;
168
169   scoped_ptr<FrameTreeNode> node(new FrameTreeNode(
170       this, parent->navigator(), render_frame_delegate_, render_view_delegate_,
171       render_widget_delegate_, manager_delegate_, frame_name));
172   std::pair<FrameTreeNodeIDMap::iterator, bool> result =
173       g_frame_tree_node_id_map.Get().insert(
174           std::make_pair(node->frame_tree_node_id(), node.get()));
175   CHECK(result.second);
176   FrameTreeNode* node_ptr = node.get();
177   // AddChild is what creates the RenderFrameHost.
178   parent->AddChild(node.Pass(), process_id, new_routing_id);
179   return node_ptr->current_frame_host();
180 }
181
182 void FrameTree::RemoveFrame(FrameTreeNode* child) {
183   FrameTreeNode* parent = child->parent();
184   if (!parent) {
185     NOTREACHED() << "Unexpected RemoveFrame call for main frame.";
186     return;
187   }
188
189   // Notify observers of the frame removal.
190   RenderFrameHostImpl* render_frame_host = child->current_frame_host();
191   if (!on_frame_removed_.is_null()) {
192     on_frame_removed_.Run(render_frame_host);
193   }
194   g_frame_tree_node_id_map.Get().erase(child->frame_tree_node_id());
195   parent->RemoveChild(child);
196 }
197
198 void FrameTree::CreateProxiesForSiteInstance(
199     FrameTreeNode* source,
200     SiteInstance* site_instance) {
201   // Create the swapped out RVH for the new SiteInstance. This will create
202   // a top-level swapped out RFH as well, which will then be wrapped by a
203   // RenderFrameProxyHost.
204   if (!source->IsMainFrame()) {
205     RenderViewHostImpl* render_view_host =
206         source->frame_tree()->GetRenderViewHost(site_instance);
207     if (!render_view_host) {
208       root()->render_manager()->CreateRenderFrame(site_instance,
209                                                   MSG_ROUTING_NONE,
210                                                   true,
211                                                   false,
212                                                   true);
213     }
214   }
215
216   scoped_refptr<SiteInstance> instance(site_instance);
217
218   // Proxies are created in the FrameTree in response to a node navigating to a
219   // new SiteInstance. Since |source|'s navigation will replace the currently
220   // loaded document, the entire subtree under |source| will be removed.
221   ForEach(base::Bind(&CreateProxyForSiteInstance, instance), source);
222 }
223
224 void FrameTree::ResetForMainFrameSwap() {
225   root_->ResetForNewProcess();
226   focused_frame_tree_node_id_ = -1;
227 }
228
229 void FrameTree::RenderProcessGone(RenderViewHost* render_view_host) {
230   // Walk the full tree looking for nodes that may be affected.  Once a frame
231   // crashes, all of its child FrameTreeNodes go away.
232   // Note that the helper function may call ResetForNewProcess on a node, which
233   // clears its children before we iterate over them.  That's ok, because
234   // ForEach does not add a node's children to the queue until after visiting
235   // the node itself.
236   ForEach(base::Bind(&ResetNodesForNewProcess, render_view_host));
237 }
238
239 RenderFrameHostImpl* FrameTree::GetMainFrame() const {
240   return root_->current_frame_host();
241 }
242
243 FrameTreeNode* FrameTree::GetFocusedFrame() {
244   return FindByID(focused_frame_tree_node_id_);
245 }
246
247 void FrameTree::SetFocusedFrame(FrameTreeNode* node) {
248   focused_frame_tree_node_id_ = node->frame_tree_node_id();
249 }
250
251 void FrameTree::SetFrameRemoveListener(
252     const base::Callback<void(RenderFrameHost*)>& on_frame_removed) {
253   on_frame_removed_ = on_frame_removed;
254 }
255
256 RenderViewHostImpl* FrameTree::CreateRenderViewHost(SiteInstance* site_instance,
257                                                     int routing_id,
258                                                     int main_frame_routing_id,
259                                                     bool swapped_out,
260                                                     bool hidden) {
261   DCHECK(main_frame_routing_id != MSG_ROUTING_NONE);
262   RenderViewHostMap::iterator iter =
263       render_view_host_map_.find(site_instance->GetId());
264   if (iter != render_view_host_map_.end()) {
265     // If a RenderViewHost's main frame is pending deletion for this
266     // |site_instance|, put it in the map of RenderViewHosts pending shutdown.
267     // Otherwise return the existing RenderViewHost for the SiteInstance.
268     RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
269         iter->second->GetMainFrame());
270     if (main_frame->frame_tree_node()->render_manager()->IsPendingDeletion(
271             main_frame)) {
272       render_view_host_pending_shutdown_map_.insert(
273           std::pair<int, RenderViewHostImpl*>(site_instance->GetId(),
274                                               iter->second));
275       render_view_host_map_.erase(iter);
276     } else {
277       return iter->second;
278     }
279   }
280   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
281       RenderViewHostFactory::Create(site_instance,
282                                     render_view_delegate_,
283                                     render_widget_delegate_,
284                                     routing_id,
285                                     main_frame_routing_id,
286                                     swapped_out,
287                                     hidden));
288
289   render_view_host_map_[site_instance->GetId()] = rvh;
290   return rvh;
291 }
292
293 RenderViewHostImpl* FrameTree::GetRenderViewHost(SiteInstance* site_instance) {
294   RenderViewHostMap::iterator iter =
295       render_view_host_map_.find(site_instance->GetId());
296   // TODO(creis): Mirror the frame tree so this check can't fail.
297   if (iter == render_view_host_map_.end())
298     return NULL;
299   return iter->second;
300 }
301
302 void FrameTree::RegisterRenderFrameHost(
303     RenderFrameHostImpl* render_frame_host) {
304   SiteInstance* site_instance =
305       render_frame_host->render_view_host()->GetSiteInstance();
306   RenderViewHostMap::iterator iter =
307       render_view_host_map_.find(site_instance->GetId());
308   CHECK(iter != render_view_host_map_.end());
309
310   iter->second->increment_ref_count();
311 }
312
313 void FrameTree::UnregisterRenderFrameHost(
314     RenderFrameHostImpl* render_frame_host) {
315   SiteInstance* site_instance =
316       render_frame_host->render_view_host()->GetSiteInstance();
317   int32 site_instance_id = site_instance->GetId();
318   RenderViewHostMap::iterator iter =
319       render_view_host_map_.find(site_instance_id);
320   if (iter != render_view_host_map_.end() &&
321       iter->second == render_frame_host->render_view_host()) {
322     // Decrement the refcount and shutdown the RenderViewHost if no one else is
323     // using it.
324     CHECK_GT(iter->second->ref_count(), 0);
325     iter->second->decrement_ref_count();
326     if (iter->second->ref_count() == 0) {
327       iter->second->Shutdown();
328       render_view_host_map_.erase(iter);
329     }
330   } else {
331     // The RenderViewHost should be in the list of RenderViewHosts pending
332     // shutdown.
333     bool render_view_host_found = false;
334     std::pair<RenderViewHostMultiMap::iterator,
335               RenderViewHostMultiMap::iterator> result =
336         render_view_host_pending_shutdown_map_.equal_range(site_instance_id);
337     for (RenderViewHostMultiMap::iterator multi_iter = result.first;
338          multi_iter != result.second;
339          ++multi_iter) {
340       if (multi_iter->second != render_frame_host->render_view_host())
341         continue;
342       render_view_host_found = true;
343       RenderViewHostImpl* rvh = multi_iter->second;
344       // Decrement the refcount and shutdown the RenderViewHost if no one else
345       // is using it.
346       CHECK_GT(rvh->ref_count(), 0);
347       rvh->decrement_ref_count();
348       if (rvh->ref_count() == 0) {
349         rvh->Shutdown();
350         render_view_host_pending_shutdown_map_.erase(multi_iter);
351       }
352       break;
353     }
354     CHECK(render_view_host_found);
355   }
356 }
357
358 }  // namespace content