Cast: Skip receiver log messages with time delta that can't be encoded.
[chromium-blink-merge.git] / content / browser / frame_host / frame_tree.cc
blob23fc768af0c56c090abe1aa273f4f84ff6a1d2c0
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 "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"
18 namespace content {
20 namespace {
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) {
27 *out_node = node;
28 // Terminate iteration once the node has been found.
29 return false;
31 return true;
34 bool FrameTreeNodeForRoutingId(int routing_id,
35 int process_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) {
41 *out_node = node;
42 // Terminate iteration once the node has been found.
43 return false;
45 return true;
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();
54 return true;
57 } // namespace
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,
69 navigator,
70 render_frame_delegate,
71 render_view_delegate,
72 render_widget_delegate,
73 manager_delegate,
74 std::string())) {
77 FrameTree::~FrameTree() {
80 FrameTreeNode* FrameTree::FindByID(int64 frame_tree_node_id) {
81 FrameTreeNode* node = NULL;
82 ForEach(base::Bind(&FrameTreeNodeForId, frame_tree_node_id, &node));
83 return node;
86 FrameTreeNode* FrameTree::FindByRoutingID(int routing_id, int process_id) {
87 FrameTreeNode* node = NULL;
88 ForEach(
89 base::Bind(&FrameTreeNodeForRoutingId, routing_id, process_id, &node));
90 return node;
93 void FrameTree::ForEach(
94 const base::Callback<bool(FrameTreeNode*)>& on_node) const {
95 std::queue<FrameTreeNode*> queue;
96 queue.push(root_.get());
98 while (!queue.empty()) {
99 FrameTreeNode* node = queue.front();
100 queue.pop();
101 if (!on_node.Run(node))
102 break;
104 for (size_t i = 0; i < node->child_count(); ++i)
105 queue.push(node->child_at(i));
109 RenderFrameHostImpl* FrameTree::AddFrame(FrameTreeNode* parent,
110 int new_routing_id,
111 const std::string& frame_name) {
112 scoped_ptr<FrameTreeNode> node(new FrameTreeNode(
113 this, parent->navigator(), render_frame_delegate_, render_view_delegate_,
114 render_widget_delegate_, manager_delegate_, frame_name));
115 FrameTreeNode* node_ptr = node.get();
116 // AddChild is what creates the RenderFrameHost.
117 parent->AddChild(node.Pass(), new_routing_id);
118 return node_ptr->current_frame_host();
121 void FrameTree::RemoveFrame(FrameTreeNode* child) {
122 FrameTreeNode* parent = child->parent();
123 if (!parent) {
124 NOTREACHED() << "Unexpected RemoveFrame call for main frame.";
125 return;
128 // Notify observers of the frame removal.
129 RenderFrameHostImpl* render_frame_host = child->current_frame_host();
130 if (!on_frame_removed_.is_null()) {
131 on_frame_removed_.Run(
132 render_frame_host->render_view_host(),
133 render_frame_host->GetRoutingID());
136 parent->RemoveChild(child);
139 void FrameTree::ResetForMainFrameSwap() {
140 root_->ResetForNewProcess();
143 void FrameTree::RenderProcessGone(RenderViewHost* render_view_host) {
144 // Walk the full tree looking for nodes that may be affected. Once a frame
145 // crashes, all of its child FrameTreeNodes go away.
146 // Note that the helper function may call ResetForNewProcess on a node, which
147 // clears its children before we iterate over them. That's ok, because
148 // ForEach does not add a node's children to the queue until after visiting
149 // the node itself.
150 ForEach(base::Bind(&ResetNodesForNewProcess, render_view_host));
153 RenderFrameHostImpl* FrameTree::GetMainFrame() const {
154 return root_->current_frame_host();
157 void FrameTree::SetFrameRemoveListener(
158 const base::Callback<void(RenderViewHostImpl*, int)>& on_frame_removed) {
159 on_frame_removed_ = on_frame_removed;
162 RenderViewHostImpl* FrameTree::CreateRenderViewHostForMainFrame(
163 SiteInstance* site_instance,
164 int routing_id,
165 int main_frame_routing_id,
166 bool swapped_out,
167 bool hidden) {
168 DCHECK(main_frame_routing_id != MSG_ROUTING_NONE);
169 RenderViewHostMap::iterator iter =
170 render_view_host_map_.find(site_instance->GetId());
171 if (iter != render_view_host_map_.end()) {
172 // If a RenderViewHost is pending shutdown for this |site_instance|, put it
173 // in the map of RenderViewHosts pending shutdown. Otherwise there should
174 // not be a RenderViewHost for the SiteInstance.
175 CHECK_EQ(RenderViewHostImpl::STATE_PENDING_SHUTDOWN,
176 iter->second->rvh_state());
177 render_view_host_pending_shutdown_map_.insert(
178 std::pair<int, RenderViewHostImpl*>(site_instance->GetId(),
179 iter->second));
180 render_view_host_map_.erase(iter);
182 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
183 RenderViewHostFactory::Create(site_instance,
184 render_view_delegate_,
185 render_widget_delegate_,
186 routing_id,
187 main_frame_routing_id,
188 swapped_out,
189 hidden));
191 render_view_host_map_[site_instance->GetId()] = rvh;
192 return rvh;
195 RenderViewHostImpl* FrameTree::GetRenderViewHostForSubFrame(
196 SiteInstance* site_instance) {
197 RenderViewHostMap::iterator iter =
198 render_view_host_map_.find(site_instance->GetId());
199 // TODO(creis): Mirror the frame tree so this check can't fail.
200 if (iter == render_view_host_map_.end())
201 return NULL;
202 return iter->second;
205 void FrameTree::RegisterRenderFrameHost(
206 RenderFrameHostImpl* render_frame_host) {
207 SiteInstance* site_instance =
208 render_frame_host->render_view_host()->GetSiteInstance();
209 RenderViewHostMap::iterator iter =
210 render_view_host_map_.find(site_instance->GetId());
211 CHECK(iter != render_view_host_map_.end());
213 iter->second->increment_ref_count();
216 void FrameTree::UnregisterRenderFrameHost(
217 RenderFrameHostImpl* render_frame_host) {
218 SiteInstance* site_instance =
219 render_frame_host->render_view_host()->GetSiteInstance();
220 int32 site_instance_id = site_instance->GetId();
221 RenderViewHostMap::iterator iter =
222 render_view_host_map_.find(site_instance_id);
223 if (iter != render_view_host_map_.end() &&
224 iter->second == render_frame_host->render_view_host()) {
225 // Decrement the refcount and shutdown the RenderViewHost if no one else is
226 // using it.
227 CHECK_GT(iter->second->ref_count(), 0);
228 iter->second->decrement_ref_count();
229 if (iter->second->ref_count() == 0) {
230 iter->second->Shutdown();
231 render_view_host_map_.erase(iter);
233 } else {
234 // The RenderViewHost should be in the list of RenderViewHosts pending
235 // shutdown.
236 bool render_view_host_found = false;
237 std::pair<RenderViewHostMultiMap::iterator,
238 RenderViewHostMultiMap::iterator> result =
239 render_view_host_pending_shutdown_map_.equal_range(site_instance_id);
240 for (RenderViewHostMultiMap::iterator multi_iter = result.first;
241 multi_iter != result.second;
242 ++multi_iter) {
243 if (multi_iter->second != render_frame_host->render_view_host())
244 continue;
245 render_view_host_found = true;
246 RenderViewHostImpl* rvh = multi_iter->second;
247 // Decrement the refcount and shutdown the RenderViewHost if no one else
248 // is using it.
249 CHECK_GT(rvh->ref_count(), 0);
250 rvh->decrement_ref_count();
251 if (rvh->ref_count() == 0) {
252 rvh->Shutdown();
253 render_view_host_pending_shutdown_map_.erase(multi_iter);
255 break;
257 CHECK(render_view_host_found);
261 } // namespace content