DevTools: cut host and port from webSocketDebuggerUrl in addition to ws:// prefix
[chromium-blink-merge.git] / content / browser / frame_host / frame_tree_node.cc
blob409a2a84932d6b0330cadc30c3eaa7e9121a972a
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_node.h"
7 #include <queue>
9 #include "base/command_line.h"
10 #include "base/profiler/scoped_tracker.h"
11 #include "base/stl_util.h"
12 #include "content/browser/frame_host/frame_tree.h"
13 #include "content/browser/frame_host/navigation_request.h"
14 #include "content/browser/frame_host/navigator.h"
15 #include "content/browser/frame_host/render_frame_host_impl.h"
16 #include "content/browser/renderer_host/render_view_host_impl.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/common/content_switches.h"
20 namespace content {
22 namespace {
24 // This is a global map between frame_tree_node_ids and pointers to
25 // FrameTreeNodes.
26 typedef base::hash_map<int, FrameTreeNode*> FrameTreeNodeIDMap;
28 base::LazyInstance<FrameTreeNodeIDMap> g_frame_tree_node_id_map =
29 LAZY_INSTANCE_INITIALIZER;
31 // 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.
34 const double kLoadingProgressNotStarted = 0.0;
35 const double kLoadingProgressMinimum = 0.1;
36 const double kLoadingProgressDone = 1.0;
38 } // namespace
40 // This observer watches the opener of its owner FrameTreeNode and clears the
41 // owner's opener if the opener is destroyed.
42 class FrameTreeNode::OpenerDestroyedObserver : public FrameTreeNode::Observer {
43 public:
44 OpenerDestroyedObserver(FrameTreeNode* owner) : owner_(owner) {}
46 // FrameTreeNode::Observer
47 void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
48 CHECK_EQ(owner_->opener(), node);
49 owner_->SetOpener(nullptr);
52 private:
53 FrameTreeNode* owner_;
55 DISALLOW_COPY_AND_ASSIGN(OpenerDestroyedObserver);
58 int FrameTreeNode::next_frame_tree_node_id_ = 1;
60 // static
61 FrameTreeNode* FrameTreeNode::GloballyFindByID(int frame_tree_node_id) {
62 DCHECK_CURRENTLY_ON(BrowserThread::UI);
63 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;
68 FrameTreeNode::FrameTreeNode(FrameTree* frame_tree,
69 Navigator* navigator,
70 RenderFrameHostDelegate* render_frame_delegate,
71 RenderViewHostDelegate* render_view_delegate,
72 RenderWidgetHostDelegate* render_widget_delegate,
73 RenderFrameHostManager::Delegate* manager_delegate,
74 blink::WebTreeScopeType scope,
75 const std::string& name,
76 blink::WebSandboxFlags sandbox_flags)
77 : 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_++),
85 parent_(NULL),
86 opener_(nullptr),
87 opener_observer_(nullptr),
88 replication_state_(scope, name, sandbox_flags),
89 // 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),
92 loading_progress_(kLoadingProgressNotStarted) {
93 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);
99 FrameTreeNode::~FrameTreeNode() {
100 frame_tree_->FrameRemoved(this);
101 FOR_EACH_OBSERVER(Observer, observers_, OnFrameTreeNodeDestroyed(this));
103 if (opener_)
104 opener_->RemoveObserver(opener_observer_.get());
106 g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
109 void FrameTreeNode::AddObserver(Observer* observer) {
110 observers_.AddObserver(observer);
113 void FrameTreeNode::RemoveObserver(Observer* observer) {
114 observers_.RemoveObserver(observer);
117 bool FrameTreeNode::IsMainFrame() const {
118 return frame_tree_->root() == this;
121 void FrameTreeNode::AddChild(scoped_ptr<FrameTreeNode> child,
122 int process_id,
123 int frame_routing_id) {
124 // Child frame must always be created in the same process as the parent.
125 CHECK_EQ(process_id, render_manager_.current_host()->GetProcess()->GetID());
127 // 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);
135 child->set_parent(this);
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());
145 children_.push_back(child.release());
148 void FrameTreeNode::RemoveChild(FrameTreeNode* child) {
149 std::vector<FrameTreeNode*>::iterator iter;
150 for (iter = children_.begin(); iter != children_.end(); ++iter) {
151 if ((*iter) == child)
152 break;
155 if (iter != children_.end()) {
156 // 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);
160 node_to_delete.reset();
164 void FrameTreeNode::ResetForNewProcess() {
165 current_url_ = GURL();
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
169 // nodes get deleted before swapping to a new process.
170 ScopedVector<FrameTreeNode> old_children = children_.Pass();
171 old_children.clear(); // May notify observers.
174 void FrameTreeNode::SetOpener(FrameTreeNode* opener) {
175 if (opener_) {
176 opener_->RemoveObserver(opener_observer_.get());
177 opener_observer_.reset();
180 opener_ = opener;
182 if (opener_) {
183 if (!opener_observer_)
184 opener_observer_ = make_scoped_ptr(new OpenerDestroyedObserver(this));
185 opener_->AddObserver(opener_observer_.get());
189 void FrameTreeNode::SetCurrentOrigin(const url::Origin& origin) {
190 if (!origin.IsSameAs(replication_state_.origin))
191 render_manager_.OnDidUpdateOrigin(origin);
192 replication_state_.origin = origin;
195 void FrameTreeNode::SetFrameName(const std::string& name) {
196 if (name != replication_state_.name)
197 render_manager_.OnDidUpdateName(name);
198 replication_state_.name = name;
201 bool FrameTreeNode::IsDescendantOf(FrameTreeNode* other) const {
202 if (!other || !other->child_count())
203 return false;
205 for (FrameTreeNode* node = parent(); node; node = node->parent()) {
206 if (node == other)
207 return true;
210 return false;
213 FrameTreeNode* FrameTreeNode::PreviousSibling() const {
214 if (!parent_)
215 return nullptr;
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);
222 NOTREACHED() << "FrameTreeNode not found in its parent's children.";
223 return nullptr;
226 bool 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();
232 DCHECK(current_frame_host);
234 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
235 switches::kEnableBrowserSideNavigation)) {
236 if (navigation_request_)
237 return true;
238 } else {
239 if (pending_frame_host && pending_frame_host->is_loading())
240 return true;
242 return current_frame_host->is_loading();
245 bool FrameTreeNode::CommitPendingSandboxFlags() {
246 bool did_change_flags =
247 effective_sandbox_flags_ != replication_state_.sandbox_flags;
248 effective_sandbox_flags_ = replication_state_.sandbox_flags;
249 return did_change_flags;
252 void FrameTreeNode::CreatedNavigationRequest(
253 scoped_ptr<NavigationRequest> navigation_request) {
254 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
255 switches::kEnableBrowserSideNavigation));
256 ResetNavigationRequest(false);
258 // Force the throbber to start to keep it in sync with what is happening in
259 // the UI. Blink doesn't send throb notifications for JavaScript URLs, so it
260 // is not done here either.
261 if (!navigation_request->common_params().url.SchemeIs(
262 url::kJavaScriptScheme)) {
263 // TODO(fdegans): Check if this is a same-document navigation and set the
264 // proper argument.
265 DidStartLoading(true);
268 navigation_request_ = navigation_request.Pass();
270 render_manager()->DidCreateNavigationRequest(*navigation_request_);
273 void FrameTreeNode::ResetNavigationRequest(bool is_commit) {
274 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
275 switches::kEnableBrowserSideNavigation));
276 if (!navigation_request_)
277 return;
278 navigation_request_.reset();
280 // During commit, the clean up of a speculative RenderFrameHost is done in
281 // RenderFrameHostManager::DidNavigateFrame. The load is also still being
282 // tracked.
283 if (is_commit)
284 return;
286 // If the reset corresponds to a cancelation, the RenderFrameHostManager
287 // should clean up any speculative RenderFrameHost it created for the
288 // navigation.
289 DidStopLoading();
290 render_manager_.CleanUpNavigation();
293 bool FrameTreeNode::has_started_loading() const {
294 return loading_progress_ != kLoadingProgressNotStarted;
297 void FrameTreeNode::reset_loading_progress() {
298 loading_progress_ = kLoadingProgressNotStarted;
301 void FrameTreeNode::DidStartLoading(bool to_different_document) {
302 // Any main frame load to a new document should reset the load progress since
303 // it will replace the current page and any frames. The WebContents will
304 // be notified when DidChangeLoadProgress is called.
305 if (to_different_document && IsMainFrame())
306 frame_tree_->ResetLoadProgress();
308 // Notify the WebContents.
309 if (!frame_tree_->IsLoading())
310 navigator()->GetDelegate()->DidStartLoading(this, to_different_document);
312 // Set initial load progress and update overall progress. This will notify
313 // the WebContents of the load progress change.
314 DidChangeLoadProgress(kLoadingProgressMinimum);
316 // Notify the RenderFrameHostManager of the event.
317 render_manager()->OnDidStartLoading();
320 void FrameTreeNode::DidStopLoading() {
321 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
322 tracked_objects::ScopedTracker tracking_profile1(
323 FROM_HERE_WITH_EXPLICIT_FUNCTION(
324 "465796 FrameTreeNode::DidStopLoading::Start"));
326 // Set final load progress and update overall progress. This will notify
327 // the WebContents of the load progress change.
328 DidChangeLoadProgress(kLoadingProgressDone);
330 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
331 tracked_objects::ScopedTracker tracking_profile2(
332 FROM_HERE_WITH_EXPLICIT_FUNCTION(
333 "465796 FrameTreeNode::DidStopLoading::WCIDidStopLoading"));
335 // Notify the WebContents.
336 if (!frame_tree_->IsLoading())
337 navigator()->GetDelegate()->DidStopLoading();
339 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
340 tracked_objects::ScopedTracker tracking_profile3(
341 FROM_HERE_WITH_EXPLICIT_FUNCTION(
342 "465796 FrameTreeNode::DidStopLoading::RFHMDidStopLoading"));
344 // Notify the RenderFrameHostManager of the event.
345 render_manager()->OnDidStopLoading();
347 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
348 tracked_objects::ScopedTracker tracking_profile4(
349 FROM_HERE_WITH_EXPLICIT_FUNCTION(
350 "465796 FrameTreeNode::DidStopLoading::End"));
353 void FrameTreeNode::DidChangeLoadProgress(double load_progress) {
354 loading_progress_ = load_progress;
355 frame_tree_->UpdateLoadProgress();
358 } // namespace content