blob: e94c5d8160c04b1e869fe40d9bcc0f39aaa84a8a [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_node.h"
[email protected]9b159a52013-10-03 17:24:556
7#include <queue>
8
clamy71a42ec2014-10-02 18:43:229#include "base/command_line.h"
fdegansa696e5112015-04-17 01:57:5910#include "base/profiler/scoped_tracker.h"
[email protected]9b159a52013-10-03 17:24:5511#include "base/stl_util.h"
[email protected]94d0cc12013-12-18 00:07:4112#include "content/browser/frame_host/frame_tree.h"
clamydcb434c12015-04-16 19:29:1613#include "content/browser/frame_host/navigation_request.h"
[email protected]190b8c52013-11-09 01:35:4414#include "content/browser/frame_host/navigator.h"
[email protected]d4a8ca482013-10-30 21:06:4015#include "content/browser/frame_host/render_frame_host_impl.h"
[email protected]94d0cc12013-12-18 00:07:4116#include "content/browser/renderer_host/render_view_host_impl.h"
dmazzonie950ea232015-03-13 21:39:4517#include "content/public/browser/browser_thread.h"
clamy71a42ec2014-10-02 18:43:2218#include "content/public/common/content_switches.h"
[email protected]9b159a52013-10-03 17:24:5519
20namespace content {
21
dmazzonie950ea232015-03-13 21:39:4522namespace {
23
24// This is a global map between frame_tree_node_ids and pointers to
25// FrameTreeNodes.
vishal.b782eb5d2015-04-29 12:22:5726typedef base::hash_map<int, FrameTreeNode*> FrameTreeNodeIDMap;
dmazzonie950ea232015-03-13 21:39:4527
28base::LazyInstance<FrameTreeNodeIDMap> g_frame_tree_node_id_map =
29 LAZY_INSTANCE_INITIALIZER;
30
fdegansa696e5112015-04-17 01:57:5931// These values indicate the loading progress status. The minimum progress
32// value matches what Blink's ProgressTracker has traditionally used for a
33// minimum progress value.
34const double kLoadingProgressNotStarted = 0.0;
35const double kLoadingProgressMinimum = 0.1;
36const double kLoadingProgressDone = 1.0;
dmazzonie950ea232015-03-13 21:39:4537
fdegansa696e5112015-04-17 01:57:5938} // namespace
fdegans1d16355162015-03-26 11:58:3439
alexmose201c7cd2015-06-10 17:14:2140// This observer watches the opener of its owner FrameTreeNode and clears the
41// owner's opener if the opener is destroyed.
42class FrameTreeNode::OpenerDestroyedObserver : public FrameTreeNode::Observer {
43 public:
44 OpenerDestroyedObserver(FrameTreeNode* owner) : owner_(owner) {}
45
46 // FrameTreeNode::Observer
47 void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
48 CHECK_EQ(owner_->opener(), node);
49 owner_->SetOpener(nullptr);
50 }
51
52 private:
53 FrameTreeNode* owner_;
54
55 DISALLOW_COPY_AND_ASSIGN(OpenerDestroyedObserver);
56};
57
vishal.b782eb5d2015-04-29 12:22:5758int FrameTreeNode::next_frame_tree_node_id_ = 1;
[email protected]9b159a52013-10-03 17:24:5559
dmazzonie950ea232015-03-13 21:39:4560// static
vishal.b782eb5d2015-04-29 12:22:5761FrameTreeNode* FrameTreeNode::GloballyFindByID(int frame_tree_node_id) {
mostynb366eaf12015-03-26 00:51:1962 DCHECK_CURRENTLY_ON(BrowserThread::UI);
dmazzonie950ea232015-03-13 21:39:4563 FrameTreeNodeIDMap* nodes = g_frame_tree_node_id_map.Pointer();
64 FrameTreeNodeIDMap::iterator it = nodes->find(frame_tree_node_id);
65 return it == nodes->end() ? nullptr : it->second;
66}
67
[email protected]94d0cc12013-12-18 00:07:4168FrameTreeNode::FrameTreeNode(FrameTree* frame_tree,
69 Navigator* navigator,
[email protected]92404c62013-12-04 16:40:4670 RenderFrameHostDelegate* render_frame_delegate,
[email protected]fa944cb82013-11-15 17:51:2171 RenderViewHostDelegate* render_view_delegate,
72 RenderWidgetHostDelegate* render_widget_delegate,
[email protected]b0936d22013-11-28 06:47:3673 RenderFrameHostManager::Delegate* manager_delegate,
dcheng860817a2015-05-22 03:16:5674 blink::WebTreeScopeType scope,
alexmos6e0ee0c2015-05-01 18:57:3475 const std::string& name,
dcheng5f60abb2015-05-28 01:39:3676 blink::WebSandboxFlags sandbox_flags)
[email protected]bffc8302014-01-23 20:52:1677 : frame_tree_(frame_tree),
78 navigator_(navigator),
79 render_manager_(this,
80 render_frame_delegate,
81 render_view_delegate,
82 render_widget_delegate,
83 manager_delegate),
84 frame_tree_node_id_(next_frame_tree_node_id_++),
naskoa7064ad6e2015-01-15 18:44:5685 parent_(NULL),
alexmose201c7cd2015-06-10 17:14:2186 opener_(nullptr),
87 opener_observer_(nullptr),
dcheng860817a2015-05-22 03:16:5688 replication_state_(scope, name, sandbox_flags),
alexmos6e0ee0c2015-05-01 18:57:3489 // Effective sandbox flags also need to be set, since initial sandbox
90 // flags should apply to the initial empty document in the frame.
91 effective_sandbox_flags_(sandbox_flags),
fdegans1d16355162015-03-26 11:58:3492 loading_progress_(kLoadingProgressNotStarted) {
dmazzonie950ea232015-03-13 21:39:4593 std::pair<FrameTreeNodeIDMap::iterator, bool> result =
94 g_frame_tree_node_id_map.Get().insert(
95 std::make_pair(frame_tree_node_id_, this));
96 CHECK(result.second);
alexmos998581d2015-01-22 01:01:5997}
[email protected]9b159a52013-10-03 17:24:5598
99FrameTreeNode::~FrameTreeNode() {
dmazzonie950ea232015-03-13 21:39:45100 frame_tree_->FrameRemoved(this);
alexmose201c7cd2015-06-10 17:14:21101 FOR_EACH_OBSERVER(Observer, observers_, OnFrameTreeNodeDestroyed(this));
102
103 if (opener_)
104 opener_->RemoveObserver(opener_observer_.get());
dmazzonie950ea232015-03-13 21:39:45105
106 g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
[email protected]9b159a52013-10-03 17:24:55107}
108
alexmose201c7cd2015-06-10 17:14:21109void FrameTreeNode::AddObserver(Observer* observer) {
110 observers_.AddObserver(observer);
111}
112
113void FrameTreeNode::RemoveObserver(Observer* observer) {
114 observers_.RemoveObserver(observer);
115}
116
[email protected]94d0cc12013-12-18 00:07:41117bool FrameTreeNode::IsMainFrame() const {
118 return frame_tree_->root() == this;
119}
120
121void FrameTreeNode::AddChild(scoped_ptr<FrameTreeNode> child,
dgroganfb22f9a2014-10-20 21:32:32122 int process_id,
[email protected]94d0cc12013-12-18 00:07:41123 int frame_routing_id) {
dgroganfb22f9a2014-10-20 21:32:32124 // Child frame must always be created in the same process as the parent.
125 CHECK_EQ(process_id, render_manager_.current_host()->GetProcess()->GetID());
126
[email protected]94d0cc12013-12-18 00:07:41127 // Initialize the RenderFrameHost for the new node. We always create child
128 // frames in the same SiteInstance as the current frame, and they can swap to
129 // a different one if they navigate away.
130 child->render_manager()->Init(
131 render_manager_.current_host()->GetSiteInstance()->GetBrowserContext(),
132 render_manager_.current_host()->GetSiteInstance(),
133 render_manager_.current_host()->GetRoutingID(),
134 frame_routing_id);
[email protected]bffc8302014-01-23 20:52:16135 child->set_parent(this);
alexmos46e85ec2015-04-03 21:04:35136
137 // Other renderer processes in this BrowsingInstance may need to find out
138 // about the new frame. Create a proxy for the child frame in all
139 // SiteInstances that have a proxy for the frame's parent, since all frames
140 // in a frame tree should have the same set of proxies.
141 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
142 switches::kSitePerProcess))
143 render_manager_.CreateProxiesForChildFrame(child.get());
144
[email protected]9b159a52013-10-03 17:24:55145 children_.push_back(child.release());
146}
147
[email protected]741fd682013-11-08 08:26:55148void FrameTreeNode::RemoveChild(FrameTreeNode* child) {
[email protected]9b159a52013-10-03 17:24:55149 std::vector<FrameTreeNode*>::iterator iter;
[email protected]9b159a52013-10-03 17:24:55150 for (iter = children_.begin(); iter != children_.end(); ++iter) {
[email protected]741fd682013-11-08 08:26:55151 if ((*iter) == child)
[email protected]9b159a52013-10-03 17:24:55152 break;
153 }
154
[email protected]bffc8302014-01-23 20:52:16155 if (iter != children_.end()) {
[email protected]14266072014-04-19 00:35:20156 // Subtle: we need to make sure the node is gone from the tree before
157 // observers are notified of its deletion.
158 scoped_ptr<FrameTreeNode> node_to_delete(*iter);
159 children_.weak_erase(iter);
[email protected]14266072014-04-19 00:35:20160 node_to_delete.reset();
[email protected]bffc8302014-01-23 20:52:16161 }
[email protected]9b159a52013-10-03 17:24:55162}
163
[email protected]81c6c5e2014-02-13 20:20:07164void FrameTreeNode::ResetForNewProcess() {
[email protected]9b159a52013-10-03 17:24:55165 current_url_ = GURL();
[email protected]482ce3c2013-11-27 18:17:09166
167 // The children may not have been cleared if a cross-process navigation
168 // commits before the old process cleans everything up. Make sure the child
[email protected]81c6c5e2014-02-13 20:20:07169 // nodes get deleted before swapping to a new process.
[email protected]14266072014-04-19 00:35:20170 ScopedVector<FrameTreeNode> old_children = children_.Pass();
171 old_children.clear(); // May notify observers.
[email protected]9b159a52013-10-03 17:24:55172}
173
alexmose201c7cd2015-06-10 17:14:21174void FrameTreeNode::SetOpener(FrameTreeNode* opener) {
175 if (opener_) {
176 opener_->RemoveObserver(opener_observer_.get());
177 opener_observer_.reset();
178 }
179
180 opener_ = opener;
181
182 if (opener_) {
183 if (!opener_observer_)
184 opener_observer_ = make_scoped_ptr(new OpenerDestroyedObserver(this));
185 opener_->AddObserver(opener_observer_.get());
186 }
187}
188
alexmosa7a4ff822015-04-27 17:59:56189void FrameTreeNode::SetCurrentOrigin(const url::Origin& origin) {
190 if (!origin.IsSameAs(replication_state_.origin))
191 render_manager_.OnDidUpdateOrigin(origin);
192 replication_state_.origin = origin;
193}
alexmosbe2f4c32015-03-10 02:30:23194
alexmosa7a4ff822015-04-27 17:59:56195void FrameTreeNode::SetFrameName(const std::string& name) {
196 if (name != replication_state_.name)
197 render_manager_.OnDidUpdateName(name);
198 replication_state_.name = name;
alexmosbe2f4c32015-03-10 02:30:23199}
200
mlamouria85eb3f2015-01-26 17:36:27201bool FrameTreeNode::IsDescendantOf(FrameTreeNode* other) const {
202 if (!other || !other->child_count())
203 return false;
204
205 for (FrameTreeNode* node = parent(); node; node = node->parent()) {
206 if (node == other)
207 return true;
208 }
209
210 return false;
211}
212
alexmos9f8705a2015-05-06 19:58:59213FrameTreeNode* FrameTreeNode::PreviousSibling() const {
214 if (!parent_)
215 return nullptr;
216
217 for (size_t i = 0; i < parent_->child_count(); ++i) {
218 if (parent_->child_at(i) == this)
219 return (i == 0) ? nullptr : parent_->child_at(i - 1);
220 }
221
222 NOTREACHED() << "FrameTreeNode not found in its parent's children.";
223 return nullptr;
224}
225
fdegans4a49ce932015-03-12 17:11:37226bool FrameTreeNode::IsLoading() const {
227 RenderFrameHostImpl* current_frame_host =
228 render_manager_.current_frame_host();
229 RenderFrameHostImpl* pending_frame_host =
230 render_manager_.pending_frame_host();
231
232 DCHECK(current_frame_host);
fdegans39ff0382015-04-29 19:04:39233
234 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
235 switches::kEnableBrowserSideNavigation)) {
236 if (navigation_request_)
237 return true;
clamy11e11512015-07-07 16:42:17238
239 RenderFrameHostImpl* speculative_frame_host =
240 render_manager_.speculative_frame_host();
241 if (speculative_frame_host && speculative_frame_host->is_loading())
242 return true;
fdegans39ff0382015-04-29 19:04:39243 } else {
244 if (pending_frame_host && pending_frame_host->is_loading())
245 return true;
246 }
fdegans4a49ce932015-03-12 17:11:37247 return current_frame_host->is_loading();
248}
249
alexmos6b294562015-03-05 19:24:10250bool FrameTreeNode::CommitPendingSandboxFlags() {
251 bool did_change_flags =
252 effective_sandbox_flags_ != replication_state_.sandbox_flags;
253 effective_sandbox_flags_ = replication_state_.sandbox_flags;
254 return did_change_flags;
255}
256
carloskc49005eb2015-06-16 11:25:07257void FrameTreeNode::CreatedNavigationRequest(
clamydcb434c12015-04-16 19:29:16258 scoped_ptr<NavigationRequest> navigation_request) {
259 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
260 switches::kEnableBrowserSideNavigation));
261 ResetNavigationRequest(false);
fdegans39ff0382015-04-29 19:04:39262
263 // Force the throbber to start to keep it in sync with what is happening in
264 // the UI. Blink doesn't send throb notifications for JavaScript URLs, so it
265 // is not done here either.
266 if (!navigation_request->common_params().url.SchemeIs(
267 url::kJavaScriptScheme)) {
268 // TODO(fdegans): Check if this is a same-document navigation and set the
269 // proper argument.
270 DidStartLoading(true);
271 }
272
clamydcb434c12015-04-16 19:29:16273 navigation_request_ = navigation_request.Pass();
carloskc49005eb2015-06-16 11:25:07274
275 render_manager()->DidCreateNavigationRequest(*navigation_request_);
clamydcb434c12015-04-16 19:29:16276}
277
278void FrameTreeNode::ResetNavigationRequest(bool is_commit) {
279 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
280 switches::kEnableBrowserSideNavigation));
fdegans39ff0382015-04-29 19:04:39281 if (!navigation_request_)
282 return;
clamydcb434c12015-04-16 19:29:16283 navigation_request_.reset();
fdegans39ff0382015-04-29 19:04:39284
285 // During commit, the clean up of a speculative RenderFrameHost is done in
286 // RenderFrameHostManager::DidNavigateFrame. The load is also still being
287 // tracked.
288 if (is_commit)
289 return;
290
291 // If the reset corresponds to a cancelation, the RenderFrameHostManager
292 // should clean up any speculative RenderFrameHost it created for the
293 // navigation.
294 DidStopLoading();
295 render_manager_.CleanUpNavigation();
clamydcb434c12015-04-16 19:29:16296}
297
fdegansa696e5112015-04-17 01:57:59298bool FrameTreeNode::has_started_loading() const {
299 return loading_progress_ != kLoadingProgressNotStarted;
300}
301
302void FrameTreeNode::reset_loading_progress() {
303 loading_progress_ = kLoadingProgressNotStarted;
304}
305
306void FrameTreeNode::DidStartLoading(bool to_different_document) {
307 // Any main frame load to a new document should reset the load progress since
308 // it will replace the current page and any frames. The WebContents will
309 // be notified when DidChangeLoadProgress is called.
310 if (to_different_document && IsMainFrame())
311 frame_tree_->ResetLoadProgress();
312
313 // Notify the WebContents.
314 if (!frame_tree_->IsLoading())
315 navigator()->GetDelegate()->DidStartLoading(this, to_different_document);
316
317 // Set initial load progress and update overall progress. This will notify
318 // the WebContents of the load progress change.
319 DidChangeLoadProgress(kLoadingProgressMinimum);
320
321 // Notify the RenderFrameHostManager of the event.
322 render_manager()->OnDidStartLoading();
323}
324
325void FrameTreeNode::DidStopLoading() {
326 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
327 tracked_objects::ScopedTracker tracking_profile1(
328 FROM_HERE_WITH_EXPLICIT_FUNCTION(
329 "465796 FrameTreeNode::DidStopLoading::Start"));
330
331 // Set final load progress and update overall progress. This will notify
332 // the WebContents of the load progress change.
333 DidChangeLoadProgress(kLoadingProgressDone);
334
335 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
336 tracked_objects::ScopedTracker tracking_profile2(
337 FROM_HERE_WITH_EXPLICIT_FUNCTION(
338 "465796 FrameTreeNode::DidStopLoading::WCIDidStopLoading"));
339
340 // Notify the WebContents.
341 if (!frame_tree_->IsLoading())
342 navigator()->GetDelegate()->DidStopLoading();
343
344 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
345 tracked_objects::ScopedTracker tracking_profile3(
346 FROM_HERE_WITH_EXPLICIT_FUNCTION(
347 "465796 FrameTreeNode::DidStopLoading::RFHMDidStopLoading"));
348
349 // Notify the RenderFrameHostManager of the event.
350 render_manager()->OnDidStopLoading();
351
352 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
353 tracked_objects::ScopedTracker tracking_profile4(
354 FROM_HERE_WITH_EXPLICIT_FUNCTION(
355 "465796 FrameTreeNode::DidStopLoading::End"));
356}
357
358void FrameTreeNode::DidChangeLoadProgress(double load_progress) {
359 loading_progress_ = load_progress;
360 frame_tree_->UpdateLoadProgress();
361}
362
[email protected]9b159a52013-10-03 17:24:55363} // namespace content