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"
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 #include "content/browser/renderer_host/render_view_host_factory.h"
16 #include "content/browser/renderer_host/render_view_host_impl.h"
21 // Used with FrameTree::ForEach() to search for the FrameTreeNode
22 // corresponding to |frame_tree_node_id|.
23 bool FrameTreeNodeForId(int64 frame_tree_node_id
,
24 FrameTreeNode
** out_node
,
25 FrameTreeNode
* node
) {
26 if (node
->frame_tree_node_id() == frame_tree_node_id
) {
28 // Terminate iteration once the node has been found.
34 bool FrameTreeNodeForRoutingId(int routing_id
,
36 FrameTreeNode
** out_node
,
37 FrameTreeNode
* node
) {
38 // TODO(creis): Look through the swapped out RFHs as well.
39 if (node
->current_frame_host()->GetProcess()->GetID() == process_id
&&
40 node
->current_frame_host()->GetRoutingID() == routing_id
) {
42 // Terminate iteration once the node has been found.
48 // Iterate over the FrameTree to reset any node affected by the loss of the
49 // given RenderViewHost's process.
50 bool ResetNodesForNewProcess(RenderViewHost
* render_view_host
,
51 FrameTreeNode
* node
) {
52 if (render_view_host
== node
->current_frame_host()->render_view_host())
53 node
->ResetForNewProcess();
59 FrameTree::FrameTree(Navigator
* navigator
,
60 RenderFrameHostDelegate
* render_frame_delegate
,
61 RenderViewHostDelegate
* render_view_delegate
,
62 RenderWidgetHostDelegate
* render_widget_delegate
,
63 RenderFrameHostManager::Delegate
* manager_delegate
)
64 : render_frame_delegate_(render_frame_delegate
),
65 render_view_delegate_(render_view_delegate
),
66 render_widget_delegate_(render_widget_delegate
),
67 manager_delegate_(manager_delegate
),
68 root_(new FrameTreeNode(this,
70 render_frame_delegate
,
72 render_widget_delegate
,
75 focused_frame_tree_node_id_(-1) {
78 FrameTree::~FrameTree() {
81 FrameTreeNode
* FrameTree::FindByID(int64 frame_tree_node_id
) {
82 FrameTreeNode
* node
= NULL
;
83 ForEach(base::Bind(&FrameTreeNodeForId
, frame_tree_node_id
, &node
));
87 FrameTreeNode
* FrameTree::FindByRoutingID(int routing_id
, int process_id
) {
88 FrameTreeNode
* node
= NULL
;
90 base::Bind(&FrameTreeNodeForRoutingId
, routing_id
, process_id
, &node
));
94 void FrameTree::ForEach(
95 const base::Callback
<bool(FrameTreeNode
*)>& on_node
) const {
96 std::queue
<FrameTreeNode
*> queue
;
97 queue
.push(root_
.get());
99 while (!queue
.empty()) {
100 FrameTreeNode
* node
= queue
.front();
102 if (!on_node
.Run(node
))
105 for (size_t i
= 0; i
< node
->child_count(); ++i
)
106 queue
.push(node
->child_at(i
));
110 RenderFrameHostImpl
* FrameTree::AddFrame(FrameTreeNode
* parent
,
112 const std::string
& frame_name
) {
113 scoped_ptr
<FrameTreeNode
> node(new FrameTreeNode(
114 this, parent
->navigator(), render_frame_delegate_
, render_view_delegate_
,
115 render_widget_delegate_
, manager_delegate_
, frame_name
));
116 FrameTreeNode
* node_ptr
= node
.get();
117 // AddChild is what creates the RenderFrameHost.
118 parent
->AddChild(node
.Pass(), new_routing_id
);
119 return node_ptr
->current_frame_host();
122 void FrameTree::RemoveFrame(FrameTreeNode
* child
) {
123 FrameTreeNode
* parent
= child
->parent();
125 NOTREACHED() << "Unexpected RemoveFrame call for main frame.";
129 // Notify observers of the frame removal.
130 RenderFrameHostImpl
* render_frame_host
= child
->current_frame_host();
131 if (!on_frame_removed_
.is_null()) {
132 on_frame_removed_
.Run(
133 render_frame_host
->render_view_host(),
134 render_frame_host
->GetRoutingID());
137 parent
->RemoveChild(child
);
140 void FrameTree::ResetForMainFrameSwap() {
141 root_
->ResetForNewProcess();
142 focused_frame_tree_node_id_
= -1;
145 void FrameTree::RenderProcessGone(RenderViewHost
* render_view_host
) {
146 // Walk the full tree looking for nodes that may be affected. Once a frame
147 // crashes, all of its child FrameTreeNodes go away.
148 // Note that the helper function may call ResetForNewProcess on a node, which
149 // clears its children before we iterate over them. That's ok, because
150 // ForEach does not add a node's children to the queue until after visiting
152 ForEach(base::Bind(&ResetNodesForNewProcess
, render_view_host
));
155 RenderFrameHostImpl
* FrameTree::GetMainFrame() const {
156 return root_
->current_frame_host();
159 FrameTreeNode
* FrameTree::GetFocusedFrame() {
160 return FindByID(focused_frame_tree_node_id_
);
163 void FrameTree::SetFocusedFrame(FrameTreeNode
* node
) {
164 focused_frame_tree_node_id_
= node
->frame_tree_node_id();
167 void FrameTree::SetFrameRemoveListener(
168 const base::Callback
<void(RenderViewHostImpl
*, int)>& on_frame_removed
) {
169 on_frame_removed_
= on_frame_removed
;
172 RenderViewHostImpl
* FrameTree::CreateRenderViewHostForMainFrame(
173 SiteInstance
* site_instance
,
175 int main_frame_routing_id
,
178 DCHECK(main_frame_routing_id
!= MSG_ROUTING_NONE
);
179 RenderViewHostMap::iterator iter
=
180 render_view_host_map_
.find(site_instance
->GetId());
181 if (iter
!= render_view_host_map_
.end()) {
182 // If a RenderViewHost is pending shutdown for this |site_instance|, put it
183 // in the map of RenderViewHosts pending shutdown. Otherwise there should
184 // not be a RenderViewHost for the SiteInstance.
185 CHECK_EQ(RenderViewHostImpl::STATE_PENDING_SHUTDOWN
,
186 iter
->second
->rvh_state());
187 render_view_host_pending_shutdown_map_
.insert(
188 std::pair
<int, RenderViewHostImpl
*>(site_instance
->GetId(),
190 render_view_host_map_
.erase(iter
);
192 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
193 RenderViewHostFactory::Create(site_instance
,
194 render_view_delegate_
,
195 render_widget_delegate_
,
197 main_frame_routing_id
,
201 render_view_host_map_
[site_instance
->GetId()] = rvh
;
205 RenderViewHostImpl
* FrameTree::GetRenderViewHostForSubFrame(
206 SiteInstance
* site_instance
) {
207 RenderViewHostMap::iterator iter
=
208 render_view_host_map_
.find(site_instance
->GetId());
209 // TODO(creis): Mirror the frame tree so this check can't fail.
210 if (iter
== render_view_host_map_
.end())
215 void FrameTree::RegisterRenderFrameHost(
216 RenderFrameHostImpl
* render_frame_host
) {
217 SiteInstance
* site_instance
=
218 render_frame_host
->render_view_host()->GetSiteInstance();
219 RenderViewHostMap::iterator iter
=
220 render_view_host_map_
.find(site_instance
->GetId());
221 CHECK(iter
!= render_view_host_map_
.end());
223 iter
->second
->increment_ref_count();
226 void FrameTree::UnregisterRenderFrameHost(
227 RenderFrameHostImpl
* render_frame_host
) {
228 SiteInstance
* site_instance
=
229 render_frame_host
->render_view_host()->GetSiteInstance();
230 int32 site_instance_id
= site_instance
->GetId();
231 RenderViewHostMap::iterator iter
=
232 render_view_host_map_
.find(site_instance_id
);
233 if (iter
!= render_view_host_map_
.end() &&
234 iter
->second
== render_frame_host
->render_view_host()) {
235 // Decrement the refcount and shutdown the RenderViewHost if no one else is
237 CHECK_GT(iter
->second
->ref_count(), 0);
238 iter
->second
->decrement_ref_count();
239 if (iter
->second
->ref_count() == 0) {
240 iter
->second
->Shutdown();
241 render_view_host_map_
.erase(iter
);
244 // The RenderViewHost should be in the list of RenderViewHosts pending
246 bool render_view_host_found
= false;
247 std::pair
<RenderViewHostMultiMap::iterator
,
248 RenderViewHostMultiMap::iterator
> result
=
249 render_view_host_pending_shutdown_map_
.equal_range(site_instance_id
);
250 for (RenderViewHostMultiMap::iterator multi_iter
= result
.first
;
251 multi_iter
!= result
.second
;
253 if (multi_iter
->second
!= render_frame_host
->render_view_host())
255 render_view_host_found
= true;
256 RenderViewHostImpl
* rvh
= multi_iter
->second
;
257 // Decrement the refcount and shutdown the RenderViewHost if no one else
259 CHECK_GT(rvh
->ref_count(), 0);
260 rvh
->decrement_ref_count();
261 if (rvh
->ref_count() == 0) {
263 render_view_host_pending_shutdown_map_
.erase(multi_iter
);
267 CHECK(render_view_host_found
);
271 } // namespace content