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 // TODO(creis): Remove this version along with FrameTreeNode::frame_id().
35 bool FrameTreeNodeForFrameId(int64 frame_id
,
36 FrameTreeNode
** out_node
,
37 FrameTreeNode
* node
) {
38 if (node
->frame_id() == frame_id
) {
40 // Terminate iteration once the node has been found.
48 FrameTree::FrameTree(Navigator
* navigator
,
49 RenderFrameHostDelegate
* render_frame_delegate
,
50 RenderViewHostDelegate
* render_view_delegate
,
51 RenderWidgetHostDelegate
* render_widget_delegate
,
52 RenderFrameHostManager::Delegate
* manager_delegate
)
53 : render_frame_delegate_(render_frame_delegate
),
54 render_view_delegate_(render_view_delegate
),
55 render_widget_delegate_(render_widget_delegate
),
56 manager_delegate_(manager_delegate
),
57 root_(new FrameTreeNode(this,
59 render_frame_delegate
,
61 render_widget_delegate
,
63 FrameTreeNode::kInvalidFrameId
,
67 FrameTree::~FrameTree() {
70 FrameTreeNode
* FrameTree::FindByID(int64 frame_tree_node_id
) {
71 FrameTreeNode
* node
= NULL
;
72 ForEach(base::Bind(&FrameTreeNodeForId
, frame_tree_node_id
, &node
));
76 void FrameTree::ForEach(
77 const base::Callback
<bool(FrameTreeNode
*)>& on_node
) const {
78 std::queue
<FrameTreeNode
*> queue
;
79 queue
.push(root_
.get());
81 while (!queue
.empty()) {
82 FrameTreeNode
* node
= queue
.front();
84 if (!on_node
.Run(node
))
87 for (size_t i
= 0; i
< node
->child_count(); ++i
)
88 queue
.push(node
->child_at(i
));
92 bool FrameTree::IsFirstNavigationAfterSwap() const {
93 return root_
->frame_id() == FrameTreeNode::kInvalidFrameId
;
96 void FrameTree::OnFirstNavigationAfterSwap(int main_frame_id
) {
97 root_
->set_frame_id(main_frame_id
);
100 RenderFrameHostImpl
* FrameTree::AddFrame(int frame_routing_id
,
101 int64 parent_frame_id
,
103 const std::string
& frame_name
) {
104 FrameTreeNode
* parent
= FindByFrameID(parent_frame_id
);
105 // TODO(ajwong): Should the renderer be killed here? Would there be a race on
106 // shutdown that might make this case possible?
110 scoped_ptr
<FrameTreeNode
> node(new FrameTreeNode(
111 this, parent
->navigator(), render_frame_delegate_
, render_view_delegate_
,
112 render_widget_delegate_
, manager_delegate_
, frame_id
, frame_name
));
113 FrameTreeNode
* node_ptr
= node
.get();
114 // AddChild is what creates the RenderFrameHost.
115 parent
->AddChild(node
.Pass(), frame_routing_id
);
116 return node_ptr
->current_frame_host();
119 void FrameTree::RemoveFrame(RenderFrameHostImpl
* render_frame_host
,
120 int64 parent_frame_id
,
122 // If switches::kSitePerProcess is not specified, then the FrameTree only
123 // contains a node for the root element. However, even in this case
124 // frame detachments need to be broadcast outwards.
126 // TODO(ajwong): Move this below the |parent| check after the FrameTree is
127 // guaranteed to be correctly populated even without the
128 // switches::kSitePerProcess flag.
129 FrameTreeNode
* parent
= FindByFrameID(parent_frame_id
);
130 FrameTreeNode
* child
= FindByFrameID(frame_id
);
131 if (!on_frame_removed_
.is_null()) {
132 on_frame_removed_
.Run(
133 render_frame_host
->render_view_host(), frame_id
);
136 // TODO(ajwong): Should the renderer be killed here? Would there be a race on
137 // shutdown that might make this case possible?
138 if (!parent
|| !child
)
141 parent
->RemoveChild(child
);
144 void FrameTree::SetFrameUrl(int64 frame_id
, const GURL
& url
) {
145 FrameTreeNode
* node
= FindByFrameID(frame_id
);
146 // TODO(ajwong): Should the renderer be killed here? Would there be a race on
147 // shutdown that might make this case possible?
152 node
->set_current_url(url
);
155 void FrameTree::ResetForMainFrameSwap() {
156 return root_
->ResetForMainFrameSwap();
159 RenderFrameHostImpl
* FrameTree::GetMainFrame() const {
160 return root_
->current_frame_host();
163 void FrameTree::SetFrameRemoveListener(
164 const base::Callback
<void(RenderViewHostImpl
*, int64
)>& on_frame_removed
) {
165 on_frame_removed_
= on_frame_removed
;
168 void FrameTree::ClearFrameRemoveListenerForTesting() {
169 on_frame_removed_
.Reset();
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 CHECK(iter
== render_view_host_map_
.end());
182 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
183 RenderViewHostFactory::Create(site_instance
,
184 render_view_delegate_
,
185 render_widget_delegate_
,
187 main_frame_routing_id
,
191 render_view_host_map_
[site_instance
->GetId()] =
192 RenderViewHostRefCount(rvh
, 0);
196 RenderViewHostImpl
* FrameTree::GetRenderViewHostForSubFrame(
197 SiteInstance
* site_instance
) {
198 RenderViewHostMap::iterator iter
=
199 render_view_host_map_
.find(site_instance
->GetId());
200 // TODO(creis): Mirror the frame tree so this check can't fail.
201 if (iter
== render_view_host_map_
.end())
203 RenderViewHostRefCount rvh_refcount
= iter
->second
;
204 return rvh_refcount
.first
;
207 void FrameTree::RegisterRenderFrameHost(
208 RenderFrameHostImpl
* render_frame_host
) {
209 SiteInstance
* site_instance
=
210 render_frame_host
->render_view_host()->GetSiteInstance();
211 RenderViewHostMap::iterator iter
=
212 render_view_host_map_
.find(site_instance
->GetId());
213 CHECK(iter
!= render_view_host_map_
.end());
215 // Increment the refcount.
216 CHECK_GE(iter
->second
.second
, 0);
217 iter
->second
.second
++;
220 void FrameTree::UnregisterRenderFrameHost(
221 RenderFrameHostImpl
* render_frame_host
) {
222 SiteInstance
* site_instance
=
223 render_frame_host
->render_view_host()->GetSiteInstance();
224 RenderViewHostMap::iterator iter
=
225 render_view_host_map_
.find(site_instance
->GetId());
226 CHECK(iter
!= render_view_host_map_
.end());
228 // Decrement the refcount and shutdown the RenderViewHost if no one else is
230 CHECK_GT(iter
->second
.second
, 0);
231 iter
->second
.second
--;
232 if (iter
->second
.second
== 0) {
233 iter
->second
.first
->Shutdown();
234 render_view_host_map_
.erase(iter
);
238 FrameTreeNode
* FrameTree::FindByFrameID(int64 frame_id
) {
239 FrameTreeNode
* node
= NULL
;
240 ForEach(base::Bind(&FrameTreeNodeForFrameId
, frame_id
, &node
));
244 } // namespace content