blob: 199edd496359fb68d51586321bd372475f2a0682 [file] [log] [blame]
[email protected]9b159a52013-10-03 17:24:551// 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
[email protected]d4a8ca482013-10-30 21:06:405#include "content/browser/frame_host/frame_tree.h"
[email protected]9b159a52013-10-03 17:24:556
avib7348942015-12-25 20:57:107#include <stddef.h>
8
[email protected]9b159a52013-10-03 17:24:559#include <queue>
dcheng29f5a6c2015-08-31 21:43:2710#include <utility>
[email protected]9b159a52013-10-03 17:24:5511
12#include "base/bind.h"
13#include "base/callback.h"
[email protected]20edca72014-08-14 10:27:5314#include "base/containers/hash_tables.h"
15#include "base/lazy_instance.h"
[email protected]d4a8ca482013-10-30 21:06:4016#include "content/browser/frame_host/frame_tree_node.h"
[email protected]190b8c52013-11-09 01:35:4417#include "content/browser/frame_host/navigator.h"
[email protected]2a18ee222013-11-21 07:52:4418#include "content/browser/frame_host/render_frame_host_factory.h"
[email protected]d4a8ca482013-10-30 21:06:4019#include "content/browser/frame_host/render_frame_host_impl.h"
dmazzoni0b5d2482014-09-10 19:45:5720#include "content/browser/frame_host/render_frame_proxy_host.h"
[email protected]94d0cc12013-12-18 00:07:4121#include "content/browser/renderer_host/render_view_host_factory.h"
22#include "content/browser/renderer_host/render_view_host_impl.h"
alexmos3fcd0ca2015-10-23 18:18:3323#include "content/common/input_messages.h"
nickac60e75472015-07-31 00:44:3524#include "content/common/site_isolation_policy.h"
dcheng5f60abb2015-05-28 01:39:3625#include "third_party/WebKit/public/web/WebSandboxFlags.h"
[email protected]9b159a52013-10-03 17:24:5526
27namespace content {
28
29namespace {
[email protected]20edca72014-08-14 10:27:5330
dcheng57e39e22016-01-21 00:25:3831// Helper function to collect SiteInstances involved in rendering a single
32// FrameTree (which is a subset of SiteInstances in main frame's proxy_hosts_
33// because of openers).
34std::set<SiteInstance*> CollectSiteInstances(FrameTree* tree) {
35 std::set<SiteInstance*> instances;
36 for (FrameTreeNode* node : tree->Nodes())
37 instances.insert(node->current_frame_host()->GetSiteInstance());
38 return instances;
alexmos3fcd0ca2015-10-23 18:18:3339}
40
[email protected]9b159a52013-10-03 17:24:5541} // namespace
42
dcheng57e39e22016-01-21 00:25:3843FrameTree::NodeIterator::~NodeIterator() {}
44
45FrameTree::NodeIterator& FrameTree::NodeIterator::operator++() {
46 for (size_t i = 0; i < current_node_->child_count(); ++i) {
47 FrameTreeNode* child = current_node_->child_at(i);
48 if (child == node_to_skip_)
49 continue;
50 queue_.push(child);
51 }
52
53 if (!queue_.empty()) {
54 current_node_ = queue_.front();
55 queue_.pop();
56 } else {
57 current_node_ = nullptr;
58 }
59
60 return *this;
61}
62
63bool FrameTree::NodeIterator::operator==(const NodeIterator& rhs) const {
64 return current_node_ == rhs.current_node_;
65}
66
67FrameTree::NodeIterator::NodeIterator(FrameTreeNode* starting_node,
68 FrameTreeNode* node_to_skip)
69 : current_node_(starting_node != node_to_skip ? starting_node : nullptr),
70 node_to_skip_(node_to_skip) {}
71
72FrameTree::NodeIterator FrameTree::NodeRange::begin() {
73 return NodeIterator(tree_->root(), node_to_skip_);
74}
75
76FrameTree::NodeIterator FrameTree::NodeRange::end() {
77 return NodeIterator(nullptr, nullptr);
78}
79
80FrameTree::NodeRange::NodeRange(FrameTree* tree, FrameTreeNode* node_to_skip)
81 : tree_(tree), node_to_skip_(node_to_skip) {}
82
clamy44e84ce2016-02-22 15:38:2583FrameTree::ConstNodeIterator::~ConstNodeIterator() {}
84
85FrameTree::ConstNodeIterator& FrameTree::ConstNodeIterator::operator++() {
86 for (size_t i = 0; i < current_node_->child_count(); ++i) {
87 const FrameTreeNode* child = current_node_->child_at(i);
88 queue_.push(child);
89 }
90
91 if (!queue_.empty()) {
92 current_node_ = queue_.front();
93 queue_.pop();
94 } else {
95 current_node_ = nullptr;
96 }
97
98 return *this;
99}
100
101bool FrameTree::ConstNodeIterator::operator==(
102 const ConstNodeIterator& rhs) const {
103 return current_node_ == rhs.current_node_;
104}
105
106FrameTree::ConstNodeIterator::ConstNodeIterator(
107 const FrameTreeNode* starting_node)
108 : current_node_(starting_node) {}
109
110FrameTree::ConstNodeIterator FrameTree::ConstNodeRange::begin() {
111 return ConstNodeIterator(tree_->root());
112}
113
114FrameTree::ConstNodeIterator FrameTree::ConstNodeRange::end() {
115 return ConstNodeIterator(nullptr);
116}
117
118FrameTree::ConstNodeRange::ConstNodeRange(const FrameTree* tree)
119 : tree_(tree) {}
120
[email protected]fa944cb82013-11-15 17:51:21121FrameTree::FrameTree(Navigator* navigator,
[email protected]92404c62013-12-04 16:40:46122 RenderFrameHostDelegate* render_frame_delegate,
[email protected]fa944cb82013-11-15 17:51:21123 RenderViewHostDelegate* render_view_delegate,
124 RenderWidgetHostDelegate* render_widget_delegate,
[email protected]b0936d22013-11-28 06:47:36125 RenderFrameHostManager::Delegate* manager_delegate)
[email protected]92404c62013-12-04 16:40:46126 : render_frame_delegate_(render_frame_delegate),
127 render_view_delegate_(render_view_delegate),
[email protected]fa944cb82013-11-15 17:51:21128 render_widget_delegate_(render_widget_delegate),
129 manager_delegate_(manager_delegate),
[email protected]94d0cc12013-12-18 00:07:41130 root_(new FrameTreeNode(this,
131 navigator,
[email protected]92404c62013-12-04 16:40:46132 render_frame_delegate,
[email protected]fa944cb82013-11-15 17:51:21133 render_view_delegate,
134 render_widget_delegate,
135 manager_delegate,
dcheng860817a2015-05-22 03:16:56136 // The top-level frame must always be in a
137 // document scope.
138 blink::WebTreeScopeType::Document,
alexmos6e0ee0c2015-05-01 18:57:34139 std::string(),
lukasza464d8692016-02-22 19:26:32140 std::string(),
lazyboy70605c32015-11-03 01:27:31141 blink::WebFrameOwnerProperties())),
fdegansa696e5112015-04-17 01:57:59142 focused_frame_tree_node_id_(-1),
lazyboy70605c32015-11-03 01:27:31143 load_progress_(0.0) {}
[email protected]9b159a52013-10-03 17:24:55144
145FrameTree::~FrameTree() {
nick70b782d2015-10-06 17:37:04146 delete root_;
147 root_ = nullptr;
[email protected]9b159a52013-10-03 17:24:55148}
149
vishal.b782eb5d2015-04-29 12:22:57150FrameTreeNode* FrameTree::FindByID(int frame_tree_node_id) {
dcheng57e39e22016-01-21 00:25:38151 for (FrameTreeNode* node : Nodes()) {
152 if (node->frame_tree_node_id() == frame_tree_node_id)
153 return node;
154 }
155 return nullptr;
[email protected]9b159a52013-10-03 17:24:55156}
157
nasko479ea5a2015-02-14 00:03:04158FrameTreeNode* FrameTree::FindByRoutingID(int process_id, int routing_id) {
dmazzoni0b5d2482014-09-10 19:45:57159 RenderFrameHostImpl* render_frame_host =
160 RenderFrameHostImpl::FromID(process_id, routing_id);
161 if (render_frame_host) {
162 FrameTreeNode* result = render_frame_host->frame_tree_node();
163 if (this == result->frame_tree())
164 return result;
165 }
166
167 RenderFrameProxyHost* render_frame_proxy_host =
168 RenderFrameProxyHost::FromID(process_id, routing_id);
169 if (render_frame_proxy_host) {
170 FrameTreeNode* result = render_frame_proxy_host->frame_tree_node();
171 if (this == result->frame_tree())
172 return result;
173 }
174
creis6a93a812015-04-24 23:13:17175 return nullptr;
176}
177
178FrameTreeNode* FrameTree::FindByName(const std::string& name) {
179 if (name.empty())
nick70b782d2015-10-06 17:37:04180 return root_;
creis6a93a812015-04-24 23:13:17181
dcheng57e39e22016-01-21 00:25:38182 for (FrameTreeNode* node : Nodes()) {
183 if (node->frame_name() == name)
184 return node;
[email protected]9b159a52013-10-03 17:24:55185 }
dcheng57e39e22016-01-21 00:25:38186
187 return nullptr;
188}
189
190FrameTree::NodeRange FrameTree::Nodes() {
191 return NodesExcept(nullptr);
192}
193
194FrameTree::NodeRange FrameTree::NodesExcept(FrameTreeNode* node_to_skip) {
195 return NodeRange(this, node_to_skip);
[email protected]9b159a52013-10-03 17:24:55196}
197
clamy44e84ce2016-02-22 15:38:25198FrameTree::ConstNodeRange FrameTree::ConstNodes() const {
199 return ConstNodeRange(this);
200}
201
nick8814e652015-12-18 01:44:12202bool FrameTree::AddFrame(
lazyboy70605c32015-11-03 01:27:31203 FrameTreeNode* parent,
204 int process_id,
205 int new_routing_id,
206 blink::WebTreeScopeType scope,
207 const std::string& frame_name,
lukasza464d8692016-02-22 19:26:32208 const std::string& frame_unique_name,
lazyboy70605c32015-11-03 01:27:31209 blink::WebSandboxFlags sandbox_flags,
210 const blink::WebFrameOwnerProperties& frame_owner_properties) {
nick8814e652015-12-18 01:44:12211 CHECK_NE(new_routing_id, MSG_ROUTING_NONE);
212
dgroganfb22f9a2014-10-20 21:32:32213 // A child frame always starts with an initial empty document, which means
214 // it is in the same SiteInstance as the parent frame. Ensure that the process
215 // which requested a child frame to be added is the same as the process of the
216 // parent node.
dgroganfb22f9a2014-10-20 21:32:32217 if (parent->current_frame_host()->GetProcess()->GetID() != process_id)
nick8814e652015-12-18 01:44:12218 return false;
dgroganfb22f9a2014-10-20 21:32:32219
[email protected]5f96f5a62014-01-10 00:05:11220 // AddChild is what creates the RenderFrameHost.
nick8814e652015-12-18 01:44:12221 FrameTreeNode* added_node = parent->AddChild(
222 make_scoped_ptr(new FrameTreeNode(
223 this, parent->navigator(), render_frame_delegate_,
224 render_view_delegate_, render_widget_delegate_, manager_delegate_,
lukasza464d8692016-02-22 19:26:32225 scope, frame_name, frame_unique_name, frame_owner_properties)),
nick8814e652015-12-18 01:44:12226 process_id, new_routing_id);
227
alexmos6e940102016-01-19 22:47:25228 // Set sandbox flags and make them effective immediately, since initial
229 // sandbox flags should apply to the initial empty document in the frame.
230 added_node->SetPendingSandboxFlags(sandbox_flags);
231 added_node->CommitPendingSandboxFlags();
232
nick8814e652015-12-18 01:44:12233 // Now that the new node is part of the FrameTree and has a RenderFrameHost,
234 // we can announce the creation of the initial RenderFrame which already
235 // exists in the renderer process.
236 added_node->current_frame_host()->SetRenderFrameCreated(true);
237 return true;
[email protected]9b159a52013-10-03 17:24:55238}
239
[email protected]58faf942014-02-20 21:03:58240void FrameTree::RemoveFrame(FrameTreeNode* child) {
241 FrameTreeNode* parent = child->parent();
242 if (!parent) {
243 NOTREACHED() << "Unexpected RemoveFrame call for main frame.";
244 return;
[email protected]9b159a52013-10-03 17:24:55245 }
246
[email protected]741fd682013-11-08 08:26:55247 parent->RemoveChild(child);
[email protected]9b159a52013-10-03 17:24:55248}
249
[email protected]82307f6b2014-08-07 03:30:12250void FrameTree::CreateProxiesForSiteInstance(
251 FrameTreeNode* source,
252 SiteInstance* site_instance) {
253 // Create the swapped out RVH for the new SiteInstance. This will create
254 // a top-level swapped out RFH as well, which will then be wrapped by a
255 // RenderFrameProxyHost.
alexmos58729042015-06-18 23:20:00256 if (!source || !source->IsMainFrame()) {
257 RenderViewHostImpl* render_view_host = GetRenderViewHost(site_instance);
[email protected]82307f6b2014-08-07 03:30:12258 if (!render_view_host) {
nickac60e75472015-07-31 00:44:35259 if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
nasko4c0feb62015-06-05 18:37:06260 root()->render_manager()->CreateRenderFrameProxy(site_instance);
261 } else {
262 root()->render_manager()->CreateRenderFrame(
carlosk35f35af2015-12-01 10:55:40263 site_instance, CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN, nullptr);
nasko4c0feb62015-06-05 18:37:06264 }
lazyboybb1af562015-02-04 02:36:02265 } else {
alexmos58729042015-06-18 23:20:00266 root()->render_manager()->EnsureRenderViewInitialized(render_view_host,
267 site_instance);
[email protected]82307f6b2014-08-07 03:30:12268 }
269 }
270
naskoe6edde32014-10-17 15:36:48271 // Proxies are created in the FrameTree in response to a node navigating to a
272 // new SiteInstance. Since |source|'s navigation will replace the currently
273 // loaded document, the entire subtree under |source| will be removed.
dcheng57e39e22016-01-21 00:25:38274 for (FrameTreeNode* node : NodesExcept(source)) {
275 // If a new frame is created in the current SiteInstance, other frames in
276 // that SiteInstance don't need a proxy for the new frame.
277 SiteInstance* current_instance =
278 node->render_manager()->current_frame_host()->GetSiteInstance();
279 if (current_instance != site_instance)
280 node->render_manager()->CreateRenderFrameProxy(site_instance);
281 }
[email protected]82307f6b2014-08-07 03:30:12282}
283
[email protected]9b159a52013-10-03 17:24:55284RenderFrameHostImpl* FrameTree::GetMainFrame() const {
[email protected]94d0cc12013-12-18 00:07:41285 return root_->current_frame_host();
[email protected]9b159a52013-10-03 17:24:55286}
287
[email protected]9c9343b2014-03-08 02:56:07288FrameTreeNode* FrameTree::GetFocusedFrame() {
289 return FindByID(focused_frame_tree_node_id_);
290}
291
alexmos5357efb2015-12-16 21:44:00292void FrameTree::SetFocusedFrame(FrameTreeNode* node, SiteInstance* source) {
293 if (node == GetFocusedFrame())
294 return;
295
dcheng57e39e22016-01-21 00:25:38296 std::set<SiteInstance*> frame_tree_site_instances =
297 CollectSiteInstances(this);
alexmosb1dc2162015-11-05 00:59:20298
alexmos5357efb2015-12-16 21:44:00299 SiteInstance* current_instance =
300 node->current_frame_host()->GetSiteInstance();
301
alexmosb1dc2162015-11-05 00:59:20302 // Update the focused frame in all other SiteInstances. If focus changes to
303 // a cross-process frame, this allows the old focused frame's renderer
304 // process to clear focus from that frame and fire blur events. It also
305 // ensures that the latest focused frame is available in all renderers to
306 // compute document.activeElement.
alexmos5357efb2015-12-16 21:44:00307 //
308 // We do not notify the |source| SiteInstance because it already knows the
309 // new focused frame (since it initiated the focus change), and we notify the
310 // new focused frame's SiteInstance (if it differs from |source|) separately
311 // below.
alexmosb1dc2162015-11-05 00:59:20312 for (const auto& instance : frame_tree_site_instances) {
alexmos5357efb2015-12-16 21:44:00313 if (instance != source && instance != current_instance) {
alexmosb1dc2162015-11-05 00:59:20314 DCHECK(SiteIsolationPolicy::AreCrossProcessFramesPossible());
315 RenderFrameProxyHost* proxy =
316 node->render_manager()->GetRenderFrameProxyHost(instance);
317 proxy->SetFocusedFrame();
318 }
alexmosca2c6ba2015-10-01 21:52:25319 }
320
alexmos5357efb2015-12-16 21:44:00321 // If |node| was focused from a cross-process frame (i.e., via
322 // window.focus()), tell its RenderFrame that it should focus.
323 if (current_instance != source)
324 node->current_frame_host()->SetFocusedFrame();
325
[email protected]9c9343b2014-03-08 02:56:07326 focused_frame_tree_node_id_ = node->frame_tree_node_id();
alexmos21acae52015-11-07 01:04:43327 node->DidFocus();
[email protected]9c9343b2014-03-08 02:56:07328}
329
[email protected]9b159a52013-10-03 17:24:55330void FrameTree::SetFrameRemoveListener(
[email protected]ae7eeda2014-07-04 01:53:26331 const base::Callback<void(RenderFrameHost*)>& on_frame_removed) {
[email protected]9b159a52013-10-03 17:24:55332 on_frame_removed_ = on_frame_removed;
333}
334
avib7348942015-12-25 20:57:10335RenderViewHostImpl* FrameTree::CreateRenderViewHost(
336 SiteInstance* site_instance,
337 int32_t routing_id,
338 int32_t main_frame_routing_id,
339 bool swapped_out,
340 bool hidden) {
[email protected]94d0cc12013-12-18 00:07:41341 RenderViewHostMap::iterator iter =
342 render_view_host_map_.find(site_instance->GetId());
[email protected]21b41c7e892014-02-28 01:52:24343 if (iter != render_view_host_map_.end()) {
alexmosb97d6bb62015-09-24 07:31:26344 // If a RenderViewHost is pending deletion for this |site_instance|, it
345 // shouldn't be reused, so put it in the map of RenderViewHosts pending
346 // shutdown. Otherwise, return the existing RenderViewHost for the
347 // SiteInstance. Note that if swapped-out is forbidden, the
348 // RenderViewHost's main frame has already been cleared, so we cannot rely
349 // on checking whether the main frame is pending deletion.
350 if (iter->second->is_pending_deletion()) {
[email protected]82307f6b2014-08-07 03:30:12351 render_view_host_pending_shutdown_map_.insert(
dcheng29f5a6c2015-08-31 21:43:27352 std::make_pair(site_instance->GetId(), iter->second));
[email protected]82307f6b2014-08-07 03:30:12353 render_view_host_map_.erase(iter);
354 } else {
355 return iter->second;
356 }
[email protected]21b41c7e892014-02-28 01:52:24357 }
dcheng29f5a6c2015-08-31 21:43:27358 RenderViewHostImpl* rvh =
359 static_cast<RenderViewHostImpl*>(RenderViewHostFactory::Create(
360 site_instance, render_view_delegate_, render_widget_delegate_,
361 routing_id, main_frame_routing_id, swapped_out, hidden));
[email protected]94d0cc12013-12-18 00:07:41362
[email protected]21b41c7e892014-02-28 01:52:24363 render_view_host_map_[site_instance->GetId()] = rvh;
[email protected]94d0cc12013-12-18 00:07:41364 return rvh;
365}
366
[email protected]82307f6b2014-08-07 03:30:12367RenderViewHostImpl* FrameTree::GetRenderViewHost(SiteInstance* site_instance) {
[email protected]94d0cc12013-12-18 00:07:41368 RenderViewHostMap::iterator iter =
369 render_view_host_map_.find(site_instance->GetId());
[email protected]a1b99262013-12-27 21:56:22370 if (iter == render_view_host_map_.end())
creis6a93a812015-04-24 23:13:17371 return nullptr;
[email protected]21b41c7e892014-02-28 01:52:24372 return iter->second;
[email protected]94d0cc12013-12-18 00:07:41373}
374
naskof95ab0e2015-05-23 02:27:24375void FrameTree::AddRenderViewHostRef(RenderViewHostImpl* render_view_host) {
376 SiteInstance* site_instance = render_view_host->GetSiteInstance();
[email protected]94d0cc12013-12-18 00:07:41377 RenderViewHostMap::iterator iter =
378 render_view_host_map_.find(site_instance->GetId());
379 CHECK(iter != render_view_host_map_.end());
naskof95ab0e2015-05-23 02:27:24380 CHECK(iter->second == render_view_host);
[email protected]94d0cc12013-12-18 00:07:41381
[email protected]21b41c7e892014-02-28 01:52:24382 iter->second->increment_ref_count();
[email protected]94d0cc12013-12-18 00:07:41383}
384
naskof95ab0e2015-05-23 02:27:24385void FrameTree::ReleaseRenderViewHostRef(RenderViewHostImpl* render_view_host) {
386 SiteInstance* site_instance = render_view_host->GetSiteInstance();
avib7348942015-12-25 20:57:10387 int32_t site_instance_id = site_instance->GetId();
[email protected]94d0cc12013-12-18 00:07:41388 RenderViewHostMap::iterator iter =
[email protected]21b41c7e892014-02-28 01:52:24389 render_view_host_map_.find(site_instance_id);
naskof95ab0e2015-05-23 02:27:24390 if (iter != render_view_host_map_.end() && iter->second == render_view_host) {
[email protected]21b41c7e892014-02-28 01:52:24391 // Decrement the refcount and shutdown the RenderViewHost if no one else is
392 // using it.
393 CHECK_GT(iter->second->ref_count(), 0);
394 iter->second->decrement_ref_count();
395 if (iter->second->ref_count() == 0) {
avi85a4cef2015-12-18 20:13:37396 iter->second->ShutdownAndDestroy();
[email protected]21b41c7e892014-02-28 01:52:24397 render_view_host_map_.erase(iter);
398 }
399 } else {
400 // The RenderViewHost should be in the list of RenderViewHosts pending
401 // shutdown.
402 bool render_view_host_found = false;
403 std::pair<RenderViewHostMultiMap::iterator,
404 RenderViewHostMultiMap::iterator> result =
405 render_view_host_pending_shutdown_map_.equal_range(site_instance_id);
406 for (RenderViewHostMultiMap::iterator multi_iter = result.first;
407 multi_iter != result.second;
408 ++multi_iter) {
naskof95ab0e2015-05-23 02:27:24409 if (multi_iter->second != render_view_host)
[email protected]21b41c7e892014-02-28 01:52:24410 continue;
411 render_view_host_found = true;
[email protected]21b41c7e892014-02-28 01:52:24412 // Decrement the refcount and shutdown the RenderViewHost if no one else
413 // is using it.
naskof95ab0e2015-05-23 02:27:24414 CHECK_GT(render_view_host->ref_count(), 0);
415 render_view_host->decrement_ref_count();
416 if (render_view_host->ref_count() == 0) {
avi85a4cef2015-12-18 20:13:37417 render_view_host->ShutdownAndDestroy();
[email protected]21b41c7e892014-02-28 01:52:24418 render_view_host_pending_shutdown_map_.erase(multi_iter);
419 }
420 break;
421 }
422 CHECK(render_view_host_found);
[email protected]94d0cc12013-12-18 00:07:41423 }
424}
425
dmazzonie950ea232015-03-13 21:39:45426void FrameTree::FrameRemoved(FrameTreeNode* frame) {
nick53d5cbf2015-04-23 22:50:14427 if (frame->frame_tree_node_id() == focused_frame_tree_node_id_)
428 focused_frame_tree_node_id_ = -1;
429
dmazzonie950ea232015-03-13 21:39:45430 // No notification for the root frame.
clamy9dbf17e22015-03-31 13:37:08431 if (!frame->parent()) {
nick70b782d2015-10-06 17:37:04432 CHECK_EQ(frame, root_);
dmazzonie950ea232015-03-13 21:39:45433 return;
clamy9dbf17e22015-03-31 13:37:08434 }
dmazzonie950ea232015-03-13 21:39:45435
436 // Notify observers of the frame removal.
437 if (!on_frame_removed_.is_null())
438 on_frame_removed_.Run(frame->current_frame_host());
439}
440
fdegansa696e5112015-04-17 01:57:59441void FrameTree::UpdateLoadProgress() {
fdegans1d16355162015-03-26 11:58:34442 double progress = 0.0;
443 int frame_count = 0;
444
dcheng57e39e22016-01-21 00:25:38445 for (FrameTreeNode* node : Nodes()) {
446 // Ignore the current frame if it has not started loading.
447 if (!node->has_started_loading())
448 continue;
449
450 // Collect progress.
451 progress += node->loading_progress();
452 frame_count++;
453 }
454
fdegans1d16355162015-03-26 11:58:34455 if (frame_count != 0)
456 progress /= frame_count;
fdegansa696e5112015-04-17 01:57:59457
458 if (progress <= load_progress_)
459 return;
460 load_progress_ = progress;
461
462 // Notify the WebContents.
463 root_->navigator()->GetDelegate()->DidChangeLoadProgress();
fdegans1d16355162015-03-26 11:58:34464}
465
466void FrameTree::ResetLoadProgress() {
dcheng57e39e22016-01-21 00:25:38467 for (FrameTreeNode* node : Nodes())
468 node->reset_loading_progress();
fdegansa696e5112015-04-17 01:57:59469 load_progress_ = 0.0;
fdegans1d16355162015-03-26 11:58:34470}
471
clamy44e84ce2016-02-22 15:38:25472bool FrameTree::IsLoading() const {
473 for (const FrameTreeNode* node : ConstNodes()) {
dcheng57e39e22016-01-21 00:25:38474 if (node->IsLoading())
475 return true;
476 }
477 return false;
fdegans1d16355162015-03-26 11:58:34478}
479
alexmos3fcd0ca2015-10-23 18:18:33480void FrameTree::ReplicatePageFocus(bool is_focused) {
dcheng57e39e22016-01-21 00:25:38481 std::set<SiteInstance*> frame_tree_site_instances =
482 CollectSiteInstances(this);
alexmos3fcd0ca2015-10-23 18:18:33483
484 // Send the focus update to main frame's proxies in all SiteInstances of
485 // other frames in this FrameTree. Note that the main frame might also know
486 // about proxies in SiteInstances for frames in a different FrameTree (e.g.,
487 // for window.open), so we can't just iterate over its proxy_hosts_ in
488 // RenderFrameHostManager.
alexmos0d7e0b09b2015-10-29 22:11:48489 for (const auto& instance : frame_tree_site_instances)
490 SetPageFocus(instance, is_focused);
491}
alexmos3fcd0ca2015-10-23 18:18:33492
alexmos0d7e0b09b2015-10-29 22:11:48493void FrameTree::SetPageFocus(SiteInstance* instance, bool is_focused) {
494 RenderFrameHostManager* root_manager = root_->render_manager();
495
496 // This is only used to set page-level focus in cross-process subframes, and
497 // requests to set focus in main frame's SiteInstance are ignored.
498 if (instance != root_manager->current_frame_host()->GetSiteInstance()) {
alexmos3fcd0ca2015-10-23 18:18:33499 RenderFrameProxyHost* proxy =
alexmos0d7e0b09b2015-10-29 22:11:48500 root_manager->GetRenderFrameProxyHost(instance);
alexmos3fcd0ca2015-10-23 18:18:33501 proxy->Send(new InputMsg_SetFocus(proxy->GetRoutingID(), is_focused));
502 }
503}
504
[email protected]9b159a52013-10-03 17:24:55505} // namespace content