Use blink::WebSandboxFlags directly in content.
[chromium-blink-merge.git] / content / browser / frame_host / frame_tree_node.cc
blob08254c9d2d44aafdbfd321f9c38e379bde819bee
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 int FrameTreeNode::next_frame_tree_node_id_ = 1;
42 // static
43 FrameTreeNode* FrameTreeNode::GloballyFindByID(int frame_tree_node_id) {
44 DCHECK_CURRENTLY_ON(BrowserThread::UI);
45 FrameTreeNodeIDMap* nodes = g_frame_tree_node_id_map.Pointer();
46 FrameTreeNodeIDMap::iterator it = nodes->find(frame_tree_node_id);
47 return it == nodes->end() ? nullptr : it->second;
50 FrameTreeNode::FrameTreeNode(FrameTree* frame_tree,
51 Navigator* navigator,
52 RenderFrameHostDelegate* render_frame_delegate,
53 RenderViewHostDelegate* render_view_delegate,
54 RenderWidgetHostDelegate* render_widget_delegate,
55 RenderFrameHostManager::Delegate* manager_delegate,
56 blink::WebTreeScopeType scope,
57 const std::string& name,
58 blink::WebSandboxFlags sandbox_flags)
59 : frame_tree_(frame_tree),
60 navigator_(navigator),
61 render_manager_(this,
62 render_frame_delegate,
63 render_view_delegate,
64 render_widget_delegate,
65 manager_delegate),
66 frame_tree_node_id_(next_frame_tree_node_id_++),
67 parent_(NULL),
68 replication_state_(scope, name, sandbox_flags),
69 // Effective sandbox flags also need to be set, since initial sandbox
70 // flags should apply to the initial empty document in the frame.
71 effective_sandbox_flags_(sandbox_flags),
72 loading_progress_(kLoadingProgressNotStarted) {
73 std::pair<FrameTreeNodeIDMap::iterator, bool> result =
74 g_frame_tree_node_id_map.Get().insert(
75 std::make_pair(frame_tree_node_id_, this));
76 CHECK(result.second);
79 FrameTreeNode::~FrameTreeNode() {
80 frame_tree_->FrameRemoved(this);
82 g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
85 bool FrameTreeNode::IsMainFrame() const {
86 return frame_tree_->root() == this;
89 void FrameTreeNode::AddChild(scoped_ptr<FrameTreeNode> child,
90 int process_id,
91 int frame_routing_id) {
92 // Child frame must always be created in the same process as the parent.
93 CHECK_EQ(process_id, render_manager_.current_host()->GetProcess()->GetID());
95 // Initialize the RenderFrameHost for the new node. We always create child
96 // frames in the same SiteInstance as the current frame, and they can swap to
97 // a different one if they navigate away.
98 child->render_manager()->Init(
99 render_manager_.current_host()->GetSiteInstance()->GetBrowserContext(),
100 render_manager_.current_host()->GetSiteInstance(),
101 render_manager_.current_host()->GetRoutingID(),
102 frame_routing_id);
103 child->set_parent(this);
105 // Other renderer processes in this BrowsingInstance may need to find out
106 // about the new frame. Create a proxy for the child frame in all
107 // SiteInstances that have a proxy for the frame's parent, since all frames
108 // in a frame tree should have the same set of proxies.
109 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
110 switches::kSitePerProcess))
111 render_manager_.CreateProxiesForChildFrame(child.get());
113 children_.push_back(child.release());
116 void FrameTreeNode::RemoveChild(FrameTreeNode* child) {
117 std::vector<FrameTreeNode*>::iterator iter;
118 for (iter = children_.begin(); iter != children_.end(); ++iter) {
119 if ((*iter) == child)
120 break;
123 if (iter != children_.end()) {
124 // Subtle: we need to make sure the node is gone from the tree before
125 // observers are notified of its deletion.
126 scoped_ptr<FrameTreeNode> node_to_delete(*iter);
127 children_.weak_erase(iter);
128 node_to_delete.reset();
132 void FrameTreeNode::ResetForNewProcess() {
133 current_url_ = GURL();
135 // The children may not have been cleared if a cross-process navigation
136 // commits before the old process cleans everything up. Make sure the child
137 // nodes get deleted before swapping to a new process.
138 ScopedVector<FrameTreeNode> old_children = children_.Pass();
139 old_children.clear(); // May notify observers.
142 void FrameTreeNode::SetCurrentOrigin(const url::Origin& origin) {
143 if (!origin.IsSameAs(replication_state_.origin))
144 render_manager_.OnDidUpdateOrigin(origin);
145 replication_state_.origin = origin;
148 void FrameTreeNode::SetFrameName(const std::string& name) {
149 if (name != replication_state_.name)
150 render_manager_.OnDidUpdateName(name);
151 replication_state_.name = name;
154 bool FrameTreeNode::IsDescendantOf(FrameTreeNode* other) const {
155 if (!other || !other->child_count())
156 return false;
158 for (FrameTreeNode* node = parent(); node; node = node->parent()) {
159 if (node == other)
160 return true;
163 return false;
166 FrameTreeNode* FrameTreeNode::PreviousSibling() const {
167 if (!parent_)
168 return nullptr;
170 for (size_t i = 0; i < parent_->child_count(); ++i) {
171 if (parent_->child_at(i) == this)
172 return (i == 0) ? nullptr : parent_->child_at(i - 1);
175 NOTREACHED() << "FrameTreeNode not found in its parent's children.";
176 return nullptr;
179 bool FrameTreeNode::IsLoading() const {
180 RenderFrameHostImpl* current_frame_host =
181 render_manager_.current_frame_host();
182 RenderFrameHostImpl* pending_frame_host =
183 render_manager_.pending_frame_host();
185 DCHECK(current_frame_host);
187 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
188 switches::kEnableBrowserSideNavigation)) {
189 if (navigation_request_)
190 return true;
191 } else {
192 if (pending_frame_host && pending_frame_host->is_loading())
193 return true;
195 return current_frame_host->is_loading();
198 bool FrameTreeNode::CommitPendingSandboxFlags() {
199 bool did_change_flags =
200 effective_sandbox_flags_ != replication_state_.sandbox_flags;
201 effective_sandbox_flags_ = replication_state_.sandbox_flags;
202 return did_change_flags;
205 void FrameTreeNode::SetNavigationRequest(
206 scoped_ptr<NavigationRequest> navigation_request) {
207 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
208 switches::kEnableBrowserSideNavigation));
209 ResetNavigationRequest(false);
211 // Force the throbber to start to keep it in sync with what is happening in
212 // the UI. Blink doesn't send throb notifications for JavaScript URLs, so it
213 // is not done here either.
214 if (!navigation_request->common_params().url.SchemeIs(
215 url::kJavaScriptScheme)) {
216 // TODO(fdegans): Check if this is a same-document navigation and set the
217 // proper argument.
218 DidStartLoading(true);
221 navigation_request_ = navigation_request.Pass();
224 void FrameTreeNode::ResetNavigationRequest(bool is_commit) {
225 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
226 switches::kEnableBrowserSideNavigation));
227 if (!navigation_request_)
228 return;
229 navigation_request_.reset();
231 // During commit, the clean up of a speculative RenderFrameHost is done in
232 // RenderFrameHostManager::DidNavigateFrame. The load is also still being
233 // tracked.
234 if (is_commit)
235 return;
237 // If the reset corresponds to a cancelation, the RenderFrameHostManager
238 // should clean up any speculative RenderFrameHost it created for the
239 // navigation.
240 DidStopLoading();
241 render_manager_.CleanUpNavigation();
244 bool FrameTreeNode::has_started_loading() const {
245 return loading_progress_ != kLoadingProgressNotStarted;
248 void FrameTreeNode::reset_loading_progress() {
249 loading_progress_ = kLoadingProgressNotStarted;
252 void FrameTreeNode::DidStartLoading(bool to_different_document) {
253 // Any main frame load to a new document should reset the load progress since
254 // it will replace the current page and any frames. The WebContents will
255 // be notified when DidChangeLoadProgress is called.
256 if (to_different_document && IsMainFrame())
257 frame_tree_->ResetLoadProgress();
259 // Notify the WebContents.
260 if (!frame_tree_->IsLoading())
261 navigator()->GetDelegate()->DidStartLoading(this, to_different_document);
263 // Set initial load progress and update overall progress. This will notify
264 // the WebContents of the load progress change.
265 DidChangeLoadProgress(kLoadingProgressMinimum);
267 // Notify the RenderFrameHostManager of the event.
268 render_manager()->OnDidStartLoading();
271 void FrameTreeNode::DidStopLoading() {
272 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
273 tracked_objects::ScopedTracker tracking_profile1(
274 FROM_HERE_WITH_EXPLICIT_FUNCTION(
275 "465796 FrameTreeNode::DidStopLoading::Start"));
277 // Set final load progress and update overall progress. This will notify
278 // the WebContents of the load progress change.
279 DidChangeLoadProgress(kLoadingProgressDone);
281 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
282 tracked_objects::ScopedTracker tracking_profile2(
283 FROM_HERE_WITH_EXPLICIT_FUNCTION(
284 "465796 FrameTreeNode::DidStopLoading::WCIDidStopLoading"));
286 // Notify the WebContents.
287 if (!frame_tree_->IsLoading())
288 navigator()->GetDelegate()->DidStopLoading();
290 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
291 tracked_objects::ScopedTracker tracking_profile3(
292 FROM_HERE_WITH_EXPLICIT_FUNCTION(
293 "465796 FrameTreeNode::DidStopLoading::RFHMDidStopLoading"));
295 // Notify the RenderFrameHostManager of the event.
296 render_manager()->OnDidStopLoading();
298 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
299 tracked_objects::ScopedTracker tracking_profile4(
300 FROM_HERE_WITH_EXPLICIT_FUNCTION(
301 "465796 FrameTreeNode::DidStopLoading::End"));
304 void FrameTreeNode::DidChangeLoadProgress(double load_progress) {
305 loading_progress_ = load_progress;
306 frame_tree_->UpdateLoadProgress();
309 } // namespace content