1 // Copyright 2014 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 #include "third_party/blink/renderer/core/frame/remote_frame.h"
6
7 #include "cc/layers/surface_layer.h"
8 #include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
9 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
10 #include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom-blink.h"
11 #include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom-blink.h"
12 #include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h"
13 #include "third_party/blink/public/platform/interface_registry.h"
14 #include "third_party/blink/public/web/web_frame.h"
15 #include "third_party/blink/public/web/web_view.h"
16 #include "third_party/blink/renderer/bindings/core/v8/v8_fullscreen_options.h"
17 #include "third_party/blink/renderer/bindings/core/v8/window_proxy.h"
18 #include "third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h"
19 #include "third_party/blink/renderer/core/events/message_event.h"
20 #include "third_party/blink/renderer/core/exported/web_view_impl.h"
21 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
22 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
23 #include "third_party/blink/renderer/core/frame/local_frame.h"
24 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
25 #include "third_party/blink/renderer/core/frame/remote_dom_window.h"
26 #include "third_party/blink/renderer/core/frame/remote_frame_client.h"
27 #include "third_party/blink/renderer/core/frame/remote_frame_owner.h"
28 #include "third_party/blink/renderer/core/frame/remote_frame_view.h"
29 #include "third_party/blink/renderer/core/frame/user_activation.h"
30 #include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
31 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
32 #include "third_party/blink/renderer/core/inspector/console_message.h"
33 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
34 #include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
35 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
36 #include "third_party/blink/renderer/core/layout/layout_view.h"
37 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
38 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
39 #include "third_party/blink/renderer/core/loader/frame_loader.h"
40 #include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
41 #include "third_party/blink/renderer/core/messaging/blink_transferable_message.h"
42 #include "third_party/blink/renderer/core/page/page.h"
43 #include "third_party/blink/renderer/core/page/plugin_script_forbidden_scope.h"
44 #include "third_party/blink/renderer/core/paint/paint_layer.h"
45 #include "third_party/blink/renderer/core/probe/core_probes.h"
46 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
47 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
48 #include "third_party/blink/renderer/platform/heap/heap.h"
49 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
50 #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h"
51 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
52 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
53 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
54 #include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
55 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
56
57 namespace blink {
58
59 namespace {
60
61 // Maintain a global (statically-allocated) hash map indexed by the the result
62 // of hashing the |frame_token| passed on creation of a RemoteFrame object.
63 typedef HeapHashMap<uint64_t, WeakMember<RemoteFrame>> RemoteFramesByTokenMap;
GetRemoteFramesMap()64 static RemoteFramesByTokenMap& GetRemoteFramesMap() {
65 DEFINE_STATIC_LOCAL(Persistent<RemoteFramesByTokenMap>, map,
66 (MakeGarbageCollected<RemoteFramesByTokenMap>()));
67 return *map;
68 }
69
DeNormalizeRect(const gfx::RectF & normalized,const IntRect & base)70 FloatRect DeNormalizeRect(const gfx::RectF& normalized, const IntRect& base) {
71 FloatRect result(normalized);
72 result.Scale(base.Width(), base.Height());
73 result.MoveBy(FloatPoint(base.Location()));
74 return result;
75 }
76
77 } // namespace
78
79 // static
FromFrameToken(const base::UnguessableToken & frame_token)80 RemoteFrame* RemoteFrame::FromFrameToken(
81 const base::UnguessableToken& frame_token) {
82 RemoteFramesByTokenMap& remote_frames_map = GetRemoteFramesMap();
83 auto it = remote_frames_map.find(base::UnguessableTokenHash()(frame_token));
84 return it == remote_frames_map.end() ? nullptr : it->value.Get();
85 }
86
87 // static
FromFrameToken(const RemoteFrameToken & frame_token)88 RemoteFrame* RemoteFrame::FromFrameToken(const RemoteFrameToken& frame_token) {
89 return FromFrameToken(frame_token.value());
90 }
91
RemoteFrame(RemoteFrameClient * client,Page & page,FrameOwner * owner,Frame * parent,Frame * previous_sibling,FrameInsertType insert_type,const base::UnguessableToken & frame_token,WindowAgentFactory * inheriting_agent_factory,InterfaceRegistry * interface_registry,AssociatedInterfaceProvider * associated_interface_provider)92 RemoteFrame::RemoteFrame(
93 RemoteFrameClient* client,
94 Page& page,
95 FrameOwner* owner,
96 Frame* parent,
97 Frame* previous_sibling,
98 FrameInsertType insert_type,
99 const base::UnguessableToken& frame_token,
100 WindowAgentFactory* inheriting_agent_factory,
101 InterfaceRegistry* interface_registry,
102 AssociatedInterfaceProvider* associated_interface_provider)
103 : Frame(client,
104 page,
105 owner,
106 parent,
107 previous_sibling,
108 insert_type,
109 frame_token,
110 MakeGarbageCollected<RemoteWindowProxyManager>(*this),
111 inheriting_agent_factory),
112 interface_registry_(interface_registry
113 ? interface_registry
114 : InterfaceRegistry::GetEmptyInterfaceRegistry()),
115 task_runner_(page.GetPageScheduler()
116 ->GetAgentGroupScheduler()
117 .DefaultTaskRunner()) {
118 // TODO(crbug.com/1094850): Remove this check once the renderer is correctly
119 // handling errors during the creation of HTML portal elements, which would
120 // otherwise cause RemoteFrame() being created with empty frame tokens.
121 if (!frame_token.is_empty()) {
122 auto frame_tracking_result = GetRemoteFramesMap().insert(
123 base::UnguessableTokenHash()(frame_token), this);
124 CHECK(frame_tracking_result.stored_value) << "Inserting a duplicate item.";
125 }
126
127 dom_window_ = MakeGarbageCollected<RemoteDOMWindow>(*this);
128
129 interface_registry->AddAssociatedInterface(WTF::BindRepeating(
130 &RemoteFrame::BindToReceiver, WrapWeakPersistent(this)));
131
132 DCHECK(task_runner_);
133 associated_interface_provider->GetInterface(
134 remote_frame_host_remote_.BindNewEndpointAndPassReceiver(task_runner_));
135
136 UpdateInertIfPossible();
137 UpdateInheritedEffectiveTouchActionIfPossible();
138 UpdateVisibleToHitTesting();
139 Initialize();
140 }
141
~RemoteFrame()142 RemoteFrame::~RemoteFrame() {
143 DCHECK(!view_);
144 }
145
Trace(Visitor * visitor) const146 void RemoteFrame::Trace(Visitor* visitor) const {
147 visitor->Trace(view_);
148 visitor->Trace(security_context_);
149 Frame::Trace(visitor);
150 }
151
Navigate(FrameLoadRequest & frame_request,WebFrameLoadType frame_load_type)152 void RemoteFrame::Navigate(FrameLoadRequest& frame_request,
153 WebFrameLoadType frame_load_type) {
154 // RemoteFrame::Navigate doesn't support policies like
155 // kNavigationPolicyNewForegroundTab - such policies need to be handled via
156 // local frames.
157 DCHECK_EQ(kNavigationPolicyCurrentTab, frame_request.GetNavigationPolicy());
158
159 if (HTMLFrameOwnerElement* element = DeprecatedLocalOwner())
160 element->CancelPendingLazyLoad();
161
162 if (!navigation_rate_limiter().CanProceed())
163 return;
164
165 frame_request.SetFrameType(IsMainFrame()
166 ? mojom::RequestContextFrameType::kTopLevel
167 : mojom::RequestContextFrameType::kNested);
168
169 const KURL& url = frame_request.GetResourceRequest().Url();
170 auto* window = frame_request.GetOriginWindow();
171 if (!frame_request.CanDisplay(url)) {
172 if (window) {
173 window->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
174 mojom::blink::ConsoleMessageSource::kSecurity,
175 mojom::blink::ConsoleMessageLevel::kError,
176 "Not allowed to load local resource: " + url.ElidedString()));
177 }
178 return;
179 }
180
181 // The process where this frame actually lives won't have sufficient
182 // information to upgrade the url, since it won't have access to the
183 // origin context. Do it now.
184 const FetchClientSettingsObject* fetch_client_settings_object = nullptr;
185 if (window) {
186 fetch_client_settings_object =
187 &window->Fetcher()->GetProperties().GetFetchClientSettingsObject();
188 }
189 MixedContentChecker::UpgradeInsecureRequest(
190 frame_request.GetResourceRequest(), fetch_client_settings_object, window,
191 frame_request.GetFrameType(),
192 window ? window->GetFrame()->GetContentSettingsClient() : nullptr);
193
194 // Navigations in portal contexts do not create back/forward entries.
195 if (GetPage()->InsidePortal() &&
196 frame_load_type == WebFrameLoadType::kStandard) {
197 frame_load_type = WebFrameLoadType::kReplaceCurrentItem;
198 }
199
200 WebLocalFrame* initiator_frame =
201 window ? window->GetFrame()->Client()->GetWebFrame() : nullptr;
202
203 bool is_opener_navigation = false;
204 bool initiator_frame_has_download_sandbox_flag = false;
205 bool initiator_frame_is_ad = false;
206
207 if (window) {
208 is_opener_navigation = window->GetFrame()->Opener() == this;
209 initiator_frame_has_download_sandbox_flag =
210 window->IsSandboxed(network::mojom::blink::WebSandboxFlags::kDownloads);
211 initiator_frame_is_ad = window->GetFrame()->IsAdSubframe();
212 if (frame_request.ClientRedirectReason() != ClientNavigationReason::kNone) {
213 probe::FrameRequestedNavigation(window->GetFrame(), this, url,
214 frame_request.ClientRedirectReason(),
215 kNavigationPolicyCurrentTab);
216 }
217 }
218
219 Client()->Navigate(frame_request.GetResourceRequest(), initiator_frame,
220 frame_load_type == WebFrameLoadType::kReplaceCurrentItem,
221 is_opener_navigation,
222 initiator_frame_has_download_sandbox_flag,
223 initiator_frame_is_ad, frame_request.GetBlobURLToken(),
224 frame_request.Impression());
225 }
226
DetachImpl(FrameDetachType type)227 void RemoteFrame::DetachImpl(FrameDetachType type) {
228 PluginScriptForbiddenScope forbid_plugin_destructor_scripting;
229 DetachChildren();
230 if (!Client())
231 return;
232
233 // Clean up the frame's view if needed. A remote frame only has a view if
234 // the parent is a local frame.
235 if (view_)
236 view_->Dispose();
237 GetWindowProxyManager()->ClearForClose();
238 SetView(nullptr);
239 // ... the RemoteDOMWindow will need to be informed of detachment,
240 // as otherwise it will keep a strong reference back to this RemoteFrame.
241 // That combined with wrappers (owned and kept alive by RemoteFrame) keeping
242 // persistent strong references to RemoteDOMWindow will prevent the GCing
243 // of all these objects. Break the cycle by notifying of detachment.
244 To<RemoteDOMWindow>(dom_window_.Get())->FrameDetached();
245 if (cc_layer_)
246 SetCcLayer(nullptr, false, false);
247 receiver_.reset();
248 main_frame_receiver_.reset();
249 }
250
DetachDocument()251 bool RemoteFrame::DetachDocument() {
252 DetachChildren();
253 return !!GetPage();
254 }
255
CheckCompleted()256 void RemoteFrame::CheckCompleted() {
257 // Notify the client so that the corresponding LocalFrame can do the check.
258 GetRemoteFrameHostRemote().CheckCompleted();
259 }
260
GetSecurityContext() const261 const RemoteSecurityContext* RemoteFrame::GetSecurityContext() const {
262 return &security_context_;
263 }
264
ShouldClose()265 bool RemoteFrame::ShouldClose() {
266 // TODO(nasko): Implement running the beforeunload handler in the actual
267 // LocalFrame running in a different process and getting back a real result.
268 return true;
269 }
270
SetIsInert(bool inert)271 void RemoteFrame::SetIsInert(bool inert) {
272 if (inert != is_inert_)
273 GetRemoteFrameHostRemote().SetIsInert(inert);
274 is_inert_ = inert;
275 }
276
SetInheritedEffectiveTouchAction(TouchAction touch_action)277 void RemoteFrame::SetInheritedEffectiveTouchAction(TouchAction touch_action) {
278 if (inherited_effective_touch_action_ != touch_action)
279 GetRemoteFrameHostRemote().SetInheritedEffectiveTouchAction(touch_action);
280 inherited_effective_touch_action_ = touch_action;
281 }
282
BubbleLogicalScrollFromChildFrame(mojom::blink::ScrollDirection direction,ScrollGranularity granularity,Frame * child)283 bool RemoteFrame::BubbleLogicalScrollFromChildFrame(
284 mojom::blink::ScrollDirection direction,
285 ScrollGranularity granularity,
286 Frame* child) {
287 DCHECK(child->Client());
288 To<LocalFrame>(child)
289 ->GetLocalFrameHostRemote()
290 .BubbleLogicalScrollInParentFrame(direction, granularity);
291 return false;
292 }
293
RenderFallbackContent()294 void RemoteFrame::RenderFallbackContent() {
295 // TODO(ekaramad): If the owner renders its own content, then the current
296 // ContentFrame() should detach and free-up the OOPIF process (see
297 // https://crbug.com/850223).
298 auto* owner = DeprecatedLocalOwner();
299 DCHECK(IsA<HTMLObjectElement>(owner));
300 owner->RenderFallbackContent(this);
301 }
302
AddResourceTimingFromChild(mojom::blink::ResourceTimingInfoPtr timing)303 void RemoteFrame::AddResourceTimingFromChild(
304 mojom::blink::ResourceTimingInfoPtr timing) {
305 HTMLFrameOwnerElement* owner_element = To<HTMLFrameOwnerElement>(Owner());
306 DCHECK(owner_element);
307
308 // TODO(https://crbug.com/900700): Take a Mojo pending receiver for
309 // WorkerTimingContainer for navigation from the calling function.
310 DOMWindowPerformance::performance(*owner_element->GetDocument().domWindow())
311 ->AddResourceTiming(std::move(timing), owner_element->localName(),
312 /*worker_timing_receiver=*/mojo::NullReceiver(),
313 owner_element->GetDocument().GetExecutionContext());
314 }
315
DidStartLoading()316 void RemoteFrame::DidStartLoading() {
317 SetIsLoading(true);
318 }
319
DidStopLoading()320 void RemoteFrame::DidStopLoading() {
321 SetIsLoading(false);
322
323 // When a subframe finishes loading, the parent should check if *all*
324 // subframes have finished loading (which may mean that the parent can declare
325 // that the parent itself has finished loading). This remote-subframe-focused
326 // code has a local-subframe equivalent in FrameLoader::DidFinishNavigation.
327 Frame* parent = Tree().Parent();
328 if (parent)
329 parent->CheckCompleted();
330 }
331
DidFocus()332 void RemoteFrame::DidFocus() {
333 GetRemoteFrameHostRemote().DidFocusFrame();
334 }
335
SetView(RemoteFrameView * view)336 void RemoteFrame::SetView(RemoteFrameView* view) {
337 // Oilpan: as RemoteFrameView performs no finalization actions,
338 // no explicit Dispose() of it needed here. (cf. LocalFrameView::Dispose().)
339 view_ = view;
340 }
341
CreateView()342 void RemoteFrame::CreateView() {
343 // If the RemoteFrame does not have a LocalFrame parent, there's no need to
344 // create a EmbeddedContentView for it.
345 if (!DeprecatedLocalOwner())
346 return;
347
348 DCHECK(!DeprecatedLocalOwner()->OwnedEmbeddedContentView());
349
350 SetView(MakeGarbageCollected<RemoteFrameView>(this));
351
352 if (OwnerLayoutObject())
353 DeprecatedLocalOwner()->SetEmbeddedContentView(view_);
354 }
355
ForwardPostMessage(MessageEvent * message_event,base::Optional<base::UnguessableToken> cluster_id,scoped_refptr<const SecurityOrigin> target_security_origin,LocalFrame * source_frame)356 void RemoteFrame::ForwardPostMessage(
357 MessageEvent* message_event,
358 base::Optional<base::UnguessableToken> cluster_id,
359 scoped_refptr<const SecurityOrigin> target_security_origin,
360 LocalFrame* source_frame) {
361 base::Optional<base::UnguessableToken> source_token;
362 if (source_frame)
363 source_token = source_frame->GetFrameToken();
364
365 String source_origin = message_event->origin();
366 String target_origin = g_empty_string;
367 if (target_security_origin)
368 target_origin = target_security_origin->ToString();
369
370 GetRemoteFrameHostRemote().RouteMessageEvent(
371 source_token, source_origin, target_origin,
372 BlinkTransferableMessage::FromMessageEvent(message_event, cluster_id));
373 }
374
GetRemoteFrameHostRemote()375 mojom::blink::RemoteFrameHost& RemoteFrame::GetRemoteFrameHostRemote() {
376 return *remote_frame_host_remote_.get();
377 }
378
GetRemoteAssociatedInterfaces()379 AssociatedInterfaceProvider* RemoteFrame::GetRemoteAssociatedInterfaces() {
380 DCHECK(Client());
381 return Client()->GetRemoteAssociatedInterfaces();
382 }
383
Client() const384 RemoteFrameClient* RemoteFrame::Client() const {
385 return static_cast<RemoteFrameClient*>(Frame::Client());
386 }
387
DidChangeVisibleToHitTesting()388 void RemoteFrame::DidChangeVisibleToHitTesting() {
389 if (!cc_layer_ || !is_surface_layer_)
390 return;
391
392 static_cast<cc::SurfaceLayer*>(cc_layer_)->SetHasPointerEventsNone(
393 IsIgnoredForHitTest());
394 }
395
SetReplicatedFeaturePolicyHeaderAndOpenerPolicies(const ParsedFeaturePolicy & parsed_header,const FeaturePolicyFeatureState & opener_feature_state)396 void RemoteFrame::SetReplicatedFeaturePolicyHeaderAndOpenerPolicies(
397 const ParsedFeaturePolicy& parsed_header,
398 const FeaturePolicyFeatureState& opener_feature_state) {
399 feature_policy_header_ = parsed_header;
400 if (RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled()) {
401 DCHECK(opener_feature_state.empty() || IsMainFrame());
402 if (OpenerFeatureState().empty()) {
403 SetOpenerFeatureState(opener_feature_state);
404 }
405 }
406 ApplyReplicatedFeaturePolicyHeader();
407 }
408
SetReplicatedSandboxFlags(network::mojom::blink::WebSandboxFlags flags)409 void RemoteFrame::SetReplicatedSandboxFlags(
410 network::mojom::blink::WebSandboxFlags flags) {
411 security_context_.ResetAndEnforceSandboxFlags(flags);
412 }
413
SetInsecureRequestPolicy(mojom::blink::InsecureRequestPolicy policy)414 void RemoteFrame::SetInsecureRequestPolicy(
415 mojom::blink::InsecureRequestPolicy policy) {
416 security_context_.SetInsecureRequestPolicy(policy);
417 }
418
SetInsecureNavigationsSet(const WebVector<unsigned> & set)419 void RemoteFrame::SetInsecureNavigationsSet(const WebVector<unsigned>& set) {
420 security_context_.SetInsecureNavigationsSet(set);
421 }
422
WillEnterFullscreen(mojom::blink::FullscreenOptionsPtr request_options)423 void RemoteFrame::WillEnterFullscreen(
424 mojom::blink::FullscreenOptionsPtr request_options) {
425 // This should only ever be called when the FrameOwner is local.
426 HTMLFrameOwnerElement* owner_element = To<HTMLFrameOwnerElement>(Owner());
427
428 // Call |requestFullscreen()| on |ownerElement| to make it the pending
429 // fullscreen element in anticipation of the coming |didEnterFullscreen()|
430 // call.
431 //
432 // ForCrossProcessDescendant is necessary because:
433 // - The fullscreen element ready check and other checks should be bypassed.
434 // - |ownerElement| will need :-webkit-full-screen-ancestor style in addition
435 // to :fullscreen.
436 FullscreenRequestType request_type =
437 (request_options->is_prefixed ? FullscreenRequestType::kPrefixed
438 : FullscreenRequestType::kUnprefixed) |
439 (request_options->is_xr_overlay ? FullscreenRequestType::kForXrOverlay
440 : FullscreenRequestType::kNull) |
441 FullscreenRequestType::kForCrossProcessDescendant;
442
443 Fullscreen::RequestFullscreen(*owner_element, FullscreenOptions::Create(),
444 request_type);
445 }
446
AddReplicatedContentSecurityPolicies(WTF::Vector<network::mojom::blink::ContentSecurityPolicyHeaderPtr> headers)447 void RemoteFrame::AddReplicatedContentSecurityPolicies(
448 WTF::Vector<network::mojom::blink::ContentSecurityPolicyHeaderPtr>
449 headers) {
450 for (auto& header : headers) {
451 GetSecurityContext()->GetContentSecurityPolicy()->AddPolicyFromHeaderValue(
452 header->header_value, header->type, header->source);
453 }
454 }
455
ResetReplicatedContentSecurityPolicy()456 void RemoteFrame::ResetReplicatedContentSecurityPolicy() {
457 security_context_.ResetReplicatedContentSecurityPolicy();
458 }
459
EnforceInsecureNavigationsSet(const WTF::Vector<uint32_t> & set)460 void RemoteFrame::EnforceInsecureNavigationsSet(
461 const WTF::Vector<uint32_t>& set) {
462 security_context_.SetInsecureNavigationsSet(set);
463 }
464
SetFrameOwnerProperties(mojom::blink::FrameOwnerPropertiesPtr properties)465 void RemoteFrame::SetFrameOwnerProperties(
466 mojom::blink::FrameOwnerPropertiesPtr properties) {
467 Frame::ApplyFrameOwnerProperties(std::move(properties));
468 }
469
EnforceInsecureRequestPolicy(mojom::blink::InsecureRequestPolicy policy)470 void RemoteFrame::EnforceInsecureRequestPolicy(
471 mojom::blink::InsecureRequestPolicy policy) {
472 SetInsecureRequestPolicy(policy);
473 }
474
SetReplicatedOrigin(const scoped_refptr<const SecurityOrigin> & origin,bool is_potentially_trustworthy_unique_origin)475 void RemoteFrame::SetReplicatedOrigin(
476 const scoped_refptr<const SecurityOrigin>& origin,
477 bool is_potentially_trustworthy_unique_origin) {
478 scoped_refptr<SecurityOrigin> security_origin = origin->IsolatedCopy();
479 security_origin->SetOpaqueOriginIsPotentiallyTrustworthy(
480 is_potentially_trustworthy_unique_origin);
481 security_context_.SetReplicatedOrigin(security_origin);
482 ApplyReplicatedFeaturePolicyHeader();
483
484 // If the origin of a remote frame changed, the accessibility object for the
485 // owner element now points to a different child.
486 //
487 // TODO(dmazzoni, dcheng): there's probably a better way to solve this.
488 // Run SitePerProcessAccessibilityBrowserTest.TwoCrossSiteNavigations to
489 // ensure an alternate fix works. http://crbug.com/566222
490 FrameOwner* owner = Owner();
491 HTMLElement* owner_element = DynamicTo<HTMLFrameOwnerElement>(owner);
492 if (owner_element) {
493 AXObjectCache* cache = owner_element->GetDocument().ExistingAXObjectCache();
494 if (cache)
495 cache->ChildrenChanged(owner_element);
496 }
497 }
498
SetReplicatedAdFrameType(mojom::blink::AdFrameType ad_frame_type)499 void RemoteFrame::SetReplicatedAdFrameType(
500 mojom::blink::AdFrameType ad_frame_type) {
501 if (ad_frame_type_ == mojom::blink::AdFrameType::kNonAd) {
502 ad_frame_type_ = ad_frame_type;
503 } else {
504 DCHECK_EQ(ad_frame_type_, ad_frame_type);
505 }
506 }
507
SetReplicatedName(const String & name,const String & unique_name)508 void RemoteFrame::SetReplicatedName(const String& name,
509 const String& unique_name) {
510 Tree().SetName(AtomicString(name));
511 unique_name_ = unique_name;
512 }
513
DispatchLoadEventForFrameOwner()514 void RemoteFrame::DispatchLoadEventForFrameOwner() {
515 DCHECK(Owner()->IsLocal());
516 Owner()->DispatchLoad();
517 }
518
Collapse(bool collapsed)519 void RemoteFrame::Collapse(bool collapsed) {
520 FrameOwner* owner = Owner();
521 To<HTMLFrameOwnerElement>(owner)->SetCollapsed(collapsed);
522 }
523
Focus()524 void RemoteFrame::Focus() {
525 FocusImpl();
526 }
527
SetHadStickyUserActivationBeforeNavigation(bool value)528 void RemoteFrame::SetHadStickyUserActivationBeforeNavigation(bool value) {
529 Frame::SetHadStickyUserActivationBeforeNavigation(value);
530 }
531
SetNeedsOcclusionTracking(bool needs_tracking)532 void RemoteFrame::SetNeedsOcclusionTracking(bool needs_tracking) {
533 View()->SetNeedsOcclusionTracking(needs_tracking);
534 }
535
BubbleLogicalScroll(mojom::blink::ScrollDirection direction,ui::ScrollGranularity granularity)536 void RemoteFrame::BubbleLogicalScroll(mojom::blink::ScrollDirection direction,
537 ui::ScrollGranularity granularity) {
538 Frame* parent_frame = Parent();
539 DCHECK(parent_frame);
540 DCHECK(parent_frame->IsLocalFrame());
541
542 parent_frame->BubbleLogicalScrollFromChildFrame(direction, granularity, this);
543 }
544
UpdateUserActivationState(mojom::blink::UserActivationUpdateType update_type,mojom::blink::UserActivationNotificationType notification_type)545 void RemoteFrame::UpdateUserActivationState(
546 mojom::blink::UserActivationUpdateType update_type,
547 mojom::blink::UserActivationNotificationType notification_type) {
548 switch (update_type) {
549 case mojom::blink::UserActivationUpdateType::kNotifyActivation:
550 NotifyUserActivationInFrameTree(notification_type);
551 break;
552 case mojom::blink::UserActivationUpdateType::kConsumeTransientActivation:
553 ConsumeTransientUserActivationInFrameTree();
554 break;
555 case mojom::blink::UserActivationUpdateType::kClearActivation:
556 ClearUserActivationInFrameTree();
557 break;
558 case mojom::blink::UserActivationUpdateType::
559 kNotifyActivationPendingBrowserVerification:
560 NOTREACHED() << "Unexpected UserActivationUpdateType from browser";
561 break;
562 }
563 }
564
SetEmbeddingToken(const base::UnguessableToken & embedding_token)565 void RemoteFrame::SetEmbeddingToken(
566 const base::UnguessableToken& embedding_token) {
567 DCHECK(IsA<HTMLFrameOwnerElement>(Owner()));
568 Frame::SetEmbeddingToken(embedding_token);
569 }
570
SetPageFocus(bool is_focused)571 void RemoteFrame::SetPageFocus(bool is_focused) {
572 WebFrame::FromFrame(this)->View()->SetFocus(is_focused);
573 }
574
ScrollRectToVisible(const gfx::Rect & rect_to_scroll,mojom::blink::ScrollIntoViewParamsPtr params)575 void RemoteFrame::ScrollRectToVisible(
576 const gfx::Rect& rect_to_scroll,
577 mojom::blink::ScrollIntoViewParamsPtr params) {
578 Element* owner_element = DeprecatedLocalOwner();
579 LayoutObject* owner_object = owner_element->GetLayoutObject();
580 if (!owner_object) {
581 // The LayoutObject could be nullptr by the time we get here. For instance
582 // <iframe>'s style might have been set to 'display: none' right after
583 // scrolling starts in the OOPIF's process (see https://crbug.com/777811).
584 return;
585 }
586
587 // Schedule the scroll.
588 PhysicalRect absolute_rect = owner_object->LocalToAncestorRect(
589 PhysicalRect(LayoutUnit(rect_to_scroll.x()),
590 LayoutUnit(rect_to_scroll.y()),
591 LayoutUnit(rect_to_scroll.width()),
592 LayoutUnit(rect_to_scroll.height())),
593 owner_object->View());
594
595 if (!params->zoom_into_rect ||
596 !owner_object->GetDocument().GetFrame()->LocalFrameRoot().IsMainFrame()) {
597 owner_object->ScrollRectToVisible(absolute_rect, std::move(params));
598 return;
599 }
600
601 // ZoomAndScrollToFocusedEditableElementRect will scroll only the layout and
602 // visual viewports. Ensure the element is actually visible in the viewport
603 // scrolling layer. (i.e. isn't clipped by some other content).
604 auto relative_element_bounds = params->relative_element_bounds;
605 auto relative_caret_bounds = params->relative_caret_bounds;
606
607 params->stop_at_main_frame_layout_viewport = true;
608 absolute_rect =
609 owner_object->ScrollRectToVisible(absolute_rect, std::move(params));
610
611 IntRect rect_in_document =
612 owner_object->GetDocument()
613 .GetFrame()
614 ->LocalFrameRoot()
615 .View()
616 ->RootFrameToDocument(EnclosingIntRect(
617 owner_element->GetDocument().View()->ConvertToRootFrame(
618 absolute_rect)));
619 IntRect element_bounds_in_document = EnclosingIntRect(
620 DeNormalizeRect(relative_element_bounds, rect_in_document));
621 IntRect caret_bounds_in_document = EnclosingIntRect(
622 DeNormalizeRect(relative_caret_bounds, rect_in_document));
623
624 // This is due to something such as scroll focused editable element into
625 // view on Android which also requires an automatic zoom into legible scale.
626 // This is handled by main frame's WebView.
627 WebViewImpl* web_view =
628 static_cast<WebViewImpl*>(WebFrame::FromFrame(this)->View());
629 web_view->ZoomAndScrollToFocusedEditableElementRect(
630 element_bounds_in_document, caret_bounds_in_document, true);
631 }
632
IntrinsicSizingInfoOfChildChanged(mojom::blink::IntrinsicSizingInfoPtr info)633 void RemoteFrame::IntrinsicSizingInfoOfChildChanged(
634 mojom::blink::IntrinsicSizingInfoPtr info) {
635 FrameOwner* owner = Owner();
636 // Only communication from HTMLPluginElement-owned subframes is allowed
637 // at present. This includes <embed> and <object> tags.
638 if (!owner || !owner->IsPlugin())
639 return;
640
641 // TODO(https://crbug.com/1044304): Should either remove the native
642 // C++ Blink type and use the Mojo type everywhere or typemap the
643 // Mojo type to the pre-existing native C++ Blink type.
644 IntrinsicSizingInfo sizing_info;
645 sizing_info.size = FloatSize(info->size);
646 sizing_info.aspect_ratio = FloatSize(info->aspect_ratio);
647 sizing_info.has_width = info->has_width;
648 sizing_info.has_height = info->has_height;
649 View()->SetIntrinsicSizeInfo(sizing_info);
650
651 owner->IntrinsicSizingInfoChanged();
652 }
653
654 // Update the proxy's SecurityContext with new sandbox flags or feature policy
655 // that were set during navigation. Unlike changes to the FrameOwner, which are
656 // handled by RemoteFrame::DidUpdateFramePolicy, these changes should be
657 // considered effective immediately.
658 //
659 // These flags / policy are needed on the remote frame's SecurityContext to
660 // ensure that sandbox flags and feature policy are inherited properly if this
661 // proxy ever parents a local frame.
DidSetFramePolicyHeaders(network::mojom::blink::WebSandboxFlags sandbox_flags,const WTF::Vector<ParsedFeaturePolicyDeclaration> & parsed_feature_policy)662 void RemoteFrame::DidSetFramePolicyHeaders(
663 network::mojom::blink::WebSandboxFlags sandbox_flags,
664 const WTF::Vector<ParsedFeaturePolicyDeclaration>& parsed_feature_policy) {
665 SetReplicatedSandboxFlags(sandbox_flags);
666 // Convert from WTF::Vector<ParsedFeaturePolicyDeclaration>
667 // to std::vector<ParsedFeaturePolicyDeclaration>, since ParsedFeaturePolicy
668 // is an alias for the later.
669 //
670 // TODO(crbug.com/1047273): Remove this conversion by switching
671 // ParsedFeaturePolicy to operate over Vector
672 ParsedFeaturePolicy parsed_feature_policy_copy(parsed_feature_policy.size());
673 for (size_t i = 0; i < parsed_feature_policy.size(); ++i)
674 parsed_feature_policy_copy[i] = parsed_feature_policy[i];
675 SetReplicatedFeaturePolicyHeaderAndOpenerPolicies(
676 parsed_feature_policy_copy, FeaturePolicyFeatureState());
677 }
678
679 // Update the proxy's FrameOwner with new sandbox flags and container policy
680 // that were set by its parent in another process.
681 //
682 // Normally, when a frame's sandbox attribute is changed dynamically, the
683 // frame's FrameOwner is updated with the new sandbox flags right away, while
684 // the frame's SecurityContext is updated when the frame is navigated and the
685 // new sandbox flags take effect.
686 //
687 // Currently, there is no use case for a proxy's pending FrameOwner sandbox
688 // flags, so there's no message sent to proxies when the sandbox attribute is
689 // first updated. Instead, the active flags are updated when they take effect,
690 // by OnDidSetActiveSandboxFlags. The proxy's FrameOwner flags are updated here
691 // with the caveat that the FrameOwner won't learn about updates to its flags
692 // until they take effect.
DidUpdateFramePolicy(const FramePolicy & frame_policy)693 void RemoteFrame::DidUpdateFramePolicy(const FramePolicy& frame_policy) {
694 // At the moment, this is only used to replicate sandbox flags and container
695 // policy for frames with a remote owner.
696 SECURITY_CHECK(IsA<RemoteFrameOwner>(Owner()));
697 To<RemoteFrameOwner>(Owner())->SetFramePolicy(frame_policy);
698 }
699
UpdateOpener(const base::Optional<base::UnguessableToken> & opener_frame_token)700 void RemoteFrame::UpdateOpener(
701 const base::Optional<base::UnguessableToken>& opener_frame_token) {
702 if (auto* web_frame = WebFrame::FromFrame(this)) {
703 Frame* opener_frame = nullptr;
704 if (opener_frame_token)
705 opener_frame = Frame::ResolveFrame(opener_frame_token.value());
706 SetOpenerDoNotNotify(opener_frame);
707 }
708 }
709
GetMainFrameViewportSize() const710 IntSize RemoteFrame::GetMainFrameViewportSize() const {
711 HTMLFrameOwnerElement* owner = DeprecatedLocalOwner();
712 DCHECK(owner);
713 DCHECK(owner->GetDocument().GetFrame());
714 return owner->GetDocument().GetFrame()->GetMainFrameViewportSize();
715 }
716
GetMainFrameScrollOffset() const717 IntPoint RemoteFrame::GetMainFrameScrollOffset() const {
718 HTMLFrameOwnerElement* owner = DeprecatedLocalOwner();
719 DCHECK(owner);
720 DCHECK(owner->GetDocument().GetFrame());
721 return owner->GetDocument().GetFrame()->GetMainFrameScrollOffset();
722 }
723
SetOpener(Frame * opener_frame)724 void RemoteFrame::SetOpener(Frame* opener_frame) {
725 if (Opener() == opener_frame)
726 return;
727
728 auto* web_frame = WebFrame::FromFrame(this);
729 if (web_frame) {
730 // A proxy shouldn't normally be disowning its opener. It is possible to
731 // get here when a proxy that is being detached clears its opener, in
732 // which case there is no need to notify the browser process.
733 if (opener_frame) {
734 // Only a LocalFrame (i.e., the caller of window.open) should be able to
735 // update another frame's opener.
736 DCHECK(opener_frame->IsLocalFrame());
737 GetRemoteFrameHostRemote().DidChangeOpener(
738 opener_frame ? base::Optional<base::UnguessableToken>(
739 opener_frame->GetFrameToken())
740 : base::nullopt);
741 }
742 }
743 SetOpenerDoNotNotify(opener_frame);
744 }
745
UpdateTextAutosizerPageInfo(mojom::blink::TextAutosizerPageInfoPtr mojo_remote_page_info)746 void RemoteFrame::UpdateTextAutosizerPageInfo(
747 mojom::blink::TextAutosizerPageInfoPtr mojo_remote_page_info) {
748 // Only propagate the remote page info if our main frame is remote.
749 DCHECK(IsMainFrame());
750 Frame* root_frame = GetPage()->MainFrame();
751 DCHECK(root_frame->IsRemoteFrame());
752 if (*mojo_remote_page_info == GetPage()->TextAutosizerPageInfo())
753 return;
754
755 GetPage()->SetTextAutosizerPageInfo(*mojo_remote_page_info);
756 TextAutosizer::UpdatePageInfoInAllFrames(root_frame);
757 }
758
WasAttachedAsRemoteMainFrame()759 void RemoteFrame::WasAttachedAsRemoteMainFrame() {
760 interface_registry_->AddAssociatedInterface(WTF::BindRepeating(
761 &RemoteFrame::BindToMainFrameReceiver, WrapWeakPersistent(this)));
762 }
763
GetFrameSinkId()764 viz::FrameSinkId RemoteFrame::GetFrameSinkId() {
765 return Client()->GetFrameSinkId();
766 }
767
IsIgnoredForHitTest() const768 bool RemoteFrame::IsIgnoredForHitTest() const {
769 HTMLFrameOwnerElement* owner = DeprecatedLocalOwner();
770 if (!owner || !owner->GetLayoutObject())
771 return false;
772
773 return owner->OwnerType() == mojom::blink::FrameOwnerElementType::kPortal ||
774 !visible_to_hit_testing_;
775 }
776
SetCcLayer(cc::Layer * cc_layer,bool prevent_contents_opaque_changes,bool is_surface_layer)777 void RemoteFrame::SetCcLayer(cc::Layer* cc_layer,
778 bool prevent_contents_opaque_changes,
779 bool is_surface_layer) {
780 DCHECK(Owner());
781
782 cc_layer_ = cc_layer;
783 prevent_contents_opaque_changes_ = prevent_contents_opaque_changes;
784 is_surface_layer_ = is_surface_layer;
785 if (cc_layer_) {
786 if (is_surface_layer) {
787 static_cast<cc::SurfaceLayer*>(cc_layer_)->SetHasPointerEventsNone(
788 IsIgnoredForHitTest());
789 }
790 }
791 HTMLFrameOwnerElement* owner = To<HTMLFrameOwnerElement>(Owner());
792 owner->SetNeedsCompositingUpdate();
793
794 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
795 // New layers for remote frames are controlled by Blink's embedder.
796 // To ensure the new surface is painted, we need to repaint the frame
797 // owner's PaintLayer.
798 LayoutBoxModelObject* layout_object = owner->GetLayoutBoxModelObject();
799 if (layout_object && layout_object->Layer())
800 layout_object->Layer()->SetNeedsRepaint();
801 }
802 }
803
AdvanceFocus(mojom::blink::FocusType type,LocalFrame * source)804 void RemoteFrame::AdvanceFocus(mojom::blink::FocusType type,
805 LocalFrame* source) {
806 GetRemoteFrameHostRemote().AdvanceFocus(type, source->GetFrameToken());
807 }
808
DetachChildren()809 void RemoteFrame::DetachChildren() {
810 using FrameVector = HeapVector<Member<Frame>>;
811 FrameVector children_to_detach;
812 children_to_detach.ReserveCapacity(Tree().ChildCount());
813 for (Frame* child = Tree().FirstChild(); child;
814 child = child->Tree().NextSibling())
815 children_to_detach.push_back(child);
816 for (const auto& child : children_to_detach)
817 child->Detach(FrameDetachType::kRemove);
818 }
819
ApplyReplicatedFeaturePolicyHeader()820 void RemoteFrame::ApplyReplicatedFeaturePolicyHeader() {
821 const FeaturePolicy* parent_feature_policy = nullptr;
822 if (Frame* parent_frame = Parent()) {
823 parent_feature_policy =
824 parent_frame->GetSecurityContext()->GetFeaturePolicy();
825 }
826 ParsedFeaturePolicy container_policy;
827 if (Owner())
828 container_policy = Owner()->GetFramePolicy().container_policy;
829 const FeaturePolicyFeatureState& opener_feature_state = OpenerFeatureState();
830 security_context_.InitializeFeaturePolicy(
831 feature_policy_header_, container_policy, parent_feature_policy,
832 opener_feature_state.empty() ? nullptr : &opener_feature_state);
833 }
834
BindToReceiver(RemoteFrame * frame,mojo::PendingAssociatedReceiver<mojom::blink::RemoteFrame> receiver)835 void RemoteFrame::BindToReceiver(
836 RemoteFrame* frame,
837 mojo::PendingAssociatedReceiver<mojom::blink::RemoteFrame> receiver) {
838 DCHECK(frame);
839 frame->receiver_.Bind(std::move(receiver), frame->task_runner_);
840 }
841
BindToMainFrameReceiver(RemoteFrame * frame,mojo::PendingAssociatedReceiver<mojom::blink::RemoteMainFrame> receiver)842 void RemoteFrame::BindToMainFrameReceiver(
843 RemoteFrame* frame,
844 mojo::PendingAssociatedReceiver<mojom::blink::RemoteMainFrame> receiver) {
845 DCHECK(frame);
846 frame->main_frame_receiver_.Bind(std::move(receiver), frame->task_runner_);
847 }
848
849 } // namespace blink
850