blob: 212aefa9f7ee06278b6ea57ee3783557eb99cc2c [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
fdegansa696e5112015-04-17 01:57:599#include "base/profiler/scoped_tracker.h"
[email protected]9b159a52013-10-03 17:24:5510#include "base/stl_util.h"
[email protected]94d0cc12013-12-18 00:07:4111#include "content/browser/frame_host/frame_tree.h"
clamydcb434c12015-04-16 19:29:1612#include "content/browser/frame_host/navigation_request.h"
[email protected]190b8c52013-11-09 01:35:4413#include "content/browser/frame_host/navigator.h"
[email protected]d4a8ca482013-10-30 21:06:4014#include "content/browser/frame_host/render_frame_host_impl.h"
[email protected]94d0cc12013-12-18 00:07:4115#include "content/browser/renderer_host/render_view_host_impl.h"
clamyf73862c42015-07-08 12:31:3316#include "content/common/frame_messages.h"
nickd30fd962015-07-27 21:51:0817#include "content/common/site_isolation_policy.h"
dmazzonie950ea232015-03-13 21:39:4518#include "content/public/browser/browser_thread.h"
carloskd80262f52015-12-16 14:40:3519#include "content/public/common/browser_side_navigation_policy.h"
[email protected]9b159a52013-10-03 17:24:5520
21namespace content {
22
dmazzonie950ea232015-03-13 21:39:4523namespace {
24
25// This is a global map between frame_tree_node_ids and pointers to
26// FrameTreeNodes.
rob97250742015-12-10 17:45:1527typedef base::hash_map<int, FrameTreeNode*> FrameTreeNodeIdMap;
dmazzonie950ea232015-03-13 21:39:4528
rob97250742015-12-10 17:45:1529base::LazyInstance<FrameTreeNodeIdMap> g_frame_tree_node_id_map =
dmazzonie950ea232015-03-13 21:39:4530 LAZY_INSTANCE_INITIALIZER;
31
fdegansa696e5112015-04-17 01:57:5932// These values indicate the loading progress status. The minimum progress
33// value matches what Blink's ProgressTracker has traditionally used for a
34// minimum progress value.
35const double kLoadingProgressNotStarted = 0.0;
36const double kLoadingProgressMinimum = 0.1;
37const double kLoadingProgressDone = 1.0;
dmazzonie950ea232015-03-13 21:39:4538
fdegansa696e5112015-04-17 01:57:5939} // namespace
fdegans1d16355162015-03-26 11:58:3440
alexmose201c7cd2015-06-10 17:14:2141// This observer watches the opener of its owner FrameTreeNode and clears the
42// owner's opener if the opener is destroyed.
43class FrameTreeNode::OpenerDestroyedObserver : public FrameTreeNode::Observer {
44 public:
45 OpenerDestroyedObserver(FrameTreeNode* owner) : owner_(owner) {}
46
47 // FrameTreeNode::Observer
48 void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
49 CHECK_EQ(owner_->opener(), node);
50 owner_->SetOpener(nullptr);
51 }
52
53 private:
54 FrameTreeNode* owner_;
55
56 DISALLOW_COPY_AND_ASSIGN(OpenerDestroyedObserver);
57};
58
vishal.b782eb5d2015-04-29 12:22:5759int FrameTreeNode::next_frame_tree_node_id_ = 1;
[email protected]9b159a52013-10-03 17:24:5560
dmazzonie950ea232015-03-13 21:39:4561// static
vishal.b782eb5d2015-04-29 12:22:5762FrameTreeNode* FrameTreeNode::GloballyFindByID(int frame_tree_node_id) {
mostynb366eaf12015-03-26 00:51:1963 DCHECK_CURRENTLY_ON(BrowserThread::UI);
rob97250742015-12-10 17:45:1564 FrameTreeNodeIdMap* nodes = g_frame_tree_node_id_map.Pointer();
65 FrameTreeNodeIdMap::iterator it = nodes->find(frame_tree_node_id);
dmazzonie950ea232015-03-13 21:39:4566 return it == nodes->end() ? nullptr : it->second;
67}
68
lazyboy70605c32015-11-03 01:27:3169FrameTreeNode::FrameTreeNode(
70 FrameTree* frame_tree,
71 Navigator* navigator,
72 RenderFrameHostDelegate* render_frame_delegate,
73 RenderViewHostDelegate* render_view_delegate,
74 RenderWidgetHostDelegate* render_widget_delegate,
75 RenderFrameHostManager::Delegate* manager_delegate,
76 blink::WebTreeScopeType scope,
77 const std::string& name,
78 blink::WebSandboxFlags sandbox_flags,
79 const blink::WebFrameOwnerProperties& frame_owner_properties)
[email protected]bffc8302014-01-23 20:52:1680 : frame_tree_(frame_tree),
81 navigator_(navigator),
82 render_manager_(this,
83 render_frame_delegate,
84 render_view_delegate,
85 render_widget_delegate,
86 manager_delegate),
87 frame_tree_node_id_(next_frame_tree_node_id_++),
naskoa7064ad6e2015-01-15 18:44:5688 parent_(NULL),
alexmose201c7cd2015-06-10 17:14:2189 opener_(nullptr),
90 opener_observer_(nullptr),
creisf0f069a2015-07-23 23:51:5391 has_committed_real_load_(false),
dcheng860817a2015-05-22 03:16:5692 replication_state_(scope, name, sandbox_flags),
alexmos6e0ee0c2015-05-01 18:57:3493 // Effective sandbox flags also need to be set, since initial sandbox
94 // flags should apply to the initial empty document in the frame.
95 effective_sandbox_flags_(sandbox_flags),
lazyboy70605c32015-11-03 01:27:3196 frame_owner_properties_(frame_owner_properties),
fdegans1d16355162015-03-26 11:58:3497 loading_progress_(kLoadingProgressNotStarted) {
rob97250742015-12-10 17:45:1598 std::pair<FrameTreeNodeIdMap::iterator, bool> result =
dmazzonie950ea232015-03-13 21:39:4599 g_frame_tree_node_id_map.Get().insert(
100 std::make_pair(frame_tree_node_id_, this));
101 CHECK(result.second);
alexmos998581d2015-01-22 01:01:59102}
[email protected]9b159a52013-10-03 17:24:55103
104FrameTreeNode::~FrameTreeNode() {
dmazzonie950ea232015-03-13 21:39:45105 frame_tree_->FrameRemoved(this);
alexmose201c7cd2015-06-10 17:14:21106 FOR_EACH_OBSERVER(Observer, observers_, OnFrameTreeNodeDestroyed(this));
107
108 if (opener_)
109 opener_->RemoveObserver(opener_observer_.get());
dmazzonie950ea232015-03-13 21:39:45110
111 g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
[email protected]9b159a52013-10-03 17:24:55112}
113
alexmose201c7cd2015-06-10 17:14:21114void FrameTreeNode::AddObserver(Observer* observer) {
115 observers_.AddObserver(observer);
116}
117
118void FrameTreeNode::RemoveObserver(Observer* observer) {
119 observers_.RemoveObserver(observer);
120}
121
[email protected]94d0cc12013-12-18 00:07:41122bool FrameTreeNode::IsMainFrame() const {
123 return frame_tree_->root() == this;
124}
125
126void FrameTreeNode::AddChild(scoped_ptr<FrameTreeNode> child,
dgroganfb22f9a2014-10-20 21:32:32127 int process_id,
[email protected]94d0cc12013-12-18 00:07:41128 int frame_routing_id) {
dgroganfb22f9a2014-10-20 21:32:32129 // Child frame must always be created in the same process as the parent.
130 CHECK_EQ(process_id, render_manager_.current_host()->GetProcess()->GetID());
creisd06a9422015-11-11 03:08:45131 child->set_parent(this);
dgroganfb22f9a2014-10-20 21:32:32132
[email protected]94d0cc12013-12-18 00:07:41133 // Initialize the RenderFrameHost for the new node. We always create child
134 // frames in the same SiteInstance as the current frame, and they can swap to
135 // a different one if they navigate away.
136 child->render_manager()->Init(
[email protected]94d0cc12013-12-18 00:07:41137 render_manager_.current_host()->GetSiteInstance(),
dcheng29f5a6c2015-08-31 21:43:27138 render_manager_.current_host()->GetRoutingID(), frame_routing_id,
piman5d36dae2015-09-24 22:47:05139 MSG_ROUTING_NONE);
alexmos46e85ec2015-04-03 21:04:35140
141 // Other renderer processes in this BrowsingInstance may need to find out
142 // about the new frame. Create a proxy for the child frame in all
143 // SiteInstances that have a proxy for the frame's parent, since all frames
144 // in a frame tree should have the same set of proxies.
nickd30fd962015-07-27 21:51:08145 // TODO(alexmos, nick): We ought to do this for non-oopif too, for openers.
146 if (SiteIsolationPolicy::AreCrossProcessFramesPossible())
alexmos46e85ec2015-04-03 21:04:35147 render_manager_.CreateProxiesForChildFrame(child.get());
148
nickb6769e632015-11-13 23:25:18149 children_.push_back(child.Pass());
[email protected]9b159a52013-10-03 17:24:55150}
151
[email protected]741fd682013-11-08 08:26:55152void FrameTreeNode::RemoveChild(FrameTreeNode* child) {
nickb6769e632015-11-13 23:25:18153 for (auto iter = children_.begin(); iter != children_.end(); ++iter) {
154 if (iter->get() == child) {
155 // Subtle: we need to make sure the node is gone from the tree before
156 // observers are notified of its deletion.
157 scoped_ptr<FrameTreeNode> node_to_delete(iter->Pass());
158 children_.erase(iter);
159 node_to_delete.reset();
160 return;
161 }
[email protected]bffc8302014-01-23 20:52:16162 }
[email protected]9b159a52013-10-03 17:24:55163}
164
[email protected]81c6c5e2014-02-13 20:20:07165void FrameTreeNode::ResetForNewProcess() {
[email protected]9b159a52013-10-03 17:24:55166 current_url_ = GURL();
[email protected]482ce3c2013-11-27 18:17:09167
nickb6769e632015-11-13 23:25:18168 // Remove child nodes from the tree, then delete them. This destruction
169 // operation will notify observers.
170 std::vector<scoped_ptr<FrameTreeNode>>().swap(children_);
[email protected]9b159a52013-10-03 17:24:55171}
172
alexmose201c7cd2015-06-10 17:14:21173void FrameTreeNode::SetOpener(FrameTreeNode* opener) {
174 if (opener_) {
175 opener_->RemoveObserver(opener_observer_.get());
176 opener_observer_.reset();
177 }
178
179 opener_ = opener;
180
181 if (opener_) {
182 if (!opener_observer_)
183 opener_observer_ = make_scoped_ptr(new OpenerDestroyedObserver(this));
184 opener_->AddObserver(opener_observer_.get());
185 }
186}
187
creisf0f069a2015-07-23 23:51:53188void FrameTreeNode::SetCurrentURL(const GURL& url) {
189 if (!has_committed_real_load_ && url != GURL(url::kAboutBlankURL))
190 has_committed_real_load_ = true;
191 current_url_ = url;
192}
193
mkwst13213f32015-07-27 07:06:27194void FrameTreeNode::SetCurrentOrigin(const url::Origin& origin) {
195 if (!origin.IsSameOriginWith(replication_state_.origin))
alexmosa7a4ff822015-04-27 17:59:56196 render_manager_.OnDidUpdateOrigin(origin);
197 replication_state_.origin = origin;
198}
alexmosbe2f4c32015-03-10 02:30:23199
alexmosa7a4ff822015-04-27 17:59:56200void FrameTreeNode::SetFrameName(const std::string& name) {
201 if (name != replication_state_.name)
202 render_manager_.OnDidUpdateName(name);
203 replication_state_.name = name;
alexmosbe2f4c32015-03-10 02:30:23204}
205
mlamouria85eb3f2015-01-26 17:36:27206bool FrameTreeNode::IsDescendantOf(FrameTreeNode* other) const {
207 if (!other || !other->child_count())
208 return false;
209
210 for (FrameTreeNode* node = parent(); node; node = node->parent()) {
211 if (node == other)
212 return true;
213 }
214
215 return false;
216}
217
alexmos9f8705a2015-05-06 19:58:59218FrameTreeNode* FrameTreeNode::PreviousSibling() const {
219 if (!parent_)
220 return nullptr;
221
222 for (size_t i = 0; i < parent_->child_count(); ++i) {
223 if (parent_->child_at(i) == this)
224 return (i == 0) ? nullptr : parent_->child_at(i - 1);
225 }
226
227 NOTREACHED() << "FrameTreeNode not found in its parent's children.";
228 return nullptr;
229}
230
fdegans4a49ce932015-03-12 17:11:37231bool FrameTreeNode::IsLoading() const {
232 RenderFrameHostImpl* current_frame_host =
233 render_manager_.current_frame_host();
234 RenderFrameHostImpl* pending_frame_host =
235 render_manager_.pending_frame_host();
236
237 DCHECK(current_frame_host);
fdegans39ff0382015-04-29 19:04:39238
carloskd80262f52015-12-16 14:40:35239 if (IsBrowserSideNavigationEnabled()) {
fdegans39ff0382015-04-29 19:04:39240 if (navigation_request_)
241 return true;
clamy11e11512015-07-07 16:42:17242
243 RenderFrameHostImpl* speculative_frame_host =
244 render_manager_.speculative_frame_host();
245 if (speculative_frame_host && speculative_frame_host->is_loading())
246 return true;
fdegans39ff0382015-04-29 19:04:39247 } else {
248 if (pending_frame_host && pending_frame_host->is_loading())
249 return true;
250 }
fdegans4a49ce932015-03-12 17:11:37251 return current_frame_host->is_loading();
252}
253
alexmos6b294562015-03-05 19:24:10254bool FrameTreeNode::CommitPendingSandboxFlags() {
255 bool did_change_flags =
256 effective_sandbox_flags_ != replication_state_.sandbox_flags;
257 effective_sandbox_flags_ = replication_state_.sandbox_flags;
258 return did_change_flags;
259}
260
carloskc49005eb2015-06-16 11:25:07261void FrameTreeNode::CreatedNavigationRequest(
clamydcb434c12015-04-16 19:29:16262 scoped_ptr<NavigationRequest> navigation_request) {
carloskd80262f52015-12-16 14:40:35263 CHECK(IsBrowserSideNavigationEnabled());
clamydcb434c12015-04-16 19:29:16264 ResetNavigationRequest(false);
fdegans39ff0382015-04-29 19:04:39265
266 // Force the throbber to start to keep it in sync with what is happening in
267 // the UI. Blink doesn't send throb notifications for JavaScript URLs, so it
268 // is not done here either.
269 if (!navigation_request->common_params().url.SchemeIs(
270 url::kJavaScriptScheme)) {
271 // TODO(fdegans): Check if this is a same-document navigation and set the
272 // proper argument.
273 DidStartLoading(true);
274 }
275
clamydcb434c12015-04-16 19:29:16276 navigation_request_ = navigation_request.Pass();
carloskc49005eb2015-06-16 11:25:07277
278 render_manager()->DidCreateNavigationRequest(*navigation_request_);
clamydcb434c12015-04-16 19:29:16279}
280
281void FrameTreeNode::ResetNavigationRequest(bool is_commit) {
carloskd80262f52015-12-16 14:40:35282 CHECK(IsBrowserSideNavigationEnabled());
fdegans39ff0382015-04-29 19:04:39283 if (!navigation_request_)
284 return;
clamydcb434c12015-04-16 19:29:16285 navigation_request_.reset();
fdegans39ff0382015-04-29 19:04:39286
287 // During commit, the clean up of a speculative RenderFrameHost is done in
288 // RenderFrameHostManager::DidNavigateFrame. The load is also still being
289 // tracked.
290 if (is_commit)
291 return;
292
293 // If the reset corresponds to a cancelation, the RenderFrameHostManager
294 // should clean up any speculative RenderFrameHost it created for the
295 // navigation.
296 DidStopLoading();
297 render_manager_.CleanUpNavigation();
clamydcb434c12015-04-16 19:29:16298}
299
fdegansa696e5112015-04-17 01:57:59300bool FrameTreeNode::has_started_loading() const {
301 return loading_progress_ != kLoadingProgressNotStarted;
302}
303
304void FrameTreeNode::reset_loading_progress() {
305 loading_progress_ = kLoadingProgressNotStarted;
306}
307
308void FrameTreeNode::DidStartLoading(bool to_different_document) {
309 // Any main frame load to a new document should reset the load progress since
310 // it will replace the current page and any frames. The WebContents will
311 // be notified when DidChangeLoadProgress is called.
312 if (to_different_document && IsMainFrame())
313 frame_tree_->ResetLoadProgress();
314
315 // Notify the WebContents.
316 if (!frame_tree_->IsLoading())
317 navigator()->GetDelegate()->DidStartLoading(this, to_different_document);
318
319 // Set initial load progress and update overall progress. This will notify
320 // the WebContents of the load progress change.
321 DidChangeLoadProgress(kLoadingProgressMinimum);
322
323 // Notify the RenderFrameHostManager of the event.
324 render_manager()->OnDidStartLoading();
325}
326
327void FrameTreeNode::DidStopLoading() {
328 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
329 tracked_objects::ScopedTracker tracking_profile1(
330 FROM_HERE_WITH_EXPLICIT_FUNCTION(
331 "465796 FrameTreeNode::DidStopLoading::Start"));
332
333 // Set final load progress and update overall progress. This will notify
334 // the WebContents of the load progress change.
335 DidChangeLoadProgress(kLoadingProgressDone);
336
337 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
338 tracked_objects::ScopedTracker tracking_profile2(
339 FROM_HERE_WITH_EXPLICIT_FUNCTION(
340 "465796 FrameTreeNode::DidStopLoading::WCIDidStopLoading"));
341
342 // Notify the WebContents.
343 if (!frame_tree_->IsLoading())
344 navigator()->GetDelegate()->DidStopLoading();
345
346 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
347 tracked_objects::ScopedTracker tracking_profile3(
348 FROM_HERE_WITH_EXPLICIT_FUNCTION(
349 "465796 FrameTreeNode::DidStopLoading::RFHMDidStopLoading"));
350
351 // Notify the RenderFrameHostManager of the event.
352 render_manager()->OnDidStopLoading();
353
354 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
355 tracked_objects::ScopedTracker tracking_profile4(
356 FROM_HERE_WITH_EXPLICIT_FUNCTION(
357 "465796 FrameTreeNode::DidStopLoading::End"));
358}
359
360void FrameTreeNode::DidChangeLoadProgress(double load_progress) {
361 loading_progress_ = load_progress;
362 frame_tree_->UpdateLoadProgress();
363}
364
clamyf73862c42015-07-08 12:31:33365bool FrameTreeNode::StopLoading() {
carloskd80262f52015-12-16 14:40:35366 if (IsBrowserSideNavigationEnabled())
clamyf73862c42015-07-08 12:31:33367 ResetNavigationRequest(false);
clamyf73862c42015-07-08 12:31:33368
369 // TODO(nasko): see if child frames should send IPCs in site-per-process
370 // mode.
371 if (!IsMainFrame())
372 return true;
373
374 render_manager_.Stop();
375 return true;
376}
377
alexmos21acae52015-11-07 01:04:43378void FrameTreeNode::DidFocus() {
379 last_focus_time_ = base::TimeTicks::Now();
380 FOR_EACH_OBSERVER(Observer, observers_, OnFrameTreeNodeFocused(this));
381}
382
[email protected]9b159a52013-10-03 17:24:55383} // namespace content