blob: ec42d954638dbe13b71ebe8a1ee36e8f23398a53 [file] [log] [blame]
danakjc492bf82020-09-09 20:02:441// 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
5#ifndef CONTENT_BROWSER_RENDERER_HOST_FRAME_TREE_H_
6#define CONTENT_BROWSER_RENDERER_HOST_FRAME_TREE_H_
7
8#include <stdint.h>
9
10#include <iterator>
11#include <memory>
12#include <string>
13#include <unordered_map>
14
15#include "base/callback.h"
16#include "base/containers/queue.h"
Carlos Caballero101ac26b2021-03-24 11:54:0517#include "base/dcheck_is_on.h"
danakjc492bf82020-09-09 20:02:4418#include "base/gtest_prod_util.h"
19#include "base/macros.h"
20#include "content/browser/renderer_host/navigator.h"
21#include "content/browser/renderer_host/navigator_delegate.h"
22#include "content/browser/renderer_host/render_frame_host_manager.h"
23#include "content/common/content_export.h"
24#include "mojo/public/cpp/bindings/pending_receiver.h"
25#include "services/service_manager/public/mojom/interface_provider.mojom.h"
Chris Hamilton3ff6ed0e2021-02-19 03:54:0426#include "third_party/blink/public/common/tokens/tokens.h"
danakjc492bf82020-09-09 20:02:4427#include "third_party/blink/public/mojom/frame/frame_owner_element_type.mojom.h"
28#include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom-forward.h"
29
30namespace blink {
31struct FramePolicy;
32} // namespace blink
33
34namespace content {
35
Carlos Caballero40b0efd2021-01-26 11:55:0036class BrowserContext;
Jeremy Roman2d8dfe132021-07-06 20:51:2637class PageDelegate;
danakjc492bf82020-09-09 20:02:4438class RenderFrameHostDelegate;
39class RenderViewHostDelegate;
40class RenderViewHostImpl;
41class RenderFrameHostManager;
42class RenderWidgetHostDelegate;
Carlos Caballero40b0efd2021-01-26 11:55:0043class SiteInstance;
danakjc492bf82020-09-09 20:02:4444
45// Represents the frame tree for a page. With the exception of the main frame,
46// all FrameTreeNodes will be created/deleted in response to frame attach and
47// detach events in the DOM.
48//
49// The main frame's FrameTreeNode is special in that it is reused. This allows
50// it to serve as an anchor for state that needs to persist across top-level
51// page navigations.
52//
53// TODO(ajwong): Move NavigationController ownership to the main frame
54// FrameTreeNode. Possibly expose access to it from here.
55//
56// This object is only used on the UI thread.
57class CONTENT_EXPORT FrameTree {
58 public:
59 class NodeRange;
60
61 class CONTENT_EXPORT NodeIterator
62 : public std::iterator<std::forward_iterator_tag, FrameTreeNode> {
63 public:
64 NodeIterator(const NodeIterator& other);
65 ~NodeIterator();
66
67 NodeIterator& operator++();
Kevin McNee5f594382021-05-06 23:18:2368 // Advances the iterator and excludes the children of the current node
69 NodeIterator& AdvanceSkippingChildren();
danakjc492bf82020-09-09 20:02:4470
71 bool operator==(const NodeIterator& rhs) const;
72 bool operator!=(const NodeIterator& rhs) const { return !(*this == rhs); }
73
74 FrameTreeNode* operator*() { return current_node_; }
75
76 private:
77 friend class NodeRange;
78
Kevin McNee5f594382021-05-06 23:18:2379 NodeIterator(const std::vector<FrameTreeNode*>& starting_nodes,
80 const FrameTreeNode* root_of_subtree_to_skip,
81 bool should_descend_into_inner_trees);
82
83 void AdvanceNode();
danakjc492bf82020-09-09 20:02:4484
85 FrameTreeNode* current_node_;
Kevin McNee5f594382021-05-06 23:18:2386 const FrameTreeNode* const root_of_subtree_to_skip_;
87 const bool should_descend_into_inner_trees_;
danakjc492bf82020-09-09 20:02:4488 base::queue<FrameTreeNode*> queue_;
89 };
90
91 class CONTENT_EXPORT NodeRange {
92 public:
Kevin McNee5f594382021-05-06 23:18:2393 NodeRange(const NodeRange&);
94 ~NodeRange();
95
danakjc492bf82020-09-09 20:02:4496 NodeIterator begin();
97 NodeIterator end();
98
99 private:
100 friend class FrameTree;
101
Kevin McNee5f594382021-05-06 23:18:23102 NodeRange(const std::vector<FrameTreeNode*>& starting_nodes,
103 const FrameTreeNode* root_of_subtree_to_skip,
104 bool should_descend_into_inner_trees);
danakjc492bf82020-09-09 20:02:44105
Kevin McNee5f594382021-05-06 23:18:23106 const std::vector<FrameTreeNode*> starting_nodes_;
107 const FrameTreeNode* const root_of_subtree_to_skip_;
108 const bool should_descend_into_inner_trees_;
danakjc492bf82020-09-09 20:02:44109 };
110
Carlos Caballero03262522021-02-05 14:49:58111 class CONTENT_EXPORT Delegate {
112 public:
113 // A RenderFrameHost in the specified |frame_tree_node| started loading a
114 // new document. This corresponds to browser UI starting to show a spinner
115 // or other visual indicator for loading. This method is only invoked if the
116 // FrameTree hadn't been previously loading. |to_different_document| will be
117 // true unless the load is a fragment navigation, or triggered by
118 // history.pushState/replaceState.
119 virtual void DidStartLoading(FrameTreeNode* frame_tree_node,
120 bool to_different_document) = 0;
121
Takashi Toyoshima74090df62021-03-09 14:34:57122 // This is called when all nodes in the FrameTree stopped loading. This
Carlos Caballero03262522021-02-05 14:49:58123 // corresponds to the browser UI stop showing a spinner or other visual
124 // indicator for loading.
125 virtual void DidStopLoading() = 0;
126
127 // The load progress was changed.
128 virtual void DidChangeLoadProgress() = 0;
Carlos Caballero6ff6ace2021-02-05 16:53:00129
130 // Returns true when the active RenderWidgetHostView should be hidden.
131 virtual bool IsHidden() = 0;
Sreeja Kamishettya21b4f62021-06-25 07:48:25132
133 // Called when current Page of this frame tree changes.
134 virtual void NotifyPageChanged() = 0;
Carlos Caballero03262522021-02-05 14:49:58135 };
136
Sreeja Kamishetty74bacd522021-03-22 17:04:24137 // Type of FrameTree instance.
138 enum class Type {
139 // This FrameTree is the primary frame tree for the WebContents, whose main
140 // document URL is shown in the Omnibox.
141 kPrimary,
142
143 // This FrameTree is used to prerender a page in the background which is
144 // invisible to the user.
145 kPrerender
146 };
Sreeja Kamishetty837a10402021-04-23 12:41:59147
148 // A set of delegates are remembered here so that we can create
149 // RenderFrameHostManagers.
150 FrameTree(BrowserContext* browser_context,
151 Delegate* delegate,
152 NavigationControllerDelegate* navigation_controller_delegate,
153 NavigatorDelegate* navigator_delegate,
154 RenderFrameHostDelegate* render_frame_delegate,
155 RenderViewHostDelegate* render_view_delegate,
156 RenderWidgetHostDelegate* render_widget_delegate,
157 RenderFrameHostManager::Delegate* manager_delegate,
Jeremy Roman2d8dfe132021-07-06 20:51:26158 PageDelegate* page_delegate,
Sreeja Kamishetty837a10402021-04-23 12:41:59159 Type type);
160 ~FrameTree();
Sreeja Kamishetty74bacd522021-03-22 17:04:24161
Carlos Caballero40b0efd2021-01-26 11:55:00162 // Initializes the main frame for this FrameTree. That is it creates the
163 // initial RenderFrameHost in the root node's RenderFrameHostManager. This
164 // method will call back into the delegates so it should only be called once
165 // they have completed their initialization.
166 // TODO(carlscab): It would be great if initialization could happened in the
167 // constructor so we do not leave objects in a half initialized state.
168 void Init(SiteInstance* main_frame_site_instance,
169 bool renderer_initiated_creation,
Sreeja Kamishetty837a10402021-04-23 12:41:59170 const std::string& main_frame_name);
171
172 Type type() const { return type_; }
Carlos Caballero40b0efd2021-01-26 11:55:00173
danakjc492bf82020-09-09 20:02:44174 FrameTreeNode* root() const { return root_; }
175
Sreeja Kamishetty74bacd522021-03-22 17:04:24176 bool is_prerendering() const { return type_ == FrameTree::Type::kPrerender; }
Sreeja Kamishetty46f762c2021-02-05 07:52:46177
Carlos Caballero03262522021-02-05 14:49:58178 Delegate* delegate() { return delegate_; }
179
Jeremy Roman2d8dfe132021-07-06 20:51:26180 // Delegates for various objects. These can be kept centrally on the
181 // FrameTree because they are expected to be the same for all frames on a
182 // given FrameTree.
danakjc492bf82020-09-09 20:02:44183 RenderFrameHostDelegate* render_frame_delegate() {
184 return render_frame_delegate_;
185 }
186 RenderViewHostDelegate* render_view_delegate() {
187 return render_view_delegate_;
188 }
189 RenderWidgetHostDelegate* render_widget_delegate() {
190 return render_widget_delegate_;
191 }
192 RenderFrameHostManager::Delegate* manager_delegate() {
193 return manager_delegate_;
194 }
Jeremy Roman2d8dfe132021-07-06 20:51:26195 PageDelegate* page_delegate() { return page_delegate_; }
Aaron Colwell78b4bde2021-03-16 16:16:09196
Albert J. Wong1b6dc962021-07-09 18:06:57197 using RenderViewHostMapId = base::IdType32<class RenderViewHostMap>;
Aaron Colwell78b4bde2021-03-16 16:16:09198 using RenderViewHostMap = std::unordered_map<RenderViewHostMapId,
199 RenderViewHostImpl*,
200 RenderViewHostMapId::Hasher>;
201 const RenderViewHostMap& render_view_hosts() const {
danakjc492bf82020-09-09 20:02:44202 return render_view_host_map_;
203 }
204
205 // Returns the FrameTreeNode with the given |frame_tree_node_id| if it is part
206 // of this FrameTree.
207 FrameTreeNode* FindByID(int frame_tree_node_id);
208
209 // Returns the FrameTreeNode with the given renderer-specific |routing_id|.
210 FrameTreeNode* FindByRoutingID(int process_id, int routing_id);
211
212 // Returns the first frame in this tree with the given |name|, or the main
213 // frame if |name| is empty.
214 // Note that this does NOT support pseudo-names like _self, _top, and _blank,
215 // nor searching other FrameTrees (unlike blink::WebView::findFrameByName).
216 FrameTreeNode* FindByName(const std::string& name);
217
218 // Returns a range to iterate over all FrameTreeNodes in the frame tree in
219 // breadth-first traversal order.
220 NodeRange Nodes();
221
222 // Returns a range to iterate over all FrameTreeNodes in a subtree of the
223 // frame tree, starting from |subtree_root|.
224 NodeRange SubtreeNodes(FrameTreeNode* subtree_root);
225
Kevin McNee5f594382021-05-06 23:18:23226 // Returns a range to iterate over all FrameTreeNodes in a subtree, starting
227 // from, but not including |parent|, as well as any FrameTreeNodes of inner
228 // frame trees.
229 static NodeRange SubtreeAndInnerTreeNodes(RenderFrameHostImpl* parent);
230
danakjc492bf82020-09-09 20:02:44231 // Adds a new child frame to the frame tree. |process_id| is required to
232 // disambiguate |new_routing_id|, and it must match the process of the
233 // |parent| node. Otherwise no child is added and this method returns false.
234 // |interface_provider_receiver| is the receiver end of the InterfaceProvider
235 // interface through which the child RenderFrame can access Mojo services
236 // exposed by the corresponding RenderFrameHost. The caller takes care of
Antonio Sartoridb967c52021-01-20 09:54:30237 // sending the client end of the interface down to the
238 // RenderFrame. |policy_container_bind_params|, if not null, is used for
239 // binding Blink's policy container to the new RenderFrameHost's
240 // PolicyContainerHost. This is only needed if this frame is the result of the
241 // CreateChildFrame mojo call, which also delivers the
242 // |policy_container_bind_params|.
danakjc492bf82020-09-09 20:02:44243 FrameTreeNode* AddFrame(
244 RenderFrameHostImpl* parent,
245 int process_id,
246 int new_routing_id,
danakj0bdfacd2021-01-20 19:27:18247 mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
danakjc492bf82020-09-09 20:02:44248 mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
249 browser_interface_broker_receiver,
Antonio Sartoridb967c52021-01-20 09:54:30250 blink::mojom::PolicyContainerBindParamsPtr policy_container_bind_params,
danakjc492bf82020-09-09 20:02:44251 blink::mojom::TreeScopeType scope,
252 const std::string& frame_name,
253 const std::string& frame_unique_name,
254 bool is_created_by_script,
Chris Hamilton3ff6ed0e2021-02-19 03:54:04255 const blink::LocalFrameToken& frame_token,
danakjc492bf82020-09-09 20:02:44256 const base::UnguessableToken& devtools_frame_token,
257 const blink::FramePolicy& frame_policy,
258 const blink::mojom::FrameOwnerProperties& frame_owner_properties,
259 bool was_discarded,
260 blink::mojom::FrameOwnerElementType owner_type);
261
262 // Removes a frame from the frame tree. |child|, its children, and objects
263 // owned by their RenderFrameHostManagers are immediately deleted. The root
264 // node cannot be removed this way.
265 void RemoveFrame(FrameTreeNode* child);
266
267 // This method walks the entire frame tree and creates a RenderFrameProxyHost
268 // for the given |site_instance| in each node except the |source| one --
269 // the source will have a RenderFrameHost. |source| may be null if there is
270 // no node navigating in this frame tree (such as when this is called
271 // for an opener's frame tree), in which case no nodes are skipped for
272 // RenderFrameProxyHost creation.
273 void CreateProxiesForSiteInstance(FrameTreeNode* source,
274 SiteInstance* site_instance);
275
276 // Convenience accessor for the main frame's RenderFrameHostImpl.
277 RenderFrameHostImpl* GetMainFrame() const;
278
279 // Returns the focused frame.
280 FrameTreeNode* GetFocusedFrame();
281
282 // Sets the focused frame to |node|. |source| identifies the SiteInstance
283 // that initiated this focus change. If this FrameTree has SiteInstances
284 // other than |source|, those SiteInstances will be notified about the new
285 // focused frame. Note that |source| may differ from |node|'s current
286 // SiteInstance (e.g., this happens for cross-process window.focus() calls).
287 void SetFocusedFrame(FrameTreeNode* node, SiteInstance* source);
288
danakjc492bf82020-09-09 20:02:44289 // Creates a RenderViewHostImpl for a given |site_instance| in the tree.
290 //
291 // The RenderFrameHostImpls and the RenderFrameProxyHosts will share ownership
292 // of this object.
293 scoped_refptr<RenderViewHostImpl> CreateRenderViewHost(
294 SiteInstance* site_instance,
295 int32_t main_frame_routing_id,
danakj08eb51d2020-12-30 20:15:23296 bool swapped_out,
297 bool renderer_initiated_creation);
danakjc492bf82020-09-09 20:02:44298
299 // Returns the existing RenderViewHost for a new RenderFrameHost.
300 // There should always be such a RenderViewHost, because the main frame
301 // RenderFrameHost for each SiteInstance should be created before subframes.
302 scoped_refptr<RenderViewHostImpl> GetRenderViewHost(
303 SiteInstance* site_instance);
304
Aaron Colwell78b4bde2021-03-16 16:16:09305 // Returns the ID used for the RenderViewHost associated with |site_instance|.
306 // Note: Callers should not assume that there is a 1:1 mapping between
307 // SiteInstances and IDs returned by this function, since several
308 // SiteInstances may share a RenderViewHost.
309 RenderViewHostMapId GetRenderViewHostMapId(SiteInstance* site_instance) const;
310
danakjc492bf82020-09-09 20:02:44311 // Registers a RenderViewHost so that it can be reused by other frames
Aaron Colwell78b4bde2021-03-16 16:16:09312 // whose SiteInstance maps to the same RenderViewHostMapId.
danakjc492bf82020-09-09 20:02:44313 //
314 // This method does not take ownership of|rvh|.
315 //
316 // NOTE: This method CHECK fails if a RenderViewHost is already registered for
317 // |rvh|'s SiteInstance.
318 //
319 // ALSO NOTE: After calling RegisterRenderViewHost, UnregisterRenderViewHost
320 // *must* be called for |rvh| when it is destroyed or put into the
321 // BackForwardCache, to prevent FrameTree::CreateRenderViewHost from trying to
322 // reuse it.
Aaron Colwell78b4bde2021-03-16 16:16:09323 void RegisterRenderViewHost(RenderViewHostMapId id, RenderViewHostImpl* rvh);
danakjc492bf82020-09-09 20:02:44324
325 // Unregisters the RenderViewHostImpl that's available for reuse for a
Aaron Colwell78b4bde2021-03-16 16:16:09326 // particular RenderViewHostMapId. NOTE: This method CHECK fails if it is
327 // called for a |render_view_host| that is not currently set for reuse.
328 void UnregisterRenderViewHost(RenderViewHostMapId id,
Aaron Colwellc4bd7d62021-01-29 04:23:13329 RenderViewHostImpl* render_view_host);
danakjc492bf82020-09-09 20:02:44330
331 // This is called when the frame is about to be removed and started to run
332 // unload handlers.
333 void FrameUnloading(FrameTreeNode* frame);
334
335 // This is only meant to be called by FrameTreeNode. Triggers calling
336 // the listener installed by SetFrameRemoveListener.
337 void FrameRemoved(FrameTreeNode* frame);
338
Carlos Caballero03262522021-02-05 14:49:58339 void DidStartLoadingNode(FrameTreeNode& node,
340 bool to_different_document,
341 bool was_previously_loading);
342 void DidStopLoadingNode(FrameTreeNode& node);
343 void DidChangeLoadProgressForNode(FrameTreeNode& node, double load_progress);
344 void DidCancelLoading();
danakjc492bf82020-09-09 20:02:44345
346 // Returns this FrameTree's total load progress.
347 double load_progress() const { return load_progress_; }
348
349 // Resets the load progress on all nodes in this FrameTree.
350 void ResetLoadProgress();
351
352 // Returns true if at least one of the nodes in this FrameTree is loading.
353 bool IsLoading() const;
354
355 // Set page-level focus in all SiteInstances involved in rendering
356 // this FrameTree, not including the current main frame's
357 // SiteInstance. The focus update will be sent via the main frame's proxies
358 // in those SiteInstances.
359 void ReplicatePageFocus(bool is_focused);
360
361 // Updates page-level focus for this FrameTree in the subframe renderer
362 // identified by |instance|.
363 void SetPageFocus(SiteInstance* instance, bool is_focused);
364
365 // Walks the current frame tree and registers any origins matching |origin|,
366 // either the last committed origin of a RenderFrameHost or the origin
367 // associated with a NavigationRequest that has been assigned to a
368 // SiteInstance, as not-opted-in for origin isolation.
369 void RegisterExistingOriginToPreventOptInIsolation(
370 const url::Origin& previously_visited_origin,
371 NavigationRequest* navigation_request_to_exclude);
372
Carlos Caballero40b0efd2021-01-26 11:55:00373 NavigationControllerImpl& controller() { return navigator_.controller(); }
danakjc492bf82020-09-09 20:02:44374 Navigator& navigator() { return navigator_; }
375
Carlos Caballeroede6f8c2021-01-28 11:01:50376 // Another page accessed the initial empty main document, which means it
377 // is no longer safe to display a pending URL without risking a URL spoof.
378 void DidAccessInitialMainDocument();
379
380 bool has_accessed_initial_main_document() const {
381 return has_accessed_initial_main_document_;
382 }
383
384 void ResetHasAccessedInitialMainDocument() {
385 has_accessed_initial_main_document_ = false;
386 }
387
Carlos Caballero6ff6ace2021-02-05 16:53:00388 bool IsHidden() const { return delegate_->IsHidden(); }
389
Carlos Caballero03262522021-02-05 14:49:58390 // Stops all ongoing navigations in each of the nodes of this FrameTree.
391 void StopLoading();
392
Carlos Caballero101ac26b2021-03-24 11:54:05393 // Prepares this frame tree for destruction, cleaning up the internal state
394 // and firing the appropriate events like FrameDeleted.
395 // Must be called before FrameTree is destroyed.
396 void Shutdown();
397
shivanigithub93878d02021-06-15 11:37:53398 // Returns true if this is a fenced frame tree.
399 // TODO(crbug.com/1123606): Integrate this with the MPArch based fenced frame
400 // code once that lands.
401 bool IsFencedFrameTree() const { return is_fenced_frame_tree_; }
402 void SetFencedFrameTreeForTesting() { is_fenced_frame_tree_ = true; }
403
danakjc492bf82020-09-09 20:02:44404 private:
405 friend class FrameTreeTest;
406 FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplBrowserTest, RemoveFocusedFrame);
407
408 // Returns a range to iterate over all FrameTreeNodes in the frame tree in
409 // breadth-first traversal order, skipping the subtree rooted at
410 // |node|, but including |node| itself.
411 NodeRange NodesExceptSubtree(FrameTreeNode* node);
412
Carlos Caballero03262522021-02-05 14:49:58413 Delegate* const delegate_;
414
danakjc492bf82020-09-09 20:02:44415 // These delegates are installed into all the RenderViewHosts and
416 // RenderFrameHosts that we create.
417 RenderFrameHostDelegate* render_frame_delegate_;
418 RenderViewHostDelegate* render_view_delegate_;
419 RenderWidgetHostDelegate* render_widget_delegate_;
420 RenderFrameHostManager::Delegate* manager_delegate_;
Jeremy Roman2d8dfe132021-07-06 20:51:26421 PageDelegate* page_delegate_;
danakjc492bf82020-09-09 20:02:44422
423 // The Navigator object responsible for managing navigations on this frame
Carlos Caballero40b0efd2021-01-26 11:55:00424 // tree. Each FrameTreeNode will default to using it for navigation tasks in
425 // the frame.
danakjc492bf82020-09-09 20:02:44426 Navigator navigator_;
427
Aaron Colwell78b4bde2021-03-16 16:16:09428 // Map of RenderViewHostMapId to RenderViewHost. This allows us to look up the
danakjc492bf82020-09-09 20:02:44429 // RenderViewHost for a given SiteInstance when creating RenderFrameHosts.
430 // Each RenderViewHost maintains a refcount and is deleted when there are no
431 // more RenderFrameHosts or RenderFrameProxyHosts using it.
Aaron Colwell78b4bde2021-03-16 16:16:09432 RenderViewHostMap render_view_host_map_;
danakjc492bf82020-09-09 20:02:44433
434 // This is an owned ptr to the root FrameTreeNode, which never changes over
435 // the lifetime of the FrameTree. It is not a scoped_ptr because we need the
436 // pointer to remain valid even while the FrameTreeNode is being destroyed,
437 // since it's common for a node to test whether it's the root node.
438 FrameTreeNode* root_;
439
440 int focused_frame_tree_node_id_;
441
danakjc492bf82020-09-09 20:02:44442 // Overall load progress.
443 double load_progress_;
444
Carlos Caballeroede6f8c2021-01-28 11:01:50445 // Whether the initial empty page has been accessed by another page, making it
446 // unsafe to show the pending URL. Usually false unless another window tries
447 // to modify the blank page. Always false after the first commit.
448 bool has_accessed_initial_main_document_ = false;
449
Sreeja Kamishetty837a10402021-04-23 12:41:59450 // Indicates type of frame tree.
451 const Type type_;
Sreeja Kamishetty74bacd522021-03-22 17:04:24452
shivanigithub93878d02021-06-15 11:37:53453 // TODO(crbug.com/1123606): Integrate this with the MPArch based fenced frame
454 // code once that lands. Possibly this will then be part of |type_|.
455 bool is_fenced_frame_tree_ = false;
456
Carlos Caballero101ac26b2021-03-24 11:54:05457#if DCHECK_IS_ON()
458 // Whether Shutdown() was called.
459 bool was_shut_down_ = false;
460#endif
461
danakjc492bf82020-09-09 20:02:44462 DISALLOW_COPY_AND_ASSIGN(FrameTree);
463};
464
465} // namespace content
466
467#endif // CONTENT_BROWSER_RENDERER_HOST_FRAME_TREE_H_