blob: d34331649e6f7e7059d6e5ac8033a8fc44df6d79 [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
danakjc492bf82020-09-09 20:02:445#include "content/browser/renderer_host/frame_tree_node.h"
[email protected]9b159a52013-10-03 17:24:556
Daniel Cheng6ca7f1c92017-08-09 21:45:417#include <math.h>
[email protected]9b159a52013-10-03 17:24:558#include <queue>
Takuto Ikutaadf31eb2019-01-05 00:32:489#include <unordered_map>
dcheng36b6aec92015-12-26 06:16:3610#include <utility>
[email protected]9b159a52013-10-03 17:24:5511
Mustaq Ahmeda5dfa60b2018-12-08 00:30:1412#include "base/feature_list.h"
scottmg6ece5ae2017-02-01 18:25:1913#include "base/lazy_instance.h"
Keishi Hattori0e45c022021-11-27 09:25:5214#include "base/memory/raw_ptr.h"
Liviu Tintad9391fb92020-09-28 23:50:0715#include "base/metrics/histogram_functions.h"
dcheng23ca947d2016-05-04 20:04:1516#include "base/metrics/histogram_macros.h"
Clark DuVallc97bcf72021-12-08 22:58:2417#include "base/strings/strcat.h"
Daniel Cheng6ca7f1c92017-08-09 21:45:4118#include "base/strings/string_util.h"
Clark DuVallc97bcf72021-12-08 22:58:2419#include "base/timer/elapsed_timer.h"
Andrey Kosyakovf2d4ff72018-10-29 20:09:5920#include "content/browser/devtools/devtools_instrumentation.h"
Dominic Farolino8a2187b2021-12-24 20:44:2121#include "content/browser/fenced_frame/fenced_frame.h"
danakjc492bf82020-09-09 20:02:4422#include "content/browser/renderer_host/navigation_controller_impl.h"
23#include "content/browser/renderer_host/navigation_request.h"
24#include "content/browser/renderer_host/navigator.h"
25#include "content/browser/renderer_host/navigator_delegate.h"
26#include "content/browser/renderer_host/render_frame_host_impl.h"
[email protected]94d0cc12013-12-18 00:07:4127#include "content/browser/renderer_host/render_view_host_impl.h"
Lucas Furukawa Gadanief8290a2019-07-29 20:27:5128#include "content/common/navigation_params_utils.h"
dmazzonie950ea232015-03-13 21:39:4529#include "content/public/browser/browser_thread.h"
Nan Linaaf84f72021-12-02 22:31:5630#include "content/public/browser/site_isolation_policy.h"
Mustaq Ahmeda5dfa60b2018-12-08 00:30:1431#include "content/public/common/content_features.h"
arthursonzognib93a4472020-04-10 07:38:0032#include "services/network/public/cpp/web_sandbox_flags.h"
33#include "services/network/public/mojom/web_sandbox_flags.mojom-shared.h"
Harkiran Bolaria59290d62021-03-17 01:53:0134#include "third_party/blink/public/common/features.h"
Sreeja Kamishetty0be3b1b2021-08-12 17:04:1535#include "third_party/blink/public/common/loader/loader_constants.h"
Antonio Gomes4b2c5132020-01-16 11:49:4836#include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom.h"
Julie Jeongeun Kimd90e2dd2020-03-03 11:45:3737#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom.h"
[email protected]9b159a52013-10-03 17:24:5538
39namespace content {
40
dmazzonie950ea232015-03-13 21:39:4541namespace {
42
43// This is a global map between frame_tree_node_ids and pointers to
44// FrameTreeNodes.
Takuto Ikutaadf31eb2019-01-05 00:32:4845typedef std::unordered_map<int, FrameTreeNode*> FrameTreeNodeIdMap;
dmazzonie950ea232015-03-13 21:39:4546
scottmg5e65e3a2017-03-08 08:48:4647base::LazyInstance<FrameTreeNodeIdMap>::DestructorAtExit
48 g_frame_tree_node_id_map = LAZY_INSTANCE_INITIALIZER;
dmazzonie950ea232015-03-13 21:39:4549
fdegansa696e5112015-04-17 01:57:5950} // namespace
fdegans1d16355162015-03-26 11:58:3451
alexmose201c7cd2015-06-10 17:14:2152// This observer watches the opener of its owner FrameTreeNode and clears the
53// owner's opener if the opener is destroyed.
54class FrameTreeNode::OpenerDestroyedObserver : public FrameTreeNode::Observer {
55 public:
jochen6004a362017-02-04 00:11:4056 OpenerDestroyedObserver(FrameTreeNode* owner, bool observing_original_opener)
57 : owner_(owner), observing_original_opener_(observing_original_opener) {}
alexmose201c7cd2015-06-10 17:14:2158
Peter Boström9b036532021-10-28 23:37:2859 OpenerDestroyedObserver(const OpenerDestroyedObserver&) = delete;
60 OpenerDestroyedObserver& operator=(const OpenerDestroyedObserver&) = delete;
61
alexmose201c7cd2015-06-10 17:14:2162 // FrameTreeNode::Observer
63 void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
jochen6004a362017-02-04 00:11:4064 if (observing_original_opener_) {
Avi Drissman36465f332017-09-11 20:49:3965 // The "original owner" is special. It's used for attribution, and clients
66 // walk down the original owner chain. Therefore, if a link in the chain
67 // is being destroyed, reconnect the observation to the parent of the link
68 // being destroyed.
jochen6004a362017-02-04 00:11:4069 CHECK_EQ(owner_->original_opener(), node);
Avi Drissman36465f332017-09-11 20:49:3970 owner_->SetOriginalOpener(node->original_opener());
71 // |this| is deleted at this point.
jochen6004a362017-02-04 00:11:4072 } else {
73 CHECK_EQ(owner_->opener(), node);
74 owner_->SetOpener(nullptr);
Avi Drissman36465f332017-09-11 20:49:3975 // |this| is deleted at this point.
jochen6004a362017-02-04 00:11:4076 }
alexmose201c7cd2015-06-10 17:14:2177 }
78
79 private:
Keishi Hattori0e45c022021-11-27 09:25:5280 raw_ptr<FrameTreeNode> owner_;
jochen6004a362017-02-04 00:11:4081 bool observing_original_opener_;
alexmose201c7cd2015-06-10 17:14:2182};
83
Kevin McNee88e61552020-10-22 20:41:1184const int FrameTreeNode::kFrameTreeNodeInvalidId = -1;
85
86static_assert(FrameTreeNode::kFrameTreeNodeInvalidId ==
87 RenderFrameHost::kNoFrameTreeNodeId,
88 "Have consistent sentinel values for an invalid FTN id.");
89
vishal.b782eb5d2015-04-29 12:22:5790int FrameTreeNode::next_frame_tree_node_id_ = 1;
[email protected]9b159a52013-10-03 17:24:5591
dmazzonie950ea232015-03-13 21:39:4592// static
vishal.b782eb5d2015-04-29 12:22:5793FrameTreeNode* FrameTreeNode::GloballyFindByID(int frame_tree_node_id) {
mostynb366eaf12015-03-26 00:51:1994 DCHECK_CURRENTLY_ON(BrowserThread::UI);
rob97250742015-12-10 17:45:1595 FrameTreeNodeIdMap* nodes = g_frame_tree_node_id_map.Pointer();
jdoerrie55ec69d2018-10-08 13:34:4696 auto it = nodes->find(frame_tree_node_id);
dmazzonie950ea232015-03-13 21:39:4597 return it == nodes->end() ? nullptr : it->second;
98}
99
Alexander Timin381e7e182020-04-28 19:04:03100// static
101FrameTreeNode* FrameTreeNode::From(RenderFrameHost* rfh) {
102 if (!rfh)
103 return nullptr;
104 return static_cast<RenderFrameHostImpl*>(rfh)->frame_tree_node();
105}
106
Julie Jeongeun Kim70a2e4e2020-02-21 05:09:54107FrameTreeNode::FrameTreeNode(
108 FrameTree* frame_tree,
Alexander Timin381e7e182020-04-28 19:04:03109 RenderFrameHostImpl* parent,
Daniel Cheng6ac128172021-05-25 18:49:01110 blink::mojom::TreeScopeType tree_scope_type,
Julie Jeongeun Kim70a2e4e2020-02-21 05:09:54111 const std::string& name,
112 const std::string& unique_name,
113 bool is_created_by_script,
114 const base::UnguessableToken& devtools_frame_token,
115 const blink::mojom::FrameOwnerProperties& frame_owner_properties,
Kevin McNee43fe8292021-10-04 22:59:41116 blink::FrameOwnerElementType owner_type,
Dominic Farolino08662c82021-06-11 07:36:34117 const blink::FramePolicy& frame_policy)
[email protected]bffc8302014-01-23 20:52:16118 : frame_tree_(frame_tree),
[email protected]bffc8302014-01-23 20:52:16119 frame_tree_node_id_(next_frame_tree_node_id_++),
xiaochengh98488162016-05-19 15:17:59120 parent_(parent),
Daniel Cheng9bd90f92021-04-23 20:49:45121 frame_owner_element_type_(owner_type),
Daniel Cheng6ac128172021-05-25 18:49:01122 tree_scope_type_(tree_scope_type),
Dominic Farolino08662c82021-06-11 07:36:34123 pending_frame_policy_(frame_policy),
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45124 is_created_by_script_(is_created_by_script),
Pavel Feldman25234722017-10-11 02:49:06125 devtools_frame_token_(devtools_frame_token),
lazyboy70605c32015-11-03 01:27:31126 frame_owner_properties_(frame_owner_properties),
Lukasz Anforowicz147141962020-12-16 18:03:24127 blame_context_(frame_tree_node_id_, FrameTreeNode::From(parent)),
Harkiran Bolaria4eacb3a2021-12-13 20:03:47128 render_manager_(this,
129 frame_tree->manager_delegate(),
130 name,
131 unique_name,
132 frame_policy) {
rob97250742015-12-10 17:45:15133 std::pair<FrameTreeNodeIdMap::iterator, bool> result =
dmazzonie950ea232015-03-13 21:39:45134 g_frame_tree_node_id_map.Get().insert(
135 std::make_pair(frame_tree_node_id_, this));
136 CHECK(result.second);
benjhaydend4da63d2016-03-11 21:29:33137
xiaochenghb9554bb2016-05-21 14:20:48138 // Note: this should always be done last in the constructor.
139 blame_context_.Initialize();
alexmos998581d2015-01-22 01:01:59140}
[email protected]9b159a52013-10-03 17:24:55141
Dominic Farolino8a2187b2021-12-24 20:44:21142void FrameTreeNode::DestroyInnerFrameTreeIfExists() {
143 // If `this` is an dummy outer delegate node, then we really are representing
144 // an inner FrameTree for one of the following consumers:
145 // - `Portal`
146 // - `FencedFrame`
147 // - `GuestView`
148 // If we are representing a `FencedFrame` object, we need to destroy it
149 // alongside ourself. `Portals` and `GuestView` however, *currently* have a
150 // more complex lifetime and are dealt with separately.
151 bool is_outer_dummy_node = false;
152 if (current_frame_host() &&
153 current_frame_host()->inner_tree_main_frame_tree_node_id() !=
154 FrameTreeNode::kFrameTreeNodeInvalidId) {
155 is_outer_dummy_node = true;
156 }
157
158 if (is_outer_dummy_node) {
159 DCHECK(parent());
160 // Try and find the `FencedFrame` that `this` represents.
161 std::vector<FencedFrame*> fenced_frames = parent()->GetFencedFrames();
162 FencedFrame* doomed_fenced_frame = nullptr;
163 for (FencedFrame* fenced_frame : fenced_frames) {
164 if (frame_tree_node_id() ==
165 fenced_frame->GetOuterDelegateFrameTreeNodeId()) {
166 doomed_fenced_frame = fenced_frame;
167 break;
168 }
169 }
170
171 // `doomed_fenced_frame` might not actually exist, because some outer dummy
172 // `FrameTreeNode`s might correspond to `Portal`s, which do not have their
173 // lifetime managed in the same way as `FencedFrames`.
174 if (doomed_fenced_frame) {
175 parent()->DestroyFencedFrame(*doomed_fenced_frame);
176 }
177 }
178}
179
[email protected]9b159a52013-10-03 17:24:55180FrameTreeNode::~FrameTreeNode() {
Daniel Chengc3d1e8d2021-06-23 02:11:45181 // There should always be a current RenderFrameHost except during prerender
182 // activation. Prerender activation moves the current RenderFrameHost from
183 // the old FrameTree's FrameTreeNode to the new FrameTree's FrameTreeNode and
184 // then destroys the old FrameTree. See
185 // `RenderFrameHostManager::TakePrerenderedPage()`.
Harkiran Bolaria59290d62021-03-17 01:53:01186 if (current_frame_host()) {
187 // Remove the children.
188 current_frame_host()->ResetChildren();
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45189
Harkiran Bolaria59290d62021-03-17 01:53:01190 current_frame_host()->ResetLoadingState();
191 } else {
Hiroki Nakagawa0a90bd42021-04-21 01:53:05192 DCHECK(blink::features::IsPrerender2Enabled());
Harkiran Bolaria59290d62021-03-17 01:53:01193 DCHECK(!parent()); // Only main documents can be activated.
194 DCHECK(!opener()); // Prerendered frame trees can't have openers.
195
196 // Activation is not allowed during ongoing navigations.
197 DCHECK(!navigation_request_);
198
Carlos Caballerod1c80432021-04-20 08:16:32199 // TODO(https://crbug.com/1199693): Need to determine how to handle pending
Harkiran Bolaria59290d62021-03-17 01:53:01200 // deletions, as observers will be notified.
201 DCHECK(!render_manager()->speculative_frame_host());
202 }
Nate Chapin22ea6592019-03-05 22:29:02203
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45204 // If the removed frame was created by a script, then its history entry will
205 // never be reused - we can save some memory by removing the history entry.
206 // See also https://crbug.com/784356.
207 if (is_created_by_script_ && parent_) {
Carlos Caballero04aab362021-02-15 17:38:16208 NavigationEntryImpl* nav_entry =
209 navigator().controller().GetLastCommittedEntry();
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45210 if (nav_entry) {
211 nav_entry->RemoveEntryForFrame(this,
212 /* only_if_different_position = */ false);
213 }
214 }
215
dmazzonie950ea232015-03-13 21:39:45216 frame_tree_->FrameRemoved(this);
Carlos Caballero6ff6ace2021-02-05 16:53:00217
Dominic Farolino8a2187b2021-12-24 20:44:21218 DestroyInnerFrameTreeIfExists();
219
Carlos Caballero6ff6ace2021-02-05 16:53:00220 // Do not dispatch notification for the root frame as ~WebContentsImpl already
221 // dispatches it for now.
222 // TODO(https://crbug.com/1170277): This is only needed because the FrameTree
223 // is a member of WebContentsImpl and we would call back into it during
224 // destruction. We should clean up the FrameTree destruction code and call the
225 // delegate unconditionally.
226 if (parent())
227 render_manager_.delegate()->OnFrameTreeNodeDestroyed(this);
228
ericwilligers254597b2016-10-17 10:32:31229 for (auto& observer : observers_)
230 observer.OnFrameTreeNodeDestroyed(this);
Lukasz Anforowicz147141962020-12-16 18:03:24231 observers_.Clear();
alexmose201c7cd2015-06-10 17:14:21232
233 if (opener_)
234 opener_->RemoveObserver(opener_observer_.get());
jochen6004a362017-02-04 00:11:40235 if (original_opener_)
236 original_opener_->RemoveObserver(original_opener_observer_.get());
dmazzonie950ea232015-03-13 21:39:45237
238 g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
jam39258caf2016-11-02 14:48:18239
Daniel Chengc3d1e8d2021-06-23 02:11:45240 // If a frame with a pending navigation is detached, make sure the
241 // WebContents (and its observers) update their loading state.
242 // TODO(dcheng): This should just check `IsLoading()`, but `IsLoading()`
243 // assumes that `current_frame_host_` is not null. This is incompatible with
244 // prerender activation when destroying the old frame tree (see above).
danakjf9400602019-06-07 15:44:58245 bool did_stop_loading = false;
246
jam39258caf2016-11-02 14:48:18247 if (navigation_request_) {
danakjf9400602019-06-07 15:44:58248 navigation_request_.reset();
danakjf9400602019-06-07 15:44:58249 did_stop_loading = true;
jam39258caf2016-11-02 14:48:18250 }
Nate Chapin22ea6592019-03-05 22:29:02251
danakjf9400602019-06-07 15:44:58252 // ~SiteProcessCountTracker DCHECKs in some tests if the speculative
253 // RenderFrameHostImpl is not destroyed last. Ideally this would be closer to
254 // (possible before) the ResetLoadingState() call above.
danakjf9400602019-06-07 15:44:58255 if (render_manager_.speculative_frame_host()) {
Daniel Chengc3d1e8d2021-06-23 02:11:45256 // TODO(dcheng): Shouldn't a FrameTreeNode with a speculative
257 // RenderFrameHost always be considered loading?
danakjf9400602019-06-07 15:44:58258 did_stop_loading |= render_manager_.speculative_frame_host()->is_loading();
Daniel Chengc3d1e8d2021-06-23 02:11:45259 // `FrameTree::Shutdown()` has special handling for the main frame's
260 // speculative RenderFrameHost, and the speculative RenderFrameHost should
261 // already be reset for main frames.
262 DCHECK(!IsMainFrame());
263
264 // This does not use `UnsetSpeculativeRenderFrameHost()`: if the speculative
265 // RenderFrameHost has already reached kPendingCommit, it would needlessly
266 // re-create a proxy for a frame that's going away.
267 render_manager_.DiscardSpeculativeRenderFrameHostForShutdown();
danakjf9400602019-06-07 15:44:58268 }
269
270 if (did_stop_loading)
271 DidStopLoading();
272
Harkiran Bolaria59290d62021-03-17 01:53:01273 // IsLoading() requires that current_frame_host() is non-null.
274 DCHECK(!current_frame_host() || !IsLoading());
[email protected]9b159a52013-10-03 17:24:55275}
276
alexmose201c7cd2015-06-10 17:14:21277void FrameTreeNode::AddObserver(Observer* observer) {
278 observers_.AddObserver(observer);
279}
280
281void FrameTreeNode::RemoveObserver(Observer* observer) {
282 observers_.RemoveObserver(observer);
283}
284
[email protected]94d0cc12013-12-18 00:07:41285bool FrameTreeNode::IsMainFrame() const {
286 return frame_tree_->root() == this;
287}
288
Hiroki Nakagawaab309622021-05-19 16:38:13289void FrameTreeNode::ResetForNavigation() {
arthursonzogni76098e52020-11-25 14:18:45290 // This frame has had its user activation bits cleared in the renderer before
291 // arriving here. We just need to clear them here and in the other renderer
292 // processes that may have a reference to this frame.
Alexander Timin45b716c2020-11-06 01:40:31293 //
294 // We do not take user activation into account when calculating
295 // |ResetForNavigationResult|, as we are using it to determine bfcache
296 // eligibility and the page can get another user gesture after restore.
Antonio Gomes4b2c5132020-01-16 11:49:48297 UpdateUserActivationState(
Mustaq Ahmeddc195e5b2020-08-04 18:45:11298 blink::mojom::UserActivationUpdateType::kClearActivation,
299 blink::mojom::UserActivationNotificationType::kNone);
Ian Clelland5cbaaf82017-11-27 22:00:03300}
301
Dave Tapuskac8de3b02021-12-03 21:51:01302RenderFrameHostImpl* FrameTreeNode::GetParentOrOuterDocument() {
303 return GetParentOrOuterDocumentHelper(/*escape_guest_view=*/false);
304}
305
306RenderFrameHostImpl* FrameTreeNode::GetParentOrOuterDocumentOrEmbedder() {
307 return GetParentOrOuterDocumentHelper(/*escape_guest_view=*/true);
308}
309
310RenderFrameHostImpl* FrameTreeNode::GetParentOrOuterDocumentHelper(
311 bool escape_guest_view) {
312 // Find the parent in the FrameTree (iframe).
313 if (parent_)
314 return parent_;
315
316 if (!escape_guest_view) {
317 // If we are not a fenced frame root nor inside a portal then return early.
318 // This code does not escape GuestViews.
319 if (!IsFencedFrameRoot() && !frame_tree_->delegate()->IsPortal())
320 return nullptr;
321 }
322
323 // Find the parent in the outer embedder (GuestView, Portal, or Fenced Frame).
324 FrameTreeNode* frame_in_embedder = render_manager()->GetOuterDelegateNode();
325 if (frame_in_embedder)
326 return frame_in_embedder->current_frame_host()->GetParent();
327
328 // No parent found.
329 return nullptr;
330}
331
Julie Jeongeun Kimf38c1eca2021-12-14 07:46:55332FrameType FrameTreeNode::GetFrameType() const {
333 if (!IsMainFrame())
334 return FrameType::kSubframe;
335
336 switch (frame_tree()->type()) {
337 case FrameTree::Type::kPrimary:
338 return FrameType::kPrimaryMainFrame;
339 case FrameTree::Type::kPrerender:
340 return FrameType::kPrerenderMainFrame;
341 case FrameTree::Type::kFencedFrame:
342 // We also have FencedFramesImplementationType::kShadowDOM for a
343 // fenced frame implementation based on <iframe> + shadowDOM,
344 // which will return kSubframe as it's a modified <iframe> rather
345 // than a dedicated FrameTree. This returns kSubframe for the
346 // shadow dom implementation in order to keep consistency (i.e.
347 // NavigationHandle::GetParentFrame returning non-null value for
348 // shadow-dom based FFs).
349 return FrameType::kFencedFrameRoot;
350 }
351}
352
alexmose201c7cd2015-06-10 17:14:21353void FrameTreeNode::SetOpener(FrameTreeNode* opener) {
354 if (opener_) {
355 opener_->RemoveObserver(opener_observer_.get());
356 opener_observer_.reset();
357 }
358
359 opener_ = opener;
360
361 if (opener_) {
Jeremy Roman04f27c372017-10-27 15:20:55362 opener_observer_ = std::make_unique<OpenerDestroyedObserver>(this, false);
alexmose201c7cd2015-06-10 17:14:21363 opener_->AddObserver(opener_observer_.get());
364 }
365}
366
Wolfgang Beyerd8809db2020-09-30 15:29:39367void FrameTreeNode::SetOpenerDevtoolsFrameToken(
368 base::UnguessableToken opener_devtools_frame_token) {
369 DCHECK(!opener_devtools_frame_token_ ||
370 opener_devtools_frame_token_->is_empty());
371 opener_devtools_frame_token_ = std::move(opener_devtools_frame_token);
372}
373
jochen6004a362017-02-04 00:11:40374void FrameTreeNode::SetOriginalOpener(FrameTreeNode* opener) {
Avi Drissman36465f332017-09-11 20:49:39375 // The original opener tracks main frames only.
avi8d1aa162017-03-27 18:27:37376 DCHECK(opener == nullptr || !opener->parent());
jochen6004a362017-02-04 00:11:40377
Avi Drissman36465f332017-09-11 20:49:39378 if (original_opener_) {
379 original_opener_->RemoveObserver(original_opener_observer_.get());
380 original_opener_observer_.reset();
381 }
382
jochen6004a362017-02-04 00:11:40383 original_opener_ = opener;
384
385 if (original_opener_) {
jochen6004a362017-02-04 00:11:40386 original_opener_observer_ =
Jeremy Roman04f27c372017-10-27 15:20:55387 std::make_unique<OpenerDestroyedObserver>(this, true);
jochen6004a362017-02-04 00:11:40388 original_opener_->AddObserver(original_opener_observer_.get());
389 }
390}
391
creisf0f069a2015-07-23 23:51:53392void FrameTreeNode::SetCurrentURL(const GURL& url) {
Erik Chen173bf3042017-07-31 06:06:21393 current_frame_host()->SetLastCommittedUrl(url);
xiaochenghb9554bb2016-05-21 14:20:48394 blame_context_.TakeSnapshot();
creisf0f069a2015-07-23 23:51:53395}
396
engedy6e2e0992017-05-25 18:58:42397void FrameTreeNode::SetCollapsed(bool collapsed) {
398 DCHECK(!IsMainFrame());
399 if (is_collapsed_ == collapsed)
400 return;
401
402 is_collapsed_ = collapsed;
403 render_manager_.OnDidChangeCollapsedState(collapsed);
404}
405
Harkiran Bolaria59290d62021-03-17 01:53:01406void FrameTreeNode::SetFrameTree(FrameTree& frame_tree) {
Hiroki Nakagawa0a90bd42021-04-21 01:53:05407 DCHECK(blink::features::IsPrerender2Enabled());
Harkiran Bolaria59290d62021-03-17 01:53:01408 frame_tree_ = &frame_tree;
Kevin McNeeb110d0c2021-10-26 15:53:00409 DCHECK(current_frame_host());
410 current_frame_host()->SetFrameTree(frame_tree);
411 RenderFrameHostImpl* speculative_frame_host =
412 render_manager_.speculative_frame_host();
413 if (speculative_frame_host)
414 speculative_frame_host->SetFrameTree(frame_tree);
Harkiran Bolaria59290d62021-03-17 01:53:01415}
416
lukasza464d8692016-02-22 19:26:32417void FrameTreeNode::SetFrameName(const std::string& name,
418 const std::string& unique_name) {
Harkiran Bolaria4eacb3a2021-12-13 20:03:47419 if (name == render_manager_.current_replication_state().name) {
lukasza464d8692016-02-22 19:26:32420 // |unique_name| shouldn't change unless |name| changes.
Harkiran Bolaria4eacb3a2021-12-13 20:03:47421 DCHECK_EQ(unique_name,
422 render_manager_.current_replication_state().unique_name);
lukasza464d8692016-02-22 19:26:32423 return;
424 }
lukasza5140a412016-09-15 21:12:30425
426 if (parent()) {
427 // Non-main frames should have a non-empty unique name.
428 DCHECK(!unique_name.empty());
429 } else {
430 // Unique name of main frames should always stay empty.
431 DCHECK(unique_name.empty());
432 }
433
Daniel Cheng6ca7f1c92017-08-09 21:45:41434 // Note the unique name should only be able to change before the first real
435 // load is committed, but that's not strongly enforced here.
lukasza464d8692016-02-22 19:26:32436 render_manager_.OnDidUpdateName(name, unique_name);
Harkiran Bolaria4eacb3a2021-12-13 20:03:47437 render_manager_.browsing_context_state()->set_frame_name(unique_name, name);
alexmosbe2f4c32015-03-10 02:30:23438}
439
Luna Luc3fdacdf2017-11-08 04:48:53440void FrameTreeNode::SetPendingFramePolicy(blink::FramePolicy frame_policy) {
Dominic Farolino08662c82021-06-11 07:36:34441 // The |is_fenced| bit should never be able to transition from what its
442 // initial value was. Since we never expect to be in a position where it can
443 // even be updated to new value, if we catch this happening we have to kill
444 // the renderer and refuse to accept any other frame policy changes here.
445 if (pending_frame_policy_.is_fenced != frame_policy.is_fenced) {
446 mojo::ReportBadMessage(
447 "The `is_fenced` FramePolicy bit is const and should never be changed");
448 return;
449 }
450
Ian Clellandcdc4f312017-10-13 22:24:12451 pending_frame_policy_.sandbox_flags = frame_policy.sandbox_flags;
alexmos6e940102016-01-19 22:47:25452
Ian Clellandcdc4f312017-10-13 22:24:12453 if (parent()) {
454 // Subframes should always inherit their parent's sandbox flags.
Alexander Timin381e7e182020-04-28 19:04:03455 pending_frame_policy_.sandbox_flags |=
Harkiran Bolaria4eacb3a2021-12-13 20:03:47456 parent()->browsing_context_state()->active_sandbox_flags();
Charlie Hue1b77ac2019-12-13 21:30:17457 // This is only applied on subframes; container policy and required document
458 // policy are not mutable on main frame.
Ian Clellandcdc4f312017-10-13 22:24:12459 pending_frame_policy_.container_policy = frame_policy.container_policy;
Charlie Hue1b77ac2019-12-13 21:30:17460 pending_frame_policy_.required_document_policy =
461 frame_policy.required_document_policy;
Ian Clellandcdc4f312017-10-13 22:24:12462 }
iclelland92f8c0b2017-04-19 12:43:05463}
464
fdegans4a49ce932015-03-12 17:11:37465bool FrameTreeNode::IsLoading() const {
466 RenderFrameHostImpl* current_frame_host =
467 render_manager_.current_frame_host();
fdegans4a49ce932015-03-12 17:11:37468
469 DCHECK(current_frame_host);
fdegans39ff0382015-04-29 19:04:39470
clamy610c63b32017-12-22 15:05:18471 if (navigation_request_)
472 return true;
clamy11e11512015-07-07 16:42:17473
clamy610c63b32017-12-22 15:05:18474 RenderFrameHostImpl* speculative_frame_host =
475 render_manager_.speculative_frame_host();
Daniel Chengc3d1e8d2021-06-23 02:11:45476 // TODO(dcheng): Shouldn't a FrameTreeNode with a speculative RenderFrameHost
477 // always be considered loading?
clamy610c63b32017-12-22 15:05:18478 if (speculative_frame_host && speculative_frame_host->is_loading())
479 return true;
fdegans4a49ce932015-03-12 17:11:37480 return current_frame_host->is_loading();
481}
482
Alex Moshchuk9b0fd822020-10-26 23:08:15483bool FrameTreeNode::HasPendingCrossDocumentNavigation() const {
484 // Having a |navigation_request_| on FrameTreeNode implies that there's an
485 // ongoing navigation that hasn't reached the ReadyToCommit state. If the
486 // navigation is between ReadyToCommit and DidCommitNavigation, the
487 // NavigationRequest will be held by RenderFrameHost, which is checked below.
488 if (navigation_request_ && !navigation_request_->IsSameDocument())
489 return true;
490
491 // Having a speculative RenderFrameHost should imply a cross-document
492 // navigation.
493 if (render_manager_.speculative_frame_host())
494 return true;
495
496 return render_manager_.current_frame_host()
497 ->HasPendingCommitForCrossDocumentNavigation();
498}
499
Arthur Hemeryc3380172018-01-22 14:00:17500void FrameTreeNode::TransferNavigationRequestOwnership(
501 RenderFrameHostImpl* render_frame_host) {
Andrey Kosyakovf2d4ff72018-10-29 20:09:59502 devtools_instrumentation::OnResetNavigationRequest(navigation_request_.get());
Arthur Hemeryc3380172018-01-22 14:00:17503 render_frame_host->SetNavigationRequest(std::move(navigation_request_));
504}
505
carloskc49005eb2015-06-16 11:25:07506void FrameTreeNode::CreatedNavigationRequest(
dcheng9bfa5162016-04-09 01:00:57507 std::unique_ptr<NavigationRequest> navigation_request) {
arthursonzognic79c251c2016-08-18 15:00:37508 // This is never called when navigating to a Javascript URL. For the loading
509 // state, this matches what Blink is doing: Blink doesn't send throbber
510 // notifications for Javascript URLS.
511 DCHECK(!navigation_request->common_params().url.SchemeIs(
512 url::kJavaScriptScheme));
513
clamy44e84ce2016-02-22 15:38:25514 bool was_previously_loading = frame_tree()->IsLoading();
515
clamy82a2f4d2016-02-02 14:20:41516 // There's no need to reset the state: there's still an ongoing load, and the
517 // RenderFrameHostManager will take care of updates to the speculative
518 // RenderFrameHost in DidCreateNavigationRequest below.
jamcd0b7b22017-03-24 22:13:05519 if (was_previously_loading) {
Mohamed Abdelhalimf03d4a22019-10-01 13:34:31520 if (navigation_request_ && navigation_request_->IsNavigationStarted()) {
jamcd0b7b22017-03-24 22:13:05521 // Mark the old request as aborted.
Mohamed Abdelhalimb4db22a2019-06-18 10:46:52522 navigation_request_->set_net_error(net::ERR_ABORTED);
jamcd0b7b22017-03-24 22:13:05523 }
Arthur Hemery241b9392019-10-24 11:08:41524 ResetNavigationRequest(true);
jamcd0b7b22017-03-24 22:13:05525 }
clamy44e84ce2016-02-22 15:38:25526
527 navigation_request_ = std::move(navigation_request);
Shubhie Panickerddf2a4e2018-03-06 00:09:06528 if (was_discarded_) {
529 navigation_request_->set_was_discarded();
530 was_discarded_ = false;
531 }
clamy8e2e299202016-04-05 11:44:59532 render_manager()->DidCreateNavigationRequest(navigation_request_.get());
fdegans39ff0382015-04-29 19:04:39533
Lucas Furukawa Gadanief8290a2019-07-29 20:27:51534 bool to_different_document = !NavigationTypeUtils::IsSameDocument(
arthursonzogni92f18682017-02-08 23:00:04535 navigation_request_->common_params().navigation_type);
536
537 DidStartLoading(to_different_document, was_previously_loading);
clamydcb434c12015-04-16 19:29:16538}
539
Arthur Hemery241b9392019-10-24 11:08:41540void FrameTreeNode::ResetNavigationRequest(bool keep_state) {
fdegans39ff0382015-04-29 19:04:39541 if (!navigation_request_)
542 return;
John Abd-El-Malekdcc7bf42017-09-12 22:30:23543
Andrey Kosyakovf2d4ff72018-10-29 20:09:59544 devtools_instrumentation::OnResetNavigationRequest(navigation_request_.get());
clamydcb434c12015-04-16 19:29:16545 navigation_request_.reset();
fdegans39ff0382015-04-29 19:04:39546
clamy82a2f4d2016-02-02 14:20:41547 if (keep_state)
fdegans39ff0382015-04-29 19:04:39548 return;
549
clamy82a2f4d2016-02-02 14:20:41550 // The RenderFrameHostManager should clean up any speculative RenderFrameHost
551 // it created for the navigation. Also register that the load stopped.
fdegans39ff0382015-04-29 19:04:39552 DidStopLoading();
553 render_manager_.CleanUpNavigation();
clamydcb434c12015-04-16 19:29:16554}
555
Nate Chapin9aabf5f2021-11-12 00:31:19556void FrameTreeNode::DidStartLoading(bool should_show_loading_ui,
clamy44e84ce2016-02-22 15:38:25557 bool was_previously_loading) {
Camille Lamyefd54b02018-10-04 16:54:14558 TRACE_EVENT2("navigation", "FrameTreeNode::DidStartLoading",
Nate Chapin9aabf5f2021-11-12 00:31:19559 "frame_tree_node", frame_tree_node_id(),
560 "should_show_loading_ui ", should_show_loading_ui);
Clark DuVallc97bcf72021-12-08 22:58:24561 base::ElapsedTimer timer;
fdegansa696e5112015-04-17 01:57:59562
Nate Chapin9aabf5f2021-11-12 00:31:19563 frame_tree_->DidStartLoadingNode(*this, should_show_loading_ui,
Carlos Caballero03262522021-02-05 14:49:58564 was_previously_loading);
fdegansa696e5112015-04-17 01:57:59565
566 // Set initial load progress and update overall progress. This will notify
567 // the WebContents of the load progress change.
Sreeja Kamishetty0be3b1b2021-08-12 17:04:15568 DidChangeLoadProgress(blink::kInitialLoadProgress);
fdegansa696e5112015-04-17 01:57:59569
570 // Notify the RenderFrameHostManager of the event.
571 render_manager()->OnDidStartLoading();
Clark DuVallc97bcf72021-12-08 22:58:24572 base::UmaHistogramTimes(
573 base::StrCat({"Navigation.DidStartLoading.",
574 IsMainFrame() ? "MainFrame" : "Subframe"}),
575 timer.Elapsed());
fdegansa696e5112015-04-17 01:57:59576}
577
578void FrameTreeNode::DidStopLoading() {
Camille Lamyefd54b02018-10-04 16:54:14579 TRACE_EVENT1("navigation", "FrameTreeNode::DidStopLoading", "frame_tree_node",
580 frame_tree_node_id());
fdegansa696e5112015-04-17 01:57:59581 // Set final load progress and update overall progress. This will notify
582 // the WebContents of the load progress change.
Sreeja Kamishetty0be3b1b2021-08-12 17:04:15583 DidChangeLoadProgress(blink::kFinalLoadProgress);
fdegansa696e5112015-04-17 01:57:59584
Lucas Furukawa Gadani6faef602019-05-06 21:16:03585 // Notify the RenderFrameHostManager of the event.
586 render_manager()->OnDidStopLoading();
587
Carlos Caballero03262522021-02-05 14:49:58588 frame_tree_->DidStopLoadingNode(*this);
fdegansa696e5112015-04-17 01:57:59589}
590
591void FrameTreeNode::DidChangeLoadProgress(double load_progress) {
Sreeja Kamishetty0be3b1b2021-08-12 17:04:15592 DCHECK_GE(load_progress, blink::kInitialLoadProgress);
593 DCHECK_LE(load_progress, blink::kFinalLoadProgress);
594 current_frame_host()->DidChangeLoadProgress(load_progress);
fdegansa696e5112015-04-17 01:57:59595}
596
clamyf73862c42015-07-08 12:31:33597bool FrameTreeNode::StopLoading() {
arthursonzogni66f711c2019-10-08 14:40:36598 if (navigation_request_ && navigation_request_->IsNavigationStarted())
599 navigation_request_->set_net_error(net::ERR_ABORTED);
Arthur Hemery241b9392019-10-24 11:08:41600 ResetNavigationRequest(false);
clamyf73862c42015-07-08 12:31:33601
clamyf73862c42015-07-08 12:31:33602 if (!IsMainFrame())
603 return true;
604
605 render_manager_.Stop();
606 return true;
607}
608
alexmos21acae52015-11-07 01:04:43609void FrameTreeNode::DidFocus() {
610 last_focus_time_ = base::TimeTicks::Now();
ericwilligers254597b2016-10-17 10:32:31611 for (auto& observer : observers_)
612 observer.OnFrameTreeNodeFocused(this);
alexmos21acae52015-11-07 01:04:43613}
614
clamy44e84ce2016-02-22 15:38:25615void FrameTreeNode::BeforeUnloadCanceled() {
616 // TODO(clamy): Support BeforeUnload in subframes.
617 if (!IsMainFrame())
618 return;
619
620 RenderFrameHostImpl* current_frame_host =
621 render_manager_.current_frame_host();
622 DCHECK(current_frame_host);
623 current_frame_host->ResetLoadingState();
624
clamy610c63b32017-12-22 15:05:18625 RenderFrameHostImpl* speculative_frame_host =
626 render_manager_.speculative_frame_host();
627 if (speculative_frame_host)
628 speculative_frame_host->ResetLoadingState();
Alexander Timin23c110b2021-01-14 02:39:04629 // Note: there is no need to set an error code on the NavigationHandle as
630 // the observers have not been notified about its creation.
631 // We also reset navigation request only when this navigation request was
632 // responsible for this dialog, as a new navigation request might cancel
633 // existing unrelated dialog.
634 if (navigation_request_ && navigation_request_->IsWaitingForBeforeUnload())
Arthur Hemery241b9392019-10-24 11:08:41635 ResetNavigationRequest(false);
clamy44e84ce2016-02-22 15:38:25636}
637
Mustaq Ahmedecb5c38e2020-07-29 00:34:30638bool FrameTreeNode::NotifyUserActivation(
639 blink::mojom::UserActivationNotificationType notification_type) {
Alex Moshchuk03904192021-04-02 07:29:08640 // User Activation V2 requires activating all ancestor frames in addition to
641 // the current frame. See
642 // https://html.spec.whatwg.org/multipage/interaction.html#tracking-user-activation.
Alexander Timina1dfadaa2020-04-28 13:30:06643 for (RenderFrameHostImpl* rfh = current_frame_host(); rfh;
644 rfh = rfh->GetParent()) {
Claudio DeSouza25259562022-01-17 09:46:51645 // The use of GetParent above is acceptable with fenced frames, as
646 // the caller to this function will eventually reach
647 // RenderFrameHostManager::UpdateUserActivationState, which in turn will
648 // lead to the propagation of the user activation to all ancestors.
John Delaneyb625dca92021-04-14 17:00:34649 rfh->DidReceiveUserActivation();
Mustaq Ahmedecb5c38e2020-07-29 00:34:30650 rfh->frame_tree_node()->user_activation_state_.Activate(notification_type);
John Delaneyedd8d6c2019-01-25 00:23:57651 }
Alex Moshchuk03904192021-04-02 07:29:08652
Harkiran Bolaria4eacb3a2021-12-13 20:03:47653 render_manager_.browsing_context_state()->set_has_active_user_gesture(true);
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14654
Mustaq Ahmed0180320f2019-03-21 16:07:01655 // See the "Same-origin Visibility" section in |UserActivationState| class
656 // doc.
Mustaq Ahmede5f12562019-10-30 18:02:03657 if (base::FeatureList::IsEnabled(
Claudio DeSouza25259562022-01-17 09:46:51658 features::kUserActivationSameOriginVisibility) &&
659 frame_tree()->type() != FrameTree::Type::kFencedFrame) {
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14660 const url::Origin& current_origin =
661 this->current_frame_host()->GetLastCommittedOrigin();
662 for (FrameTreeNode* node : frame_tree()->Nodes()) {
663 if (node->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
664 current_origin)) {
Mustaq Ahmedecb5c38e2020-07-29 00:34:30665 node->user_activation_state_.Activate(notification_type);
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14666 }
667 }
668 }
669
Carlos Caballero40b0efd2021-01-26 11:55:00670 navigator().controller().NotifyUserActivation();
Alex Moshchuk03904192021-04-02 07:29:08671 current_frame_host()->MaybeIsolateForUserActivation();
Shivani Sharma194877032019-03-07 17:52:47672
Mustaq Ahmedc4cb7162018-06-05 16:28:36673 return true;
674}
675
676bool FrameTreeNode::ConsumeTransientUserActivation() {
677 bool was_active = user_activation_state_.IsActive();
678 for (FrameTreeNode* node : frame_tree()->Nodes())
679 node->user_activation_state_.ConsumeIfActive();
Harkiran Bolaria4eacb3a2021-12-13 20:03:47680 render_manager_.browsing_context_state()->set_has_active_user_gesture(false);
Mustaq Ahmedc4cb7162018-06-05 16:28:36681 return was_active;
682}
683
Shivani Sharmac4f561582018-11-15 15:58:39684bool FrameTreeNode::ClearUserActivation() {
Shivani Sharmac4f561582018-11-15 15:58:39685 for (FrameTreeNode* node : frame_tree()->SubtreeNodes(this))
686 node->user_activation_state_.Clear();
Harkiran Bolaria4eacb3a2021-12-13 20:03:47687 render_manager_.browsing_context_state()->set_has_active_user_gesture(false);
Shivani Sharmac4f561582018-11-15 15:58:39688 return true;
689}
690
Ella Ge9caed612019-08-09 16:17:25691bool FrameTreeNode::VerifyUserActivation() {
Ella Gea78f6772019-12-11 10:35:25692 DCHECK(base::FeatureList::IsEnabled(
693 features::kBrowserVerifiedUserActivationMouse) ||
694 base::FeatureList::IsEnabled(
695 features::kBrowserVerifiedUserActivationKeyboard));
696
Ella Ge9caed612019-08-09 16:17:25697 return render_manager_.current_frame_host()
698 ->GetRenderWidgetHost()
Mustaq Ahmed83bb1722019-10-22 20:00:10699 ->RemovePendingUserActivationIfAvailable();
Ella Ge9caed612019-08-09 16:17:25700}
701
Mustaq Ahmedc4cb7162018-06-05 16:28:36702bool FrameTreeNode::UpdateUserActivationState(
Mustaq Ahmeddc195e5b2020-08-04 18:45:11703 blink::mojom::UserActivationUpdateType update_type,
704 blink::mojom::UserActivationNotificationType notification_type) {
Ella Ge9caed612019-08-09 16:17:25705 bool update_result = false;
Mustaq Ahmedc4cb7162018-06-05 16:28:36706 switch (update_type) {
Antonio Gomes4b2c5132020-01-16 11:49:48707 case blink::mojom::UserActivationUpdateType::kConsumeTransientActivation:
Ella Ge9caed612019-08-09 16:17:25708 update_result = ConsumeTransientUserActivation();
709 break;
Antonio Gomes4b2c5132020-01-16 11:49:48710 case blink::mojom::UserActivationUpdateType::kNotifyActivation:
Mustaq Ahmeddc195e5b2020-08-04 18:45:11711 update_result = NotifyUserActivation(notification_type);
Ella Ge9caed612019-08-09 16:17:25712 break;
Antonio Gomes4b2c5132020-01-16 11:49:48713 case blink::mojom::UserActivationUpdateType::
Liviu Tintad9391fb92020-09-28 23:50:07714 kNotifyActivationPendingBrowserVerification: {
715 const bool user_activation_verified = VerifyUserActivation();
716 // Add UMA metric for when browser user activation verification succeeds
717 base::UmaHistogramBoolean("Event.BrowserVerifiedUserActivation",
718 user_activation_verified);
719 if (user_activation_verified) {
Mustaq Ahmedecb5c38e2020-07-29 00:34:30720 update_result = NotifyUserActivation(
Mustaq Ahmed2cfb0402020-09-29 19:24:35721 blink::mojom::UserActivationNotificationType::kInteraction);
Antonio Gomes4b2c5132020-01-16 11:49:48722 update_type = blink::mojom::UserActivationUpdateType::kNotifyActivation;
Ella Ge9caed612019-08-09 16:17:25723 } else {
arthursonzogni9816b9192021-03-29 16:09:19724 // TODO(https://crbug.com/848778): We need to decide what to do when
725 // user activation verification failed. NOTREACHED here will make all
Ella Ge9caed612019-08-09 16:17:25726 // unrelated tests that inject event to renderer fail.
727 return false;
728 }
Liviu Tintad9391fb92020-09-28 23:50:07729 } break;
Antonio Gomes4b2c5132020-01-16 11:49:48730 case blink::mojom::UserActivationUpdateType::kClearActivation:
Ella Ge9caed612019-08-09 16:17:25731 update_result = ClearUserActivation();
732 break;
Mustaq Ahmedc4cb7162018-06-05 16:28:36733 }
Mustaq Ahmeddc195e5b2020-08-04 18:45:11734 render_manager_.UpdateUserActivationState(update_type, notification_type);
Ella Ge9caed612019-08-09 16:17:25735 return update_result;
japhet61835ae12017-01-20 01:25:39736}
737
Arthur Sonzognif8840b92018-11-07 14:10:35738void FrameTreeNode::PruneChildFrameNavigationEntries(
739 NavigationEntryImpl* entry) {
740 for (size_t i = 0; i < current_frame_host()->child_count(); ++i) {
741 FrameTreeNode* child = current_frame_host()->child_at(i);
742 if (child->is_created_by_script_) {
743 entry->RemoveEntryForFrame(child,
744 /* only_if_different_position = */ false);
745 } else {
746 child->PruneChildFrameNavigationEntries(entry);
747 }
748 }
749}
750
arthursonzogni034bb9c2020-10-01 08:29:56751void FrameTreeNode::SetInitialPopupURL(const GURL& initial_popup_url) {
752 DCHECK(initial_popup_url_.is_empty());
Rakina Zata Amni4182b032021-11-01 04:22:01753 DCHECK(is_on_initial_empty_document_);
arthursonzogni034bb9c2020-10-01 08:29:56754 initial_popup_url_ = initial_popup_url;
755}
756
757void FrameTreeNode::SetPopupCreatorOrigin(
758 const url::Origin& popup_creator_origin) {
Rakina Zata Amni4182b032021-11-01 04:22:01759 DCHECK(is_on_initial_empty_document_);
arthursonzogni034bb9c2020-10-01 08:29:56760 popup_creator_origin_ = popup_creator_origin;
761}
762
Alexander Timinbebb2002021-04-20 15:42:24763void FrameTreeNode::WriteIntoTrace(perfetto::TracedValue context) const {
Alexander Timinf785f342021-03-18 00:00:56764 auto dict = std::move(context).WriteDictionary();
765 dict.Add("id", frame_tree_node_id());
766 dict.Add("is_main_frame", IsMainFrame());
767}
768
Rakina Zata Amni4b1968d2021-09-09 03:29:47769void FrameTreeNode::WriteIntoTrace(
770 perfetto::TracedProto<perfetto::protos::pbzero::FrameTreeNodeInfo> proto) {
771 proto->set_is_main_frame(IsMainFrame());
772 proto->set_frame_tree_node_id(frame_tree_node_id());
773 proto->set_has_speculative_render_frame_host(
774 !!render_manager()->speculative_frame_host());
775}
776
Carlos Caballero76711352021-03-24 17:38:21777bool FrameTreeNode::HasNavigation() {
778 if (navigation_request())
779 return true;
780
781 // Same-RenderFrameHost navigation is committing:
782 if (current_frame_host()->HasPendingCommitNavigation())
783 return true;
784
785 // Cross-RenderFrameHost navigation is committing:
786 if (render_manager()->speculative_frame_host())
787 return true;
788
789 return false;
790}
791
Dominic Farolino4bc10ee2021-08-31 00:37:36792bool FrameTreeNode::IsFencedFrameRoot() const {
shivanigithubf3ddff52021-07-03 22:06:30793 if (!blink::features::IsFencedFramesEnabled())
794 return false;
795
796 switch (blink::features::kFencedFramesImplementationTypeParam.Get()) {
797 case blink::features::FencedFramesImplementationType::kMPArch: {
Dominic Farolino4bc10ee2021-08-31 00:37:36798 return IsMainFrame() &&
799 frame_tree()->type() == FrameTree::Type::kFencedFrame;
shivanigithubf3ddff52021-07-03 22:06:30800 }
801 case blink::features::FencedFramesImplementationType::kShadowDOM: {
802 return effective_frame_policy().is_fenced;
803 }
804 default:
805 return false;
806 }
807}
808
809bool FrameTreeNode::IsInFencedFrameTree() const {
810 if (!blink::features::IsFencedFramesEnabled())
811 return false;
812
813 switch (blink::features::kFencedFramesImplementationTypeParam.Get()) {
814 case blink::features::FencedFramesImplementationType::kMPArch:
Dominic Farolino4bc10ee2021-08-31 00:37:36815 return frame_tree()->type() == FrameTree::Type::kFencedFrame;
shivanigithubf3ddff52021-07-03 22:06:30816 case blink::features::FencedFramesImplementationType::kShadowDOM: {
817 auto* node = this;
818 while (node) {
819 if (node->effective_frame_policy().is_fenced) {
820 return true;
821 }
822 node = node->parent() ? node->parent()->frame_tree_node() : nullptr;
823 }
824 return false;
825 }
826 default:
827 return false;
828 }
829}
830
shivanigithub4cd016a2021-09-20 21:10:30831void FrameTreeNode::SetFencedFrameNonceIfNeeded() {
832 if (!IsInFencedFrameTree()) {
833 return;
834 }
835
836 if (IsFencedFrameRoot()) {
837 fenced_frame_nonce_ = base::UnguessableToken::Create();
838 return;
839 }
840
841 // For nested iframes in a fenced frame tree, propagate the same nonce as was
842 // set in the fenced frame root.
843 DCHECK(parent_);
844 absl::optional<base::UnguessableToken> nonce =
845 parent_->frame_tree_node()->fenced_frame_nonce();
846 DCHECK(nonce.has_value());
847 fenced_frame_nonce_ = nonce;
848}
849
Nan Lin171fe9a2022-02-17 16:42:16850void FrameTreeNode::SetFencedFrameModeIfNeeded(
851 FencedFrameMode fenced_frame_mode) {
852 if (!IsFencedFrameRoot())
853 return;
854
855 // TODO(crbug.com/1123606): The 'mode' attribute cannot be changed once
856 // applied to a fenced frame. This will be enforced before this point so add
857 // a DCHECK here.
858
859 fenced_frame_mode_ = fenced_frame_mode;
860}
861
Nan Linaaf84f72021-12-02 22:31:56862bool FrameTreeNode::IsErrorPageIsolationEnabled() const {
863 // Enable error page isolation for fenced frames in both MPArch and ShadowDOM
864 // modes to address the issue with invalid urn:uuid (crbug.com/1264224).
865 //
866 // Note that `IsMainFrame()` only covers MPArch, therefore we add explicit
867 // `IsFencedFrameRoot()` check for ShadowDOM, at least until error page
868 // isolation is supported for subframes in crbug.com/1092524.
869 return SiteIsolationPolicy::IsErrorPageIsolationEnabled(IsMainFrame() ||
870 IsFencedFrameRoot());
871}
872
W. James MacLean81b8d01f2022-01-25 20:50:59873void FrameTreeNode::SetSrcdocValue(const std::string& srcdoc_value) {
874 srcdoc_value_ = srcdoc_value;
875}
876
[email protected]9b159a52013-10-03 17:24:55877} // namespace content