| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/renderer/core/frame/remote_frame.h" |
| |
| #include "base/stl_util.h" |
| #include "cc/layers/surface_layer.h" |
| #include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h" |
| #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" |
| #include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom-blink.h" |
| #include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom-blink.h" |
| #include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h" |
| #include "third_party/blink/public/platform/interface_registry.h" |
| #include "third_party/blink/public/web/web_frame.h" |
| #include "third_party/blink/public/web/web_view.h" |
| #include "third_party/blink/renderer/bindings/core/v8/v8_fullscreen_options.h" |
| #include "third_party/blink/renderer/bindings/core/v8/window_proxy.h" |
| #include "third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h" |
| #include "third_party/blink/renderer/core/events/message_event.h" |
| #include "third_party/blink/renderer/core/exported/web_view_impl.h" |
| #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h" |
| #include "third_party/blink/renderer/core/frame/local_dom_window.h" |
| #include "third_party/blink/renderer/core/frame/local_frame.h" |
| #include "third_party/blink/renderer/core/frame/local_frame_client.h" |
| #include "third_party/blink/renderer/core/frame/remote_dom_window.h" |
| #include "third_party/blink/renderer/core/frame/remote_frame_client.h" |
| #include "third_party/blink/renderer/core/frame/remote_frame_owner.h" |
| #include "third_party/blink/renderer/core/frame/remote_frame_view.h" |
| #include "third_party/blink/renderer/core/frame/user_activation.h" |
| #include "third_party/blink/renderer/core/fullscreen/fullscreen.h" |
| #include "third_party/blink/renderer/core/html/html_frame_owner_element.h" |
| #include "third_party/blink/renderer/core/inspector/console_message.h" |
| #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h" |
| #include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h" |
| #include "third_party/blink/renderer/core/layout/layout_embedded_content.h" |
| #include "third_party/blink/renderer/core/layout/layout_view.h" |
| #include "third_party/blink/renderer/core/layout/text_autosizer.h" |
| #include "third_party/blink/renderer/core/loader/frame_load_request.h" |
| #include "third_party/blink/renderer/core/loader/frame_loader.h" |
| #include "third_party/blink/renderer/core/loader/mixed_content_checker.h" |
| #include "third_party/blink/renderer/core/messaging/blink_transferable_message.h" |
| #include "third_party/blink/renderer/core/page/page.h" |
| #include "third_party/blink/renderer/core/page/plugin_script_forbidden_scope.h" |
| #include "third_party/blink/renderer/core/paint/paint_layer.h" |
| #include "third_party/blink/renderer/core/probe/core_probes.h" |
| #include "third_party/blink/renderer/core/timing/dom_window_performance.h" |
| #include "third_party/blink/renderer/platform/graphics/graphics_layer.h" |
| #include "third_party/blink/renderer/platform/heap/heap.h" |
| #include "third_party/blink/renderer/platform/heap/heap_allocator.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h" |
| #include "third_party/blink/renderer/platform/weborigin/security_policy.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| // Maintain a global (statically-allocated) hash map indexed by the the result |
| // of hashing the |frame_token| passed on creation of a RemoteFrame object. |
| typedef HeapHashMap<uint64_t, WeakMember<RemoteFrame>> RemoteFramesByTokenMap; |
| static RemoteFramesByTokenMap& GetRemoteFramesMap() { |
| DEFINE_STATIC_LOCAL(Persistent<RemoteFramesByTokenMap>, map, |
| (MakeGarbageCollected<RemoteFramesByTokenMap>())); |
| return *map; |
| } |
| |
| FloatRect DeNormalizeRect(const gfx::RectF& normalized, const IntRect& base) { |
| FloatRect result(normalized); |
| result.Scale(base.Width(), base.Height()); |
| result.MoveBy(FloatPoint(base.Location())); |
| return result; |
| } |
| |
| } // namespace |
| |
| // static |
| RemoteFrame* RemoteFrame::FromFrameToken(const RemoteFrameToken& frame_token) { |
| RemoteFramesByTokenMap& remote_frames_map = GetRemoteFramesMap(); |
| auto it = remote_frames_map.find(RemoteFrameToken::Hasher()(frame_token)); |
| return it == remote_frames_map.end() ? nullptr : it->value.Get(); |
| } |
| |
| RemoteFrame::RemoteFrame( |
| RemoteFrameClient* client, |
| Page& page, |
| FrameOwner* owner, |
| Frame* parent, |
| Frame* previous_sibling, |
| FrameInsertType insert_type, |
| const RemoteFrameToken& frame_token, |
| WindowAgentFactory* inheriting_agent_factory, |
| InterfaceRegistry* interface_registry, |
| AssociatedInterfaceProvider* associated_interface_provider) |
| : Frame(client, |
| page, |
| owner, |
| parent, |
| previous_sibling, |
| insert_type, |
| frame_token, |
| MakeGarbageCollected<RemoteWindowProxyManager>(*this), |
| inheriting_agent_factory), |
| // TODO(samans): Investigate if it is safe to delay creation of this |
| // object until a FrameSinkId is provided. |
| parent_local_surface_id_allocator_( |
| std::make_unique<viz::ParentLocalSurfaceIdAllocator>()), |
| interface_registry_(interface_registry |
| ? interface_registry |
| : InterfaceRegistry::GetEmptyInterfaceRegistry()), |
| task_runner_(page.GetPageScheduler() |
| ->GetAgentGroupScheduler() |
| .DefaultTaskRunner()) { |
| // TODO(crbug.com/1094850): Remove this check once the renderer is correctly |
| // handling errors during the creation of HTML portal elements, which would |
| // otherwise cause RemoteFrame() being created with empty frame tokens. |
| if (!frame_token.value().is_empty()) { |
| auto frame_tracking_result = GetRemoteFramesMap().insert( |
| RemoteFrameToken::Hasher()(frame_token), this); |
| CHECK(frame_tracking_result.stored_value) << "Inserting a duplicate item."; |
| } |
| |
| dom_window_ = MakeGarbageCollected<RemoteDOMWindow>(*this); |
| |
| interface_registry->AddAssociatedInterface(WTF::BindRepeating( |
| &RemoteFrame::BindToReceiver, WrapWeakPersistent(this))); |
| |
| DCHECK(task_runner_); |
| associated_interface_provider->GetInterface( |
| remote_frame_host_remote_.BindNewEndpointAndPassReceiver(task_runner_)); |
| |
| UpdateInertIfPossible(); |
| UpdateInheritedEffectiveTouchActionIfPossible(); |
| UpdateVisibleToHitTesting(); |
| Initialize(); |
| } |
| |
| RemoteFrame::~RemoteFrame() { |
| DCHECK(!view_); |
| } |
| |
| void RemoteFrame::DetachAndDispose() { |
| DCHECK(!IsMainFrame()); |
| Detach(FrameDetachType::kRemove); |
| } |
| |
| void RemoteFrame::Trace(Visitor* visitor) const { |
| visitor->Trace(view_); |
| visitor->Trace(security_context_); |
| Frame::Trace(visitor); |
| } |
| |
| void RemoteFrame::Navigate(FrameLoadRequest& frame_request, |
| WebFrameLoadType frame_load_type) { |
| // RemoteFrame::Navigate doesn't support policies like |
| // kNavigationPolicyNewForegroundTab - such policies need to be handled via |
| // local frames. |
| DCHECK_EQ(kNavigationPolicyCurrentTab, frame_request.GetNavigationPolicy()); |
| |
| if (HTMLFrameOwnerElement* element = DeprecatedLocalOwner()) |
| element->CancelPendingLazyLoad(); |
| |
| if (!navigation_rate_limiter().CanProceed()) |
| return; |
| |
| frame_request.SetFrameType(IsMainFrame() |
| ? mojom::RequestContextFrameType::kTopLevel |
| : mojom::RequestContextFrameType::kNested); |
| |
| const KURL& url = frame_request.GetResourceRequest().Url(); |
| auto* window = frame_request.GetOriginWindow(); |
| |
| // Note that even if |window| is not null, it could have just been detached |
| // (so window->GetFrame() is null). This can happen for a form submission, if |
| // the frame containing the form has been deleted in between. |
| |
| if (!frame_request.CanDisplay(url)) { |
| if (window) { |
| window->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>( |
| mojom::blink::ConsoleMessageSource::kSecurity, |
| mojom::blink::ConsoleMessageLevel::kError, |
| "Not allowed to load local resource: " + url.ElidedString())); |
| } |
| return; |
| } |
| |
| // The process where this frame actually lives won't have sufficient |
| // information to upgrade the url, since it won't have access to the |
| // origin context. Do it now. |
| const FetchClientSettingsObject* fetch_client_settings_object = nullptr; |
| if (window) { |
| fetch_client_settings_object = |
| &window->Fetcher()->GetProperties().GetFetchClientSettingsObject(); |
| } |
| MixedContentChecker::UpgradeInsecureRequest( |
| frame_request.GetResourceRequest(), fetch_client_settings_object, window, |
| frame_request.GetFrameType(), |
| (window && window->GetFrame()) |
| ? window->GetFrame()->GetContentSettingsClient() |
| : nullptr); |
| |
| // Navigations in portal contexts do not create back/forward entries. |
| if (GetPage()->InsidePortal() && |
| frame_load_type == WebFrameLoadType::kStandard) { |
| frame_load_type = WebFrameLoadType::kReplaceCurrentItem; |
| } |
| |
| bool is_opener_navigation = false; |
| bool initiator_frame_has_download_sandbox_flag = false; |
| bool initiator_frame_is_ad = false; |
| |
| base::Optional<LocalFrameToken> initiator_frame_token = |
| base::OptionalFromPtr(frame_request.GetInitiatorFrameToken()); |
| mojo::PendingRemote<mojom::blink::PolicyContainerHostKeepAliveHandle> |
| initiator_policy_container_keep_alive_handle = |
| frame_request.TakeInitiatorPolicyContainerKeepAliveHandle(); |
| |
| // |initiator_frame_token| and |initiator_policy_container_keep_alive_handle| |
| // should either be both specified or both null. |
| DCHECK(!initiator_frame_token == |
| !initiator_policy_container_keep_alive_handle); |
| |
| if (window) { |
| initiator_frame_has_download_sandbox_flag = |
| window->IsSandboxed(network::mojom::blink::WebSandboxFlags::kDownloads); |
| if (window->GetFrame()) { |
| is_opener_navigation = window->GetFrame()->Opener() == this; |
| initiator_frame_is_ad = window->GetFrame()->IsAdSubframe(); |
| if (frame_request.ClientRedirectReason() != |
| ClientNavigationReason::kNone) { |
| probe::FrameRequestedNavigation(window->GetFrame(), this, url, |
| frame_request.ClientRedirectReason(), |
| kNavigationPolicyCurrentTab); |
| } |
| |
| if (!initiator_frame_token) { |
| initiator_frame_token = window->GetFrame()->GetLocalFrameToken(); |
| initiator_policy_container_keep_alive_handle = |
| window->GetFrame()->GetPolicyContainer()->IssueKeepAliveHandle(); |
| } |
| } |
| } |
| |
| // TODO(https://crbug.com/1173409 and https://crbug.com/1059959): Check that |
| // we always have valid |initiator_frame_token| and |
| // |initiator_policy_container_keep_alive_handle|. |
| |
| Client()->Navigate(frame_request.GetResourceRequest(), |
| frame_load_type == WebFrameLoadType::kReplaceCurrentItem, |
| is_opener_navigation, |
| initiator_frame_has_download_sandbox_flag, |
| initiator_frame_is_ad, frame_request.GetBlobURLToken(), |
| frame_request.Impression(), |
| base::OptionalOrNullptr(initiator_frame_token), |
| std::move(initiator_policy_container_keep_alive_handle)); |
| } |
| |
| bool RemoteFrame::DetachImpl(FrameDetachType type) { |
| PluginScriptForbiddenScope forbid_plugin_destructor_scripting; |
| |
| if (!DetachChildren()) |
| return false; |
| |
| // Clean up the frame's view if needed. A remote frame only has a view if |
| // the parent is a local frame. |
| if (view_) |
| view_->Dispose(); |
| SetView(nullptr); |
| // ... the RemoteDOMWindow will need to be informed of detachment, |
| // as otherwise it will keep a strong reference back to this RemoteFrame. |
| // That combined with wrappers (owned and kept alive by RemoteFrame) keeping |
| // persistent strong references to RemoteDOMWindow will prevent the GCing |
| // of all these objects. Break the cycle by notifying of detachment. |
| To<RemoteDOMWindow>(dom_window_.Get())->FrameDetached(); |
| if (cc_layer_) |
| SetCcLayer(nullptr, false); |
| receiver_.reset(); |
| main_frame_receiver_.reset(); |
| |
| return true; |
| } |
| |
| bool RemoteFrame::DetachDocument() { |
| return DetachChildren(); |
| } |
| |
| void RemoteFrame::CheckCompleted() { |
| // Notify the client so that the corresponding LocalFrame can do the check. |
| GetRemoteFrameHostRemote().CheckCompleted(); |
| } |
| |
| const RemoteSecurityContext* RemoteFrame::GetSecurityContext() const { |
| return &security_context_; |
| } |
| |
| bool RemoteFrame::ShouldClose() { |
| // TODO(nasko): Implement running the beforeunload handler in the actual |
| // LocalFrame running in a different process and getting back a real result. |
| return true; |
| } |
| |
| void RemoteFrame::SetIsInert(bool inert) { |
| if (inert != is_inert_) |
| GetRemoteFrameHostRemote().SetIsInert(inert); |
| is_inert_ = inert; |
| } |
| |
| void RemoteFrame::SetInheritedEffectiveTouchAction(TouchAction touch_action) { |
| if (inherited_effective_touch_action_ != touch_action) |
| GetRemoteFrameHostRemote().SetInheritedEffectiveTouchAction(touch_action); |
| inherited_effective_touch_action_ = touch_action; |
| } |
| |
| bool RemoteFrame::BubbleLogicalScrollFromChildFrame( |
| mojom::blink::ScrollDirection direction, |
| ScrollGranularity granularity, |
| Frame* child) { |
| DCHECK(child->Client()); |
| To<LocalFrame>(child) |
| ->GetLocalFrameHostRemote() |
| .BubbleLogicalScrollInParentFrame(direction, granularity); |
| return false; |
| } |
| |
| void RemoteFrame::RenderFallbackContent() { |
| // TODO(ekaramad): If the owner renders its own content, then the current |
| // ContentFrame() should detach and free-up the OOPIF process (see |
| // https://crbug.com/850223). |
| auto* owner = DeprecatedLocalOwner(); |
| DCHECK(IsA<HTMLObjectElement>(owner)); |
| owner->RenderFallbackContent(this); |
| } |
| |
| void RemoteFrame::AddResourceTimingFromChild( |
| mojom::blink::ResourceTimingInfoPtr timing) { |
| HTMLFrameOwnerElement* owner_element = To<HTMLFrameOwnerElement>(Owner()); |
| DCHECK(owner_element); |
| |
| // TODO(https://crbug.com/900700): Take a Mojo pending receiver for |
| // WorkerTimingContainer for navigation from the calling function. |
| DOMWindowPerformance::performance(*owner_element->GetDocument().domWindow()) |
| ->AddResourceTiming(std::move(timing), owner_element->localName(), |
| /*worker_timing_receiver=*/mojo::NullReceiver(), |
| owner_element->GetDocument().GetExecutionContext()); |
| } |
| |
| void RemoteFrame::DidStartLoading() { |
| SetIsLoading(true); |
| } |
| |
| void RemoteFrame::DidStopLoading() { |
| SetIsLoading(false); |
| |
| // When a subframe finishes loading, the parent should check if *all* |
| // subframes have finished loading (which may mean that the parent can declare |
| // that the parent itself has finished loading). This remote-subframe-focused |
| // code has a local-subframe equivalent in FrameLoader::DidFinishNavigation. |
| Frame* parent = Tree().Parent(); |
| if (parent) |
| parent->CheckCompleted(); |
| } |
| |
| void RemoteFrame::DidFocus() { |
| GetRemoteFrameHostRemote().DidFocusFrame(); |
| } |
| |
| void RemoteFrame::SetView(RemoteFrameView* view) { |
| // Oilpan: as RemoteFrameView performs no finalization actions, |
| // no explicit Dispose() of it needed here. (cf. LocalFrameView::Dispose().) |
| view_ = view; |
| } |
| |
| void RemoteFrame::CreateView() { |
| // If the RemoteFrame does not have a LocalFrame parent, there's no need to |
| // create a EmbeddedContentView for it. |
| if (!DeprecatedLocalOwner()) |
| return; |
| |
| DCHECK(!DeprecatedLocalOwner()->OwnedEmbeddedContentView()); |
| |
| SetView(MakeGarbageCollected<RemoteFrameView>(this)); |
| |
| if (OwnerLayoutObject()) |
| DeprecatedLocalOwner()->SetEmbeddedContentView(view_); |
| } |
| |
| void RemoteFrame::ForwardPostMessage( |
| MessageEvent* message_event, |
| base::Optional<base::UnguessableToken> cluster_id, |
| scoped_refptr<const SecurityOrigin> target_security_origin, |
| LocalFrame* source_frame) { |
| base::Optional<blink::LocalFrameToken> source_token; |
| if (source_frame) |
| source_token = source_frame->GetLocalFrameToken(); |
| |
| String source_origin = message_event->origin(); |
| String target_origin = g_empty_string; |
| if (target_security_origin) |
| target_origin = target_security_origin->ToString(); |
| |
| GetRemoteFrameHostRemote().RouteMessageEvent( |
| source_token, source_origin, target_origin, |
| BlinkTransferableMessage::FromMessageEvent(message_event, cluster_id)); |
| } |
| |
| mojom::blink::RemoteFrameHost& RemoteFrame::GetRemoteFrameHostRemote() { |
| return *remote_frame_host_remote_.get(); |
| } |
| |
| AssociatedInterfaceProvider* RemoteFrame::GetRemoteAssociatedInterfaces() { |
| DCHECK(Client()); |
| return Client()->GetRemoteAssociatedInterfaces(); |
| } |
| |
| RemoteFrameClient* RemoteFrame::Client() const { |
| return static_cast<RemoteFrameClient*>(Frame::Client()); |
| } |
| |
| void RemoteFrame::DidChangeVisibleToHitTesting() { |
| if (!cc_layer_ || !is_surface_layer_) |
| return; |
| |
| static_cast<cc::SurfaceLayer*>(cc_layer_)->SetHasPointerEventsNone( |
| IsIgnoredForHitTest()); |
| } |
| |
| void RemoteFrame::SetReplicatedFeaturePolicyHeader( |
| const ParsedFeaturePolicy& parsed_header) { |
| feature_policy_header_ = parsed_header; |
| ApplyReplicatedFeaturePolicyHeader(); |
| } |
| |
| void RemoteFrame::SetReplicatedSandboxFlags( |
| network::mojom::blink::WebSandboxFlags flags) { |
| security_context_.ResetAndEnforceSandboxFlags(flags); |
| } |
| |
| void RemoteFrame::SetInsecureRequestPolicy( |
| mojom::blink::InsecureRequestPolicy policy) { |
| security_context_.SetInsecureRequestPolicy(policy); |
| } |
| |
| void RemoteFrame::SetInsecureNavigationsSet(const WebVector<unsigned>& set) { |
| security_context_.SetInsecureNavigationsSet(set); |
| } |
| |
| void RemoteFrame::FrameRectsChanged(const IntRect& local_frame_rect, |
| const IntRect& screen_space_rect) { |
| pending_visual_properties_.screen_space_rect = gfx::Rect(screen_space_rect); |
| pending_visual_properties_.local_frame_size = |
| gfx::Size(local_frame_rect.Width(), local_frame_rect.Height()); |
| SynchronizeVisualProperties(); |
| } |
| |
| void RemoteFrame::InitializeFrameVisualProperties( |
| const FrameVisualProperties& properties) { |
| pending_visual_properties_ = properties; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RemoteFrame::WillEnterFullscreen( |
| mojom::blink::FullscreenOptionsPtr request_options) { |
| // This should only ever be called when the FrameOwner is local. |
| HTMLFrameOwnerElement* owner_element = To<HTMLFrameOwnerElement>(Owner()); |
| |
| // Call |requestFullscreen()| on |ownerElement| to make it the pending |
| // fullscreen element in anticipation of the coming |didEnterFullscreen()| |
| // call. |
| // |
| // ForCrossProcessDescendant is necessary because: |
| // - The fullscreen element ready check and other checks should be bypassed. |
| // - |ownerElement| will need :-webkit-full-screen-ancestor style in addition |
| // to :fullscreen. |
| FullscreenRequestType request_type = |
| (request_options->is_prefixed ? FullscreenRequestType::kPrefixed |
| : FullscreenRequestType::kUnprefixed) | |
| (request_options->is_xr_overlay ? FullscreenRequestType::kForXrOverlay |
| : FullscreenRequestType::kNull) | |
| FullscreenRequestType::kForCrossProcessDescendant; |
| |
| Fullscreen::RequestFullscreen(*owner_element, FullscreenOptions::Create(), |
| request_type); |
| } |
| |
| void RemoteFrame::AddReplicatedContentSecurityPolicies( |
| WTF::Vector<network::mojom::blink::ContentSecurityPolicyPtr> csps) { |
| GetSecurityContext()->GetContentSecurityPolicy()->AddPolicies( |
| std::move(csps)); |
| } |
| |
| void RemoteFrame::ResetReplicatedContentSecurityPolicy() { |
| security_context_.ResetReplicatedContentSecurityPolicy(); |
| } |
| |
| void RemoteFrame::EnforceInsecureNavigationsSet( |
| const WTF::Vector<uint32_t>& set) { |
| security_context_.SetInsecureNavigationsSet(set); |
| } |
| |
| void RemoteFrame::SetFrameOwnerProperties( |
| mojom::blink::FrameOwnerPropertiesPtr properties) { |
| Frame::ApplyFrameOwnerProperties(std::move(properties)); |
| } |
| |
| void RemoteFrame::EnforceInsecureRequestPolicy( |
| mojom::blink::InsecureRequestPolicy policy) { |
| SetInsecureRequestPolicy(policy); |
| } |
| |
| void RemoteFrame::SetReplicatedOrigin( |
| const scoped_refptr<const SecurityOrigin>& origin, |
| bool is_potentially_trustworthy_unique_origin) { |
| scoped_refptr<SecurityOrigin> security_origin = origin->IsolatedCopy(); |
| security_origin->SetOpaqueOriginIsPotentiallyTrustworthy( |
| is_potentially_trustworthy_unique_origin); |
| security_context_.SetReplicatedOrigin(security_origin); |
| ApplyReplicatedFeaturePolicyHeader(); |
| |
| // If the origin of a remote frame changed, the accessibility object for the |
| // owner element now points to a different child. |
| // |
| // TODO(dmazzoni, dcheng): there's probably a better way to solve this. |
| // Run SitePerProcessAccessibilityBrowserTest.TwoCrossSiteNavigations to |
| // ensure an alternate fix works. http://crbug.com/566222 |
| FrameOwner* owner = Owner(); |
| HTMLElement* owner_element = DynamicTo<HTMLFrameOwnerElement>(owner); |
| if (owner_element) { |
| AXObjectCache* cache = owner_element->GetDocument().ExistingAXObjectCache(); |
| if (cache) |
| cache->ChildrenChanged(owner_element); |
| } |
| } |
| |
| void RemoteFrame::SetReplicatedAdFrameType( |
| mojom::blink::AdFrameType ad_frame_type) { |
| if (ad_frame_type_ == mojom::blink::AdFrameType::kNonAd) { |
| ad_frame_type_ = ad_frame_type; |
| } else { |
| DCHECK_EQ(ad_frame_type_, ad_frame_type); |
| } |
| } |
| |
| void RemoteFrame::SetReplicatedName(const String& name, |
| const String& unique_name) { |
| Tree().SetName(AtomicString(name)); |
| unique_name_ = unique_name; |
| } |
| |
| void RemoteFrame::DispatchLoadEventForFrameOwner() { |
| DCHECK(Owner()->IsLocal()); |
| Owner()->DispatchLoad(); |
| } |
| |
| void RemoteFrame::Collapse(bool collapsed) { |
| FrameOwner* owner = Owner(); |
| To<HTMLFrameOwnerElement>(owner)->SetCollapsed(collapsed); |
| } |
| |
| void RemoteFrame::Focus() { |
| FocusImpl(); |
| } |
| |
| void RemoteFrame::SetHadStickyUserActivationBeforeNavigation(bool value) { |
| Frame::SetHadStickyUserActivationBeforeNavigation(value); |
| } |
| |
| void RemoteFrame::SetNeedsOcclusionTracking(bool needs_tracking) { |
| View()->SetNeedsOcclusionTracking(needs_tracking); |
| } |
| |
| void RemoteFrame::BubbleLogicalScroll(mojom::blink::ScrollDirection direction, |
| ui::ScrollGranularity granularity) { |
| Frame* parent_frame = Parent(); |
| DCHECK(parent_frame); |
| DCHECK(parent_frame->IsLocalFrame()); |
| |
| parent_frame->BubbleLogicalScrollFromChildFrame(direction, granularity, this); |
| } |
| |
| void RemoteFrame::UpdateUserActivationState( |
| mojom::blink::UserActivationUpdateType update_type, |
| mojom::blink::UserActivationNotificationType notification_type) { |
| switch (update_type) { |
| case mojom::blink::UserActivationUpdateType::kNotifyActivation: |
| NotifyUserActivationInFrameTree(notification_type); |
| break; |
| case mojom::blink::UserActivationUpdateType::kConsumeTransientActivation: |
| ConsumeTransientUserActivationInFrameTree(); |
| break; |
| case mojom::blink::UserActivationUpdateType::kClearActivation: |
| ClearUserActivationInFrameTree(); |
| break; |
| case mojom::blink::UserActivationUpdateType:: |
| kNotifyActivationPendingBrowserVerification: |
| NOTREACHED() << "Unexpected UserActivationUpdateType from browser"; |
| break; |
| } |
| } |
| |
| void RemoteFrame::SetEmbeddingToken( |
| const base::UnguessableToken& embedding_token) { |
| DCHECK(IsA<HTMLFrameOwnerElement>(Owner())); |
| Frame::SetEmbeddingToken(embedding_token); |
| } |
| |
| void RemoteFrame::SetPageFocus(bool is_focused) { |
| static_cast<WebViewImpl*>(WebFrame::FromCoreFrame(this)->View()) |
| ->SetPageFocus(is_focused); |
| } |
| |
| void RemoteFrame::ScrollRectToVisible( |
| const gfx::Rect& rect_to_scroll, |
| mojom::blink::ScrollIntoViewParamsPtr params) { |
| Element* owner_element = DeprecatedLocalOwner(); |
| LayoutObject* owner_object = owner_element->GetLayoutObject(); |
| if (!owner_object) { |
| // The LayoutObject could be nullptr by the time we get here. For instance |
| // <iframe>'s style might have been set to 'display: none' right after |
| // scrolling starts in the OOPIF's process (see https://crbug.com/777811). |
| return; |
| } |
| |
| // Schedule the scroll. |
| PhysicalRect absolute_rect = owner_object->LocalToAncestorRect( |
| PhysicalRect(LayoutUnit(rect_to_scroll.x()), |
| LayoutUnit(rect_to_scroll.y()), |
| LayoutUnit(rect_to_scroll.width()), |
| LayoutUnit(rect_to_scroll.height())), |
| owner_object->View()); |
| |
| if (!params->zoom_into_rect || |
| !owner_object->GetDocument().GetFrame()->LocalFrameRoot().IsMainFrame()) { |
| owner_object->ScrollRectToVisible(absolute_rect, std::move(params)); |
| return; |
| } |
| |
| // ZoomAndScrollToFocusedEditableElementRect will scroll only the layout and |
| // visual viewports. Ensure the element is actually visible in the viewport |
| // scrolling layer. (i.e. isn't clipped by some other content). |
| auto relative_element_bounds = params->relative_element_bounds; |
| auto relative_caret_bounds = params->relative_caret_bounds; |
| |
| params->stop_at_main_frame_layout_viewport = true; |
| absolute_rect = |
| owner_object->ScrollRectToVisible(absolute_rect, std::move(params)); |
| |
| IntRect rect_in_document = |
| owner_object->GetDocument() |
| .GetFrame() |
| ->LocalFrameRoot() |
| .View() |
| ->RootFrameToDocument(EnclosingIntRect( |
| owner_element->GetDocument().View()->ConvertToRootFrame( |
| absolute_rect))); |
| IntRect element_bounds_in_document = EnclosingIntRect( |
| DeNormalizeRect(relative_element_bounds, rect_in_document)); |
| IntRect caret_bounds_in_document = EnclosingIntRect( |
| DeNormalizeRect(relative_caret_bounds, rect_in_document)); |
| |
| // This is due to something such as scroll focused editable element into |
| // view on Android which also requires an automatic zoom into legible scale. |
| // This is handled by main frame's WebView. |
| WebViewImpl* web_view = |
| static_cast<WebViewImpl*>(WebFrame::FromCoreFrame(this)->View()); |
| web_view->ZoomAndScrollToFocusedEditableElementRect( |
| element_bounds_in_document, caret_bounds_in_document, true); |
| } |
| |
| void RemoteFrame::IntrinsicSizingInfoOfChildChanged( |
| mojom::blink::IntrinsicSizingInfoPtr info) { |
| FrameOwner* owner = Owner(); |
| // Only communication from HTMLPluginElement-owned subframes is allowed |
| // at present. This includes <embed> and <object> tags. |
| if (!owner || !owner->IsPlugin()) |
| return; |
| |
| // TODO(https://crbug.com/1044304): Should either remove the native |
| // C++ Blink type and use the Mojo type everywhere or typemap the |
| // Mojo type to the pre-existing native C++ Blink type. |
| IntrinsicSizingInfo sizing_info; |
| sizing_info.size = FloatSize(info->size); |
| sizing_info.aspect_ratio = FloatSize(info->aspect_ratio); |
| sizing_info.has_width = info->has_width; |
| sizing_info.has_height = info->has_height; |
| View()->SetIntrinsicSizeInfo(sizing_info); |
| |
| owner->IntrinsicSizingInfoChanged(); |
| } |
| |
| // Update the proxy's SecurityContext with new sandbox flags or feature policy |
| // that were set during navigation. Unlike changes to the FrameOwner, which are |
| // handled by RemoteFrame::DidUpdateFramePolicy, these changes should be |
| // considered effective immediately. |
| // |
| // These flags / policy are needed on the remote frame's SecurityContext to |
| // ensure that sandbox flags and feature policy are inherited properly if this |
| // proxy ever parents a local frame. |
| void RemoteFrame::DidSetFramePolicyHeaders( |
| network::mojom::blink::WebSandboxFlags sandbox_flags, |
| const WTF::Vector<ParsedFeaturePolicyDeclaration>& parsed_feature_policy) { |
| SetReplicatedSandboxFlags(sandbox_flags); |
| // Convert from WTF::Vector<ParsedFeaturePolicyDeclaration> |
| // to std::vector<ParsedFeaturePolicyDeclaration>, since ParsedFeaturePolicy |
| // is an alias for the later. |
| // |
| // TODO(crbug.com/1047273): Remove this conversion by switching |
| // ParsedFeaturePolicy to operate over Vector |
| ParsedFeaturePolicy parsed_feature_policy_copy(parsed_feature_policy.size()); |
| for (size_t i = 0; i < parsed_feature_policy.size(); ++i) |
| parsed_feature_policy_copy[i] = parsed_feature_policy[i]; |
| SetReplicatedFeaturePolicyHeader(parsed_feature_policy_copy); |
| } |
| |
| // Update the proxy's FrameOwner with new sandbox flags and container policy |
| // that were set by its parent in another process. |
| // |
| // Normally, when a frame's sandbox attribute is changed dynamically, the |
| // frame's FrameOwner is updated with the new sandbox flags right away, while |
| // the frame's SecurityContext is updated when the frame is navigated and the |
| // new sandbox flags take effect. |
| // |
| // Currently, there is no use case for a proxy's pending FrameOwner sandbox |
| // flags, so there's no message sent to proxies when the sandbox attribute is |
| // first updated. Instead, the active flags are updated when they take effect, |
| // by OnDidSetActiveSandboxFlags. The proxy's FrameOwner flags are updated here |
| // with the caveat that the FrameOwner won't learn about updates to its flags |
| // until they take effect. |
| void RemoteFrame::DidUpdateFramePolicy(const FramePolicy& frame_policy) { |
| // At the moment, this is only used to replicate sandbox flags and container |
| // policy for frames with a remote owner. |
| SECURITY_CHECK(IsA<RemoteFrameOwner>(Owner())); |
| To<RemoteFrameOwner>(Owner())->SetFramePolicy(frame_policy); |
| } |
| |
| void RemoteFrame::UpdateOpener( |
| const base::Optional<blink::FrameToken>& opener_frame_token) { |
| if (auto* web_frame = WebFrame::FromCoreFrame(this)) { |
| Frame* opener_frame = nullptr; |
| if (opener_frame_token) |
| opener_frame = Frame::ResolveFrame(opener_frame_token.value()); |
| SetOpenerDoNotNotify(opener_frame); |
| } |
| } |
| |
| IntSize RemoteFrame::GetMainFrameViewportSize() const { |
| HTMLFrameOwnerElement* owner = DeprecatedLocalOwner(); |
| DCHECK(owner); |
| DCHECK(owner->GetDocument().GetFrame()); |
| return owner->GetDocument().GetFrame()->GetMainFrameViewportSize(); |
| } |
| |
| IntPoint RemoteFrame::GetMainFrameScrollOffset() const { |
| HTMLFrameOwnerElement* owner = DeprecatedLocalOwner(); |
| DCHECK(owner); |
| DCHECK(owner->GetDocument().GetFrame()); |
| return owner->GetDocument().GetFrame()->GetMainFrameScrollOffset(); |
| } |
| |
| void RemoteFrame::SetOpener(Frame* opener_frame) { |
| if (Opener() == opener_frame) |
| return; |
| |
| auto* web_frame = WebFrame::FromCoreFrame(this); |
| if (web_frame) { |
| // A proxy shouldn't normally be disowning its opener. It is possible to |
| // get here when a proxy that is being detached clears its opener, in |
| // which case there is no need to notify the browser process. |
| if (opener_frame) { |
| // Only a LocalFrame (i.e., the caller of window.open) should be able to |
| // update another frame's opener. |
| DCHECK(opener_frame->IsLocalFrame()); |
| GetRemoteFrameHostRemote().DidChangeOpener( |
| opener_frame |
| ? base::Optional<blink::LocalFrameToken>( |
| opener_frame->GetFrameToken().GetAs<LocalFrameToken>()) |
| : base::nullopt); |
| } |
| } |
| SetOpenerDoNotNotify(opener_frame); |
| } |
| |
| void RemoteFrame::UpdateTextAutosizerPageInfo( |
| mojom::blink::TextAutosizerPageInfoPtr mojo_remote_page_info) { |
| // Only propagate the remote page info if our main frame is remote. |
| DCHECK(IsMainFrame()); |
| Frame* root_frame = GetPage()->MainFrame(); |
| DCHECK(root_frame->IsRemoteFrame()); |
| if (*mojo_remote_page_info == GetPage()->TextAutosizerPageInfo()) |
| return; |
| |
| GetPage()->SetTextAutosizerPageInfo(*mojo_remote_page_info); |
| TextAutosizer::UpdatePageInfoInAllFrames(root_frame); |
| } |
| |
| void RemoteFrame::WasAttachedAsRemoteMainFrame() { |
| interface_registry_->AddAssociatedInterface(WTF::BindRepeating( |
| &RemoteFrame::BindToMainFrameReceiver, WrapWeakPersistent(this))); |
| } |
| |
| const viz::LocalSurfaceId& RemoteFrame::GetLocalSurfaceId() const { |
| return parent_local_surface_id_allocator_->GetCurrentLocalSurfaceId(); |
| } |
| |
| viz::FrameSinkId RemoteFrame::GetFrameSinkId() { |
| return frame_sink_id_; |
| } |
| |
| void RemoteFrame::SetFrameSinkId(const viz::FrameSinkId& frame_sink_id) { |
| // This is a temporary workaround for https://crbug.com/1166729. |
| // TODO(https://crbug.com/1166722): Remove this once the migration is done. |
| Client()->DidSetFrameSinkId(); |
| |
| // The same ParentLocalSurfaceIdAllocator cannot provide LocalSurfaceIds for |
| // two different frame sinks, so recreate it here. |
| if (frame_sink_id_ != frame_sink_id) { |
| parent_local_surface_id_allocator_ = |
| std::make_unique<viz::ParentLocalSurfaceIdAllocator>(); |
| } |
| frame_sink_id_ = frame_sink_id; |
| |
| // Resend the FrameRects and allocate a new viz::LocalSurfaceId when the view |
| // changes. |
| ResendVisualProperties(); |
| } |
| |
| bool RemoteFrame::IsIgnoredForHitTest() const { |
| HTMLFrameOwnerElement* owner = DeprecatedLocalOwner(); |
| if (!owner || !owner->GetLayoutObject()) |
| return false; |
| |
| return owner->OwnerType() == mojom::blink::FrameOwnerElementType::kPortal || |
| !visible_to_hit_testing_; |
| } |
| |
| void RemoteFrame::SetCcLayer(cc::Layer* cc_layer, bool is_surface_layer) { |
| DCHECK(Owner()); |
| |
| cc_layer_ = cc_layer; |
| is_surface_layer_ = is_surface_layer; |
| if (cc_layer_) { |
| if (is_surface_layer) { |
| static_cast<cc::SurfaceLayer*>(cc_layer_)->SetHasPointerEventsNone( |
| IsIgnoredForHitTest()); |
| } |
| } |
| HTMLFrameOwnerElement* owner = To<HTMLFrameOwnerElement>(Owner()); |
| owner->SetNeedsCompositingUpdate(); |
| |
| if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { |
| // New layers for remote frames are controlled by Blink's embedder. |
| // To ensure the new surface is painted, we need to repaint the frame |
| // owner's PaintLayer. |
| LayoutBoxModelObject* layout_object = owner->GetLayoutBoxModelObject(); |
| if (layout_object && layout_object->Layer()) |
| layout_object->Layer()->SetNeedsRepaint(); |
| } |
| |
| // Schedule an animation so that a new frame is produced with the updated |
| // layer, otherwise this local root's visible content may not be up to date. |
| owner->GetDocument().GetFrame()->View()->ScheduleAnimation(); |
| } |
| |
| void RemoteFrame::AdvanceFocus(mojom::blink::FocusType type, |
| LocalFrame* source) { |
| GetRemoteFrameHostRemote().AdvanceFocus(type, source->GetLocalFrameToken()); |
| } |
| |
| bool RemoteFrame::DetachChildren() { |
| using FrameVector = HeapVector<Member<Frame>>; |
| FrameVector children_to_detach; |
| children_to_detach.ReserveCapacity(Tree().ChildCount()); |
| for (Frame* child = Tree().FirstChild(); child; |
| child = child->Tree().NextSibling()) |
| children_to_detach.push_back(child); |
| for (const auto& child : children_to_detach) |
| child->Detach(FrameDetachType::kRemove); |
| |
| return !!Client(); |
| } |
| |
| void RemoteFrame::ApplyReplicatedFeaturePolicyHeader() { |
| const FeaturePolicy* parent_feature_policy = nullptr; |
| if (Frame* parent_frame = Parent()) { |
| parent_feature_policy = |
| parent_frame->GetSecurityContext()->GetFeaturePolicy(); |
| } |
| ParsedFeaturePolicy container_policy; |
| if (Owner()) |
| container_policy = Owner()->GetFramePolicy().container_policy; |
| security_context_.InitializeFeaturePolicy( |
| feature_policy_header_, container_policy, parent_feature_policy); |
| } |
| |
| bool RemoteFrame::SynchronizeVisualProperties(bool propagate) { |
| if (!GetFrameSinkId().is_valid() || Client()->RemoteProcessGone()) |
| return false; |
| |
| bool capture_sequence_number_changed = |
| sent_visual_properties_ && |
| sent_visual_properties_->capture_sequence_number != |
| pending_visual_properties_.capture_sequence_number; |
| |
| if (view_) { |
| pending_visual_properties_.compositor_viewport = |
| view_->GetCompositingRect(); |
| pending_visual_properties_.compositing_scale_factor = |
| view_->GetCompositingScaleFactor(); |
| } |
| |
| bool synchronized_props_changed = |
| !sent_visual_properties_ || |
| sent_visual_properties_->auto_resize_enabled != |
| pending_visual_properties_.auto_resize_enabled || |
| sent_visual_properties_->min_size_for_auto_resize != |
| pending_visual_properties_.min_size_for_auto_resize || |
| sent_visual_properties_->max_size_for_auto_resize != |
| pending_visual_properties_.max_size_for_auto_resize || |
| sent_visual_properties_->local_frame_size != |
| pending_visual_properties_.local_frame_size || |
| sent_visual_properties_->screen_space_rect.size() != |
| pending_visual_properties_.screen_space_rect.size() || |
| sent_visual_properties_->screen_info != |
| pending_visual_properties_.screen_info || |
| sent_visual_properties_->zoom_level != |
| pending_visual_properties_.zoom_level || |
| sent_visual_properties_->page_scale_factor != |
| pending_visual_properties_.page_scale_factor || |
| sent_visual_properties_->compositing_scale_factor != |
| pending_visual_properties_.compositing_scale_factor || |
| sent_visual_properties_->is_pinch_gesture_active != |
| pending_visual_properties_.is_pinch_gesture_active || |
| sent_visual_properties_->visible_viewport_size != |
| pending_visual_properties_.visible_viewport_size || |
| sent_visual_properties_->compositor_viewport != |
| pending_visual_properties_.compositor_viewport || |
| sent_visual_properties_->root_widget_window_segments != |
| pending_visual_properties_.root_widget_window_segments || |
| sent_visual_properties_->capture_sequence_number != |
| pending_visual_properties_.capture_sequence_number; |
| |
| if (synchronized_props_changed) |
| parent_local_surface_id_allocator_->GenerateId(); |
| pending_visual_properties_.local_surface_id = GetLocalSurfaceId(); |
| |
| viz::SurfaceId surface_id(frame_sink_id_, |
| pending_visual_properties_.local_surface_id); |
| Client()->WillSynchronizeVisualProperties( |
| capture_sequence_number_changed, surface_id, |
| pending_visual_properties_.compositor_viewport.size()); |
| |
| bool rect_changed = !sent_visual_properties_ || |
| sent_visual_properties_->screen_space_rect != |
| pending_visual_properties_.screen_space_rect; |
| bool visual_properties_changed = synchronized_props_changed || rect_changed; |
| |
| if (!visual_properties_changed) |
| return false; |
| |
| if (propagate) { |
| GetRemoteFrameHostRemote().SynchronizeVisualProperties( |
| pending_visual_properties_); |
| RecordSentVisualProperties(); |
| } |
| |
| return true; |
| } |
| |
| void RemoteFrame::RecordSentVisualProperties() { |
| sent_visual_properties_ = pending_visual_properties_; |
| TRACE_EVENT_WITH_FLOW2( |
| TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"), |
| "RenderFrameProxy::SynchronizeVisualProperties Send Message", |
| TRACE_ID_GLOBAL( |
| pending_visual_properties_.local_surface_id.submission_trace_id()), |
| TRACE_EVENT_FLAG_FLOW_OUT, "message", |
| "FrameHostMsg_SynchronizeVisualProperties", "local_surface_id", |
| pending_visual_properties_.local_surface_id.ToString()); |
| } |
| |
| void RemoteFrame::ResendVisualProperties() { |
| sent_visual_properties_ = base::nullopt; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RemoteFrame::DidUpdateVisualProperties( |
| const cc::RenderFrameMetadata& metadata) { |
| if (!parent_local_surface_id_allocator_->UpdateFromChild( |
| metadata.local_surface_id.value_or(viz::LocalSurfaceId()))) { |
| return; |
| } |
| |
| // The viz::LocalSurfaceId has changed so we call SynchronizeVisualProperties |
| // here to embed it. |
| SynchronizeVisualProperties(); |
| } |
| |
| void RemoteFrame::SetViewportIntersection( |
| const mojom::blink::ViewportIntersectionState& intersection_state) { |
| base::Optional<FrameVisualProperties> visual_properties; |
| if (SynchronizeVisualProperties(/*propagate=*/false)) { |
| visual_properties.emplace(pending_visual_properties_); |
| RecordSentVisualProperties(); |
| } |
| GetRemoteFrameHostRemote().UpdateViewportIntersection( |
| intersection_state.Clone(), visual_properties); |
| } |
| |
| void RemoteFrame::DidChangeScreenInfo(const ScreenInfo& screen_info) { |
| pending_visual_properties_.screen_info = screen_info; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RemoteFrame::ZoomLevelChanged(double zoom_level) { |
| pending_visual_properties_.zoom_level = zoom_level; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RemoteFrame::DidChangeRootWindowSegments( |
| const std::vector<gfx::Rect>& root_widget_window_segments) { |
| pending_visual_properties_.root_widget_window_segments = |
| std::move(root_widget_window_segments); |
| SynchronizeVisualProperties(); |
| } |
| |
| void RemoteFrame::PageScaleFactorChanged(float page_scale_factor, |
| bool is_pinch_gesture_active) { |
| pending_visual_properties_.page_scale_factor = page_scale_factor; |
| pending_visual_properties_.is_pinch_gesture_active = is_pinch_gesture_active; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RemoteFrame::DidChangeVisibleViewportSize( |
| const gfx::Size& visible_viewport_size) { |
| pending_visual_properties_.visible_viewport_size = visible_viewport_size; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RemoteFrame::UpdateCaptureSequenceNumber( |
| uint32_t capture_sequence_number) { |
| pending_visual_properties_.capture_sequence_number = capture_sequence_number; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RemoteFrame::EnableAutoResize(const gfx::Size& min_size, |
| const gfx::Size& max_size) { |
| pending_visual_properties_.auto_resize_enabled = true; |
| pending_visual_properties_.min_size_for_auto_resize = min_size; |
| pending_visual_properties_.max_size_for_auto_resize = max_size; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RemoteFrame::DisableAutoResize() { |
| pending_visual_properties_.auto_resize_enabled = false; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RemoteFrame::BindToReceiver( |
| RemoteFrame* frame, |
| mojo::PendingAssociatedReceiver<mojom::blink::RemoteFrame> receiver) { |
| DCHECK(frame); |
| frame->receiver_.Bind(std::move(receiver), frame->task_runner_); |
| } |
| |
| void RemoteFrame::BindToMainFrameReceiver( |
| RemoteFrame* frame, |
| mojo::PendingAssociatedReceiver<mojom::blink::RemoteMainFrame> receiver) { |
| DCHECK(frame); |
| frame->main_frame_receiver_.Bind(std::move(receiver), frame->task_runner_); |
| } |
| |
| } // namespace blink |