ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / content / browser / frame_host / frame_tree.cc
blobf3b43e3a4557811726669c63baa84e597da66b6b
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 "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"
22 namespace content {
24 namespace {
26 // This is a global map between frame_tree_node_ids and pointer to
27 // FrameTreeNodes.
28 typedef base::hash_map<int64, FrameTreeNode*> FrameTreeNodeIDMap;
30 base::LazyInstance<FrameTreeNodeIDMap> g_frame_tree_node_id_map =
31 LAZY_INSTANCE_INITIALIZER;
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;
43 return true;
46 bool CreateProxyForSiteInstance(const scoped_refptr<SiteInstance>& instance,
47 FrameTreeNode* node) {
48 // If a new frame is created in the current SiteInstance, other frames in
49 // that SiteInstance don't need a proxy for the new frame.
50 SiteInstance* current_instance =
51 node->render_manager()->current_frame_host()->GetSiteInstance();
52 if (current_instance != instance.get())
53 node->render_manager()->CreateRenderFrameProxy(instance.get());
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())),
75 focused_frame_tree_node_id_(-1) {
76 std::pair<FrameTreeNodeIDMap::iterator, bool> result =
77 g_frame_tree_node_id_map.Get().insert(
78 std::make_pair(root_->frame_tree_node_id(), root_.get()));
79 CHECK(result.second);
82 FrameTree::~FrameTree() {
83 g_frame_tree_node_id_map.Get().erase(root_->frame_tree_node_id());
86 // static
87 FrameTreeNode* FrameTree::GloballyFindByID(int64 frame_tree_node_id) {
88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
89 FrameTreeNodeIDMap* nodes = g_frame_tree_node_id_map.Pointer();
90 FrameTreeNodeIDMap::iterator it = nodes->find(frame_tree_node_id);
91 return it == nodes->end() ? NULL : it->second;
94 FrameTreeNode* FrameTree::FindByID(int64 frame_tree_node_id) {
95 FrameTreeNode* node = NULL;
96 ForEach(base::Bind(&FrameTreeNodeForId, frame_tree_node_id, &node));
97 return node;
100 FrameTreeNode* FrameTree::FindByRoutingID(int process_id, int routing_id) {
101 RenderFrameHostImpl* render_frame_host =
102 RenderFrameHostImpl::FromID(process_id, routing_id);
103 if (render_frame_host) {
104 FrameTreeNode* result = render_frame_host->frame_tree_node();
105 if (this == result->frame_tree())
106 return result;
109 RenderFrameProxyHost* render_frame_proxy_host =
110 RenderFrameProxyHost::FromID(process_id, routing_id);
111 if (render_frame_proxy_host) {
112 FrameTreeNode* result = render_frame_proxy_host->frame_tree_node();
113 if (this == result->frame_tree())
114 return result;
117 return NULL;
120 void FrameTree::ForEach(
121 const base::Callback<bool(FrameTreeNode*)>& on_node) const {
122 ForEach(on_node, NULL);
125 void FrameTree::ForEach(
126 const base::Callback<bool(FrameTreeNode*)>& on_node,
127 FrameTreeNode* skip_this_subtree) const {
128 std::queue<FrameTreeNode*> queue;
129 queue.push(root_.get());
131 while (!queue.empty()) {
132 FrameTreeNode* node = queue.front();
133 queue.pop();
134 if (skip_this_subtree == node)
135 continue;
137 if (!on_node.Run(node))
138 break;
140 for (size_t i = 0; i < node->child_count(); ++i)
141 queue.push(node->child_at(i));
145 RenderFrameHostImpl* FrameTree::AddFrame(FrameTreeNode* parent,
146 int process_id,
147 int new_routing_id,
148 const std::string& frame_name) {
149 // A child frame always starts with an initial empty document, which means
150 // it is in the same SiteInstance as the parent frame. Ensure that the process
151 // which requested a child frame to be added is the same as the process of the
152 // parent node.
153 // We return nullptr if this is not the case, which can happen in a race if an
154 // old RFH sends a CreateChildFrame message as we're swapping to a new RFH.
155 if (parent->current_frame_host()->GetProcess()->GetID() != process_id)
156 return nullptr;
158 scoped_ptr<FrameTreeNode> node(new FrameTreeNode(
159 this, parent->navigator(), render_frame_delegate_, render_view_delegate_,
160 render_widget_delegate_, manager_delegate_, frame_name));
161 std::pair<FrameTreeNodeIDMap::iterator, bool> result =
162 g_frame_tree_node_id_map.Get().insert(
163 std::make_pair(node->frame_tree_node_id(), node.get()));
164 CHECK(result.second);
165 FrameTreeNode* node_ptr = node.get();
166 // AddChild is what creates the RenderFrameHost.
167 parent->AddChild(node.Pass(), process_id, new_routing_id);
168 return node_ptr->current_frame_host();
171 void FrameTree::RemoveFrame(FrameTreeNode* child) {
172 FrameTreeNode* parent = child->parent();
173 if (!parent) {
174 NOTREACHED() << "Unexpected RemoveFrame call for main frame.";
175 return;
178 // Notify observers of the frame removal.
179 RenderFrameHostImpl* render_frame_host = child->current_frame_host();
180 if (!on_frame_removed_.is_null()) {
181 on_frame_removed_.Run(render_frame_host);
183 g_frame_tree_node_id_map.Get().erase(child->frame_tree_node_id());
184 parent->RemoveChild(child);
187 void FrameTree::CreateProxiesForSiteInstance(
188 FrameTreeNode* source,
189 SiteInstance* site_instance) {
190 // Create the swapped out RVH for the new SiteInstance. This will create
191 // a top-level swapped out RFH as well, which will then be wrapped by a
192 // RenderFrameProxyHost.
193 if (!source->IsMainFrame()) {
194 RenderViewHostImpl* render_view_host =
195 source->frame_tree()->GetRenderViewHost(site_instance);
196 if (!render_view_host) {
197 root()->render_manager()->CreateRenderFrame(
198 site_instance, nullptr, MSG_ROUTING_NONE,
199 CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN, nullptr);
200 } else {
201 root()->render_manager()->EnsureRenderViewInitialized(
202 source, render_view_host, site_instance);
206 scoped_refptr<SiteInstance> instance(site_instance);
208 // Proxies are created in the FrameTree in response to a node navigating to a
209 // new SiteInstance. Since |source|'s navigation will replace the currently
210 // loaded document, the entire subtree under |source| will be removed.
211 ForEach(base::Bind(&CreateProxyForSiteInstance, instance), source);
214 void FrameTree::ResetForMainFrameSwap() {
215 root_->ResetForNewProcess();
216 focused_frame_tree_node_id_ = -1;
219 RenderFrameHostImpl* FrameTree::GetMainFrame() const {
220 return root_->current_frame_host();
223 FrameTreeNode* FrameTree::GetFocusedFrame() {
224 return FindByID(focused_frame_tree_node_id_);
227 void FrameTree::SetFocusedFrame(FrameTreeNode* node) {
228 focused_frame_tree_node_id_ = node->frame_tree_node_id();
231 void FrameTree::SetFrameRemoveListener(
232 const base::Callback<void(RenderFrameHost*)>& on_frame_removed) {
233 on_frame_removed_ = on_frame_removed;
236 RenderViewHostImpl* FrameTree::CreateRenderViewHost(SiteInstance* site_instance,
237 int routing_id,
238 int main_frame_routing_id,
239 bool swapped_out,
240 bool hidden) {
241 DCHECK(main_frame_routing_id != MSG_ROUTING_NONE);
242 RenderViewHostMap::iterator iter =
243 render_view_host_map_.find(site_instance->GetId());
244 if (iter != render_view_host_map_.end()) {
245 // If a RenderViewHost's main frame is pending deletion for this
246 // |site_instance|, put it in the map of RenderViewHosts pending shutdown.
247 // Otherwise return the existing RenderViewHost for the SiteInstance.
248 RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
249 iter->second->GetMainFrame());
250 if (main_frame->frame_tree_node()->render_manager()->IsPendingDeletion(
251 main_frame)) {
252 render_view_host_pending_shutdown_map_.insert(
253 std::pair<int, RenderViewHostImpl*>(site_instance->GetId(),
254 iter->second));
255 render_view_host_map_.erase(iter);
256 } else {
257 return iter->second;
260 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
261 RenderViewHostFactory::Create(site_instance,
262 render_view_delegate_,
263 render_widget_delegate_,
264 routing_id,
265 main_frame_routing_id,
266 swapped_out,
267 hidden));
269 render_view_host_map_[site_instance->GetId()] = rvh;
270 return rvh;
273 RenderViewHostImpl* FrameTree::GetRenderViewHost(SiteInstance* site_instance) {
274 RenderViewHostMap::iterator iter =
275 render_view_host_map_.find(site_instance->GetId());
276 // TODO(creis): Mirror the frame tree so this check can't fail.
277 if (iter == render_view_host_map_.end())
278 return NULL;
279 return iter->second;
282 void FrameTree::RegisterRenderFrameHost(
283 RenderFrameHostImpl* render_frame_host) {
284 SiteInstance* site_instance = render_frame_host->GetSiteInstance();
285 RenderViewHostMap::iterator iter =
286 render_view_host_map_.find(site_instance->GetId());
287 CHECK(iter != render_view_host_map_.end());
289 iter->second->increment_ref_count();
292 void FrameTree::UnregisterRenderFrameHost(
293 RenderFrameHostImpl* render_frame_host) {
294 SiteInstance* site_instance = render_frame_host->GetSiteInstance();
295 int32 site_instance_id = site_instance->GetId();
296 RenderViewHostMap::iterator iter =
297 render_view_host_map_.find(site_instance_id);
298 if (iter != render_view_host_map_.end() &&
299 iter->second == render_frame_host->render_view_host()) {
300 // Decrement the refcount and shutdown the RenderViewHost if no one else is
301 // using it.
302 CHECK_GT(iter->second->ref_count(), 0);
303 iter->second->decrement_ref_count();
304 if (iter->second->ref_count() == 0) {
305 iter->second->Shutdown();
306 render_view_host_map_.erase(iter);
308 } else {
309 // The RenderViewHost should be in the list of RenderViewHosts pending
310 // shutdown.
311 bool render_view_host_found = false;
312 std::pair<RenderViewHostMultiMap::iterator,
313 RenderViewHostMultiMap::iterator> result =
314 render_view_host_pending_shutdown_map_.equal_range(site_instance_id);
315 for (RenderViewHostMultiMap::iterator multi_iter = result.first;
316 multi_iter != result.second;
317 ++multi_iter) {
318 if (multi_iter->second != render_frame_host->render_view_host())
319 continue;
320 render_view_host_found = true;
321 RenderViewHostImpl* rvh = multi_iter->second;
322 // Decrement the refcount and shutdown the RenderViewHost if no one else
323 // is using it.
324 CHECK_GT(rvh->ref_count(), 0);
325 rvh->decrement_ref_count();
326 if (rvh->ref_count() == 0) {
327 rvh->Shutdown();
328 render_view_host_pending_shutdown_map_.erase(multi_iter);
330 break;
332 CHECK(render_view_host_found);
336 } // namespace content