| // 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 "content/renderer/render_frame_proxy.h" |
| |
| #include <stdint.h> |
| #include <map> |
| #include <memory> |
| #include <utility> |
| |
| #include "base/command_line.h" |
| #include "base/lazy_instance.h" |
| #include "components/viz/common/surfaces/local_surface_id_allocation.h" |
| #include "content/common/content_switches_internal.h" |
| #include "content/common/frame_message_structs.h" |
| #include "content/common/frame_owner_properties.h" |
| #include "content/common/frame_replication_state.h" |
| #include "content/common/input_messages.h" |
| #include "content/common/page_messages.h" |
| #include "content/common/swapped_out_messages.h" |
| #include "content/common/unfreezable_frame_messages.h" |
| #include "content/common/view_messages.h" |
| #include "content/public/common/content_client.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/screen_info.h" |
| #include "content/public/common/use_zoom_for_dsf_policy.h" |
| #include "content/public/renderer/content_renderer_client.h" |
| #include "content/renderer/child_frame_compositing_helper.h" |
| #include "content/renderer/frame_owner_properties.h" |
| #include "content/renderer/loader/web_url_request_util.h" |
| #include "content/renderer/render_frame_impl.h" |
| #include "content/renderer/render_thread_impl.h" |
| #include "content/renderer/render_view_impl.h" |
| #include "content/renderer/render_widget.h" |
| #include "content/renderer/resource_timing_info_conversions.h" |
| #include "ipc/ipc_message_macros.h" |
| #include "mojo/public/cpp/bindings/pending_associated_remote.h" |
| #include "printing/buildflags/buildflags.h" |
| #include "third_party/blink/public/common/feature_policy/feature_policy.h" |
| #include "third_party/blink/public/common/frame/frame_policy.h" |
| #include "third_party/blink/public/common/navigation/triggering_event_info.h" |
| #include "third_party/blink/public/platform/url_conversion.h" |
| #include "third_party/blink/public/platform/web_rect.h" |
| #include "third_party/blink/public/platform/web_resource_timing_info.h" |
| #include "third_party/blink/public/platform/web_string.h" |
| #include "third_party/blink/public/web/web_local_frame.h" |
| #include "third_party/blink/public/web/web_user_gesture_indicator.h" |
| #include "third_party/blink/public/web/web_view.h" |
| #include "ui/gfx/geometry/size_conversions.h" |
| |
| #if BUILDFLAG(ENABLE_PRINTING) |
| // nogncheck because dependency on //printing is conditional upon |
| // enable_basic_printing flags. |
| #include "printing/metafile_skia.h" // nogncheck |
| #endif |
| |
| namespace content { |
| |
| namespace { |
| |
| // Facilitates lookup of RenderFrameProxy by routing_id. |
| typedef std::map<int, RenderFrameProxy*> RoutingIDProxyMap; |
| static base::LazyInstance<RoutingIDProxyMap>::DestructorAtExit |
| g_routing_id_proxy_map = LAZY_INSTANCE_INITIALIZER; |
| |
| // Facilitates lookup of RenderFrameProxy by WebRemoteFrame. |
| typedef std::map<blink::WebRemoteFrame*, RenderFrameProxy*> FrameProxyMap; |
| base::LazyInstance<FrameProxyMap>::DestructorAtExit g_frame_proxy_map = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| } // namespace |
| |
| // static |
| RenderFrameProxy* RenderFrameProxy::CreateProxyToReplaceFrame( |
| RenderFrameImpl* frame_to_replace, |
| int routing_id, |
| blink::WebTreeScopeType scope) { |
| CHECK_NE(routing_id, MSG_ROUTING_NONE); |
| |
| std::unique_ptr<RenderFrameProxy> proxy(new RenderFrameProxy(routing_id)); |
| proxy->unique_name_ = frame_to_replace->unique_name(); |
| proxy->devtools_frame_token_ = frame_to_replace->GetDevToolsFrameToken(); |
| |
| // When a RenderFrame is replaced by a RenderProxy, the WebRemoteFrame should |
| // always come from WebRemoteFrame::create and a call to WebFrame::swap must |
| // follow later. |
| blink::WebRemoteFrame* web_frame = |
| blink::WebRemoteFrame::Create(scope, proxy.get()); |
| |
| bool parent_is_local = |
| !frame_to_replace->GetWebFrame()->Parent() || |
| frame_to_replace->GetWebFrame()->Parent()->IsWebLocalFrame(); |
| |
| // If frame_to_replace has a RenderFrameProxy parent, then its |
| // RenderWidget will be destroyed along with it, so the new |
| // RenderFrameProxy uses its parent's RenderWidget. |
| RenderWidget* widget = |
| parent_is_local |
| ? frame_to_replace->GetLocalRootRenderWidget() |
| : RenderFrameProxy::FromWebFrame( |
| frame_to_replace->GetWebFrame()->Parent()->ToWebRemoteFrame()) |
| ->render_widget_; |
| proxy->Init(web_frame, frame_to_replace->render_view(), widget, |
| parent_is_local); |
| return proxy.release(); |
| } |
| |
| RenderFrameProxy* RenderFrameProxy::CreateFrameProxy( |
| int routing_id, |
| int render_view_routing_id, |
| blink::WebFrame* opener, |
| int parent_routing_id, |
| const FrameReplicationState& replicated_state, |
| const base::UnguessableToken& devtools_frame_token) { |
| RenderFrameProxy* parent = nullptr; |
| if (parent_routing_id != MSG_ROUTING_NONE) { |
| parent = RenderFrameProxy::FromRoutingID(parent_routing_id); |
| // It is possible that the parent proxy has been detached in this renderer |
| // process, just as the parent's real frame was creating this child frame. |
| // In this case, do not create the proxy. See https://crbug.com/568670. |
| if (!parent) |
| return nullptr; |
| } |
| |
| std::unique_ptr<RenderFrameProxy> proxy(new RenderFrameProxy(routing_id)); |
| proxy->devtools_frame_token_ = devtools_frame_token; |
| RenderViewImpl* render_view = nullptr; |
| RenderWidget* render_widget = nullptr; |
| blink::WebRemoteFrame* web_frame = nullptr; |
| |
| if (!parent) { |
| // Create a top level WebRemoteFrame. |
| render_view = RenderViewImpl::FromRoutingID(render_view_routing_id); |
| web_frame = blink::WebRemoteFrame::CreateMainFrame( |
| render_view->GetWebView(), proxy.get(), opener); |
| render_widget = render_view->GetWidget(); |
| } else { |
| // Create a frame under an existing parent. The parent is always expected |
| // to be a RenderFrameProxy, because navigations initiated by local frames |
| // should not wind up here. |
| web_frame = parent->web_frame()->CreateRemoteChild( |
| replicated_state.scope, |
| blink::WebString::FromUTF8(replicated_state.name), |
| replicated_state.frame_policy, |
| replicated_state.frame_owner_element_type, proxy.get(), opener); |
| proxy->unique_name_ = replicated_state.unique_name; |
| render_view = parent->render_view(); |
| render_widget = parent->render_widget_; |
| } |
| |
| proxy->Init(web_frame, render_view, render_widget, false); |
| |
| // Initialize proxy's WebRemoteFrame with the security origin and other |
| // replicated information. |
| // TODO(dcheng): Calling this when parent_routing_id != MSG_ROUTING_NONE is |
| // mostly redundant, since we already pass the name and sandbox flags in |
| // createLocalChild(). We should update the Blink interface so it also takes |
| // the origin. Then it will be clear that the replication call is only needed |
| // for the case of setting up a main frame proxy. |
| proxy->SetReplicatedState(replicated_state); |
| |
| return proxy.release(); |
| } |
| |
| RenderFrameProxy* RenderFrameProxy::CreateProxyForPortal( |
| RenderFrameImpl* parent, |
| int proxy_routing_id, |
| const base::UnguessableToken& devtools_frame_token, |
| const blink::WebElement& portal_element) { |
| std::unique_ptr<RenderFrameProxy> proxy( |
| new RenderFrameProxy(proxy_routing_id)); |
| proxy->devtools_frame_token_ = devtools_frame_token; |
| blink::WebRemoteFrame* web_frame = blink::WebRemoteFrame::CreateForPortal( |
| blink::WebTreeScopeType::kDocument, proxy.get(), portal_element); |
| proxy->Init(web_frame, parent->render_view(), |
| parent->GetLocalRootRenderWidget(), true); |
| return proxy.release(); |
| } |
| |
| // static |
| RenderFrameProxy* RenderFrameProxy::FromRoutingID(int32_t routing_id) { |
| RoutingIDProxyMap* proxies = g_routing_id_proxy_map.Pointer(); |
| auto it = proxies->find(routing_id); |
| return it == proxies->end() ? NULL : it->second; |
| } |
| |
| // static |
| RenderFrameProxy* RenderFrameProxy::FromWebFrame( |
| blink::WebRemoteFrame* web_frame) { |
| // TODO(dcheng): Turn this into a DCHECK() if it doesn't crash on canary. |
| CHECK(web_frame); |
| auto iter = g_frame_proxy_map.Get().find(web_frame); |
| if (iter != g_frame_proxy_map.Get().end()) { |
| RenderFrameProxy* proxy = iter->second; |
| DCHECK_EQ(web_frame, proxy->web_frame()); |
| return proxy; |
| } |
| // Reaching this is not expected: this implies that the |web_frame| in |
| // question is not managed by the content API, or the associated |
| // RenderFrameProxy is already deleted--in which case, it's not safe to touch |
| // |web_frame|. |
| NOTREACHED(); |
| return nullptr; |
| } |
| |
| RenderFrameProxy::RenderFrameProxy(int routing_id) |
| : routing_id_(routing_id), |
| provisional_frame_routing_id_(MSG_ROUTING_NONE), |
| web_frame_(nullptr), |
| render_view_(nullptr), |
| render_widget_(nullptr), |
| // 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>()) { |
| std::pair<RoutingIDProxyMap::iterator, bool> result = |
| g_routing_id_proxy_map.Get().insert(std::make_pair(routing_id_, this)); |
| CHECK(result.second) << "Inserting a duplicate item."; |
| RenderThread::Get()->AddRoute(routing_id_, this); |
| } |
| |
| RenderFrameProxy::~RenderFrameProxy() { |
| if (render_widget_) |
| render_widget_->UnregisterRenderFrameProxy(this); |
| |
| CHECK(!web_frame_); |
| RenderThread::Get()->RemoveRoute(routing_id_); |
| g_routing_id_proxy_map.Get().erase(routing_id_); |
| } |
| |
| void RenderFrameProxy::Init(blink::WebRemoteFrame* web_frame, |
| RenderViewImpl* render_view, |
| RenderWidget* render_widget, |
| bool parent_is_local) { |
| CHECK(web_frame); |
| CHECK(render_view); |
| |
| web_frame_ = web_frame; |
| render_view_ = render_view; |
| render_widget_ = render_widget; |
| |
| // |render_widget_| can be null if this is a proxy for a remote main frame, or |
| // a subframe of that proxy. We don't need to register as an observer [since |
| // the RenderWidget is undead/won't exist]. The observer is used to propagate |
| // VisualProperty changes down the frame/process hierarchy. Remote main frame |
| // proxies do not participate in this flow. |
| if (render_widget_) { |
| render_widget_->RegisterRenderFrameProxy(this); |
| pending_visual_properties_.screen_info = |
| render_widget_->GetOriginalScreenInfo(); |
| } |
| |
| std::pair<FrameProxyMap::iterator, bool> result = |
| g_frame_proxy_map.Get().insert(std::make_pair(web_frame_, this)); |
| CHECK(result.second) << "Inserted a duplicate item."; |
| |
| if (parent_is_local) |
| compositing_helper_ = std::make_unique<ChildFrameCompositingHelper>(this); |
| } |
| |
| void RenderFrameProxy::ResendVisualProperties() { |
| // Reset |sent_visual_properties_| in order to allocate a new |
| // viz::LocalSurfaceId. |
| sent_visual_properties_ = base::nullopt; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RenderFrameProxy::OnScreenInfoChanged(const ScreenInfo& screen_info) { |
| pending_visual_properties_.screen_info = screen_info; |
| if (crashed_) { |
| // Update the sad page to match the current ScreenInfo. |
| compositing_helper_->ChildFrameGone(local_frame_size(), |
| screen_info.device_scale_factor); |
| return; |
| } |
| SynchronizeVisualProperties(); |
| } |
| |
| void RenderFrameProxy::OnZoomLevelChanged(double zoom_level) { |
| pending_visual_properties_.zoom_level = zoom_level; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RenderFrameProxy::OnPageScaleFactorChanged(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 RenderFrameProxy::UpdateCaptureSequenceNumber( |
| uint32_t capture_sequence_number) { |
| pending_visual_properties_.capture_sequence_number = capture_sequence_number; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RenderFrameProxy::SetReplicatedState(const FrameReplicationState& state) { |
| DCHECK(web_frame_); |
| |
| web_frame_->SetReplicatedOrigin( |
| state.origin, state.has_potentially_trustworthy_unique_origin); |
| |
| #if DCHECK_IS_ON() |
| blink::WebSecurityOrigin security_origin_before_sandbox_flags = |
| web_frame_->GetSecurityOrigin(); |
| #endif |
| |
| web_frame_->SetReplicatedSandboxFlags(state.active_sandbox_flags); |
| |
| #if DCHECK_IS_ON() |
| // If |state.has_potentially_trustworthy_unique_origin| is set, |
| // - |state.origin| should be unique (this is checked in |
| // blink::SecurityOrigin::SetUniqueOriginIsPotentiallyTrustworthy() in |
| // SetReplicatedOrigin()), and thus |
| // - The security origin is not updated by SetReplicatedSandboxFlags() and |
| // thus we don't have to apply |has_potentially_trustworthy_unique_origin| |
| // flag after SetReplicatedSandboxFlags(). |
| if (state.has_potentially_trustworthy_unique_origin) |
| DCHECK(security_origin_before_sandbox_flags == |
| web_frame_->GetSecurityOrigin()); |
| #endif |
| |
| web_frame_->SetReplicatedName(blink::WebString::FromUTF8(state.name)); |
| web_frame_->SetReplicatedInsecureRequestPolicy(state.insecure_request_policy); |
| web_frame_->SetReplicatedInsecureNavigationsSet( |
| state.insecure_navigations_set); |
| web_frame_->SetReplicatedFeaturePolicyHeaderAndOpenerPolicies( |
| state.feature_policy_header, state.opener_feature_state); |
| if (state.has_received_user_gesture) { |
| web_frame_->UpdateUserActivationState( |
| blink::UserActivationUpdateType::kNotifyActivation); |
| } |
| web_frame_->SetHasReceivedUserGestureBeforeNavigation( |
| state.has_received_user_gesture_before_nav); |
| |
| web_frame_->ResetReplicatedContentSecurityPolicy(); |
| OnAddContentSecurityPolicies(state.accumulated_csp_headers); |
| } |
| |
| // 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 RenderFrameProxy::OnDidUpdateFramePolicy( |
| const blink::FramePolicy& frame_policy) { |
| DCHECK(web_frame()->Parent()); |
| web_frame_->SetFrameOwnerPolicy(frame_policy); |
| } |
| |
| // 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 OnDidUpdateFramePolicy, 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 RenderFrameProxy::OnDidSetFramePolicyHeaders( |
| blink::WebSandboxFlags active_sandbox_flags, |
| blink::ParsedFeaturePolicy feature_policy_header) { |
| web_frame_->SetReplicatedSandboxFlags(active_sandbox_flags); |
| web_frame_->SetReplicatedFeaturePolicyHeaderAndOpenerPolicies( |
| feature_policy_header, blink::FeaturePolicy::FeatureState()); |
| } |
| |
| bool RenderFrameProxy::OnMessageReceived(const IPC::Message& msg) { |
| // Page IPCs are routed via the main frame (both local and remote) and then |
| // forwarded to the RenderView. See comment in |
| // RenderFrameHostManager::SendPageMessage() for more information. |
| if ((IPC_MESSAGE_CLASS(msg) == PageMsgStart)) { |
| if (render_view()) |
| return render_view()->OnMessageReceived(msg); |
| |
| return false; |
| } |
| |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(RenderFrameProxy, msg) |
| IPC_MESSAGE_HANDLER(FrameMsg_ChildFrameProcessGone, OnChildFrameProcessGone) |
| IPC_MESSAGE_HANDLER(FrameMsg_IntrinsicSizingInfoOfChildChanged, |
| OnIntrinsicSizingInfoOfChildChanged) |
| IPC_MESSAGE_HANDLER(FrameMsg_UpdateOpener, OnUpdateOpener) |
| IPC_MESSAGE_HANDLER(FrameMsg_ViewChanged, OnViewChanged) |
| IPC_MESSAGE_HANDLER(FrameMsg_DidStartLoading, OnDidStartLoading) |
| IPC_MESSAGE_HANDLER(FrameMsg_DidStopLoading, OnDidStopLoading) |
| IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateFramePolicy, OnDidUpdateFramePolicy) |
| IPC_MESSAGE_HANDLER(FrameMsg_DidSetFramePolicyHeaders, |
| OnDidSetFramePolicyHeaders) |
| IPC_MESSAGE_HANDLER(FrameMsg_ForwardResourceTimingToParent, |
| OnForwardResourceTimingToParent) |
| IPC_MESSAGE_HANDLER(FrameMsg_DispatchLoad, OnDispatchLoad) |
| IPC_MESSAGE_HANDLER(FrameMsg_SetNeedsOcclusionTracking, |
| OnSetNeedsOcclusionTracking) |
| IPC_MESSAGE_HANDLER(FrameMsg_Collapse, OnCollapse) |
| IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateName, OnDidUpdateName) |
| IPC_MESSAGE_HANDLER(FrameMsg_AddContentSecurityPolicies, |
| OnAddContentSecurityPolicies) |
| IPC_MESSAGE_HANDLER(FrameMsg_ResetContentSecurityPolicy, |
| OnResetContentSecurityPolicy) |
| IPC_MESSAGE_HANDLER(FrameMsg_EnforceInsecureRequestPolicy, |
| OnEnforceInsecureRequestPolicy) |
| IPC_MESSAGE_HANDLER(FrameMsg_EnforceInsecureNavigationsSet, |
| OnEnforceInsecureNavigationsSet) |
| IPC_MESSAGE_HANDLER(FrameMsg_SetFrameOwnerProperties, |
| OnSetFrameOwnerProperties) |
| IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateOrigin, OnDidUpdateOrigin) |
| IPC_MESSAGE_HANDLER(InputMsg_SetFocus, OnSetPageFocus) |
| IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateVisualProperties, |
| OnDidUpdateVisualProperties) |
| IPC_MESSAGE_HANDLER(FrameMsg_EnableAutoResize, OnEnableAutoResize) |
| IPC_MESSAGE_HANDLER(FrameMsg_DisableAutoResize, OnDisableAutoResize) |
| IPC_MESSAGE_HANDLER(FrameMsg_SetFocusedFrame, OnSetFocusedFrame) |
| IPC_MESSAGE_HANDLER(FrameMsg_WillEnterFullscreen, OnWillEnterFullscreen) |
| IPC_MESSAGE_HANDLER(FrameMsg_UpdateUserActivationState, |
| OnUpdateUserActivationState) |
| IPC_MESSAGE_HANDLER(FrameMsg_TransferUserActivationFrom, |
| OnTransferUserActivationFrom) |
| IPC_MESSAGE_HANDLER(FrameMsg_ScrollRectToVisible, OnScrollRectToVisible) |
| IPC_MESSAGE_HANDLER(FrameMsg_BubbleLogicalScroll, OnBubbleLogicalScroll) |
| IPC_MESSAGE_HANDLER(FrameMsg_SetHasReceivedUserGestureBeforeNavigation, |
| OnSetHasReceivedUserGestureBeforeNavigation) |
| IPC_MESSAGE_HANDLER(FrameMsg_RenderFallbackContent, OnRenderFallbackContent) |
| IPC_MESSAGE_HANDLER(UnfreezableFrameMsg_DeleteProxy, OnDeleteProxy) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| |
| // Note: If |handled| is true, |this| may have been deleted. |
| return handled; |
| } |
| |
| bool RenderFrameProxy::Send(IPC::Message* message) { |
| return RenderThread::Get()->Send(message); |
| } |
| |
| void RenderFrameProxy::OnDeleteProxy() { |
| DCHECK(web_frame_); |
| web_frame_->Detach(); |
| } |
| |
| void RenderFrameProxy::OnChildFrameProcessGone() { |
| crashed_ = true; |
| compositing_helper_->ChildFrameGone(local_frame_size(), |
| screen_info().device_scale_factor); |
| } |
| |
| void RenderFrameProxy::OnIntrinsicSizingInfoOfChildChanged( |
| blink::WebIntrinsicSizingInfo sizing_info) { |
| web_frame()->IntrinsicSizingInfoChanged(sizing_info); |
| } |
| |
| void RenderFrameProxy::OnUpdateOpener(int opener_routing_id) { |
| blink::WebFrame* opener = RenderFrameImpl::ResolveOpener(opener_routing_id); |
| web_frame_->SetOpener(opener); |
| } |
| |
| void RenderFrameProxy::OnDidStartLoading() { |
| web_frame_->DidStartLoading(); |
| } |
| |
| void RenderFrameProxy::OnViewChanged( |
| const FrameMsg_ViewChanged_Params& params) { |
| crashed_ = false; |
| // The same ParentLocalSurfaceIdAllocator cannot provide LocalSurfaceIds for |
| // two different frame sinks, so recreate it here. |
| if (frame_sink_id_ != params.frame_sink_id) { |
| parent_local_surface_id_allocator_ = |
| std::make_unique<viz::ParentLocalSurfaceIdAllocator>(); |
| } |
| frame_sink_id_ = params.frame_sink_id; |
| |
| // Resend the FrameRects and allocate a new viz::LocalSurfaceId when the view |
| // changes. |
| ResendVisualProperties(); |
| } |
| |
| void RenderFrameProxy::OnDidStopLoading() { |
| web_frame_->DidStopLoading(); |
| } |
| |
| void RenderFrameProxy::OnForwardResourceTimingToParent( |
| const ResourceTimingInfo& info) { |
| web_frame_->ForwardResourceTimingToParent( |
| ResourceTimingInfoToWebResourceTimingInfo(info)); |
| } |
| |
| void RenderFrameProxy::OnDispatchLoad() { |
| web_frame_->DispatchLoadEventForFrameOwner(); |
| } |
| |
| void RenderFrameProxy::OnSetNeedsOcclusionTracking(bool needs_tracking) { |
| web_frame_->SetNeedsOcclusionTracking(needs_tracking); |
| } |
| |
| void RenderFrameProxy::OnCollapse(bool collapsed) { |
| web_frame_->Collapse(collapsed); |
| } |
| |
| void RenderFrameProxy::OnDidUpdateName(const std::string& name, |
| const std::string& unique_name) { |
| web_frame_->SetReplicatedName(blink::WebString::FromUTF8(name)); |
| unique_name_ = unique_name; |
| } |
| |
| void RenderFrameProxy::OnAddContentSecurityPolicies( |
| const std::vector<ContentSecurityPolicyHeader>& headers) { |
| for (const auto& header : headers) { |
| web_frame_->AddReplicatedContentSecurityPolicyHeader( |
| blink::WebString::FromUTF8(header.header_value), header.type, |
| header.source); |
| } |
| } |
| |
| void RenderFrameProxy::OnResetContentSecurityPolicy() { |
| web_frame_->ResetReplicatedContentSecurityPolicy(); |
| } |
| |
| void RenderFrameProxy::OnEnforceInsecureRequestPolicy( |
| blink::WebInsecureRequestPolicy policy) { |
| web_frame_->SetReplicatedInsecureRequestPolicy(policy); |
| } |
| |
| void RenderFrameProxy::OnEnforceInsecureNavigationsSet( |
| const std::vector<uint32_t>& set) { |
| web_frame_->SetReplicatedInsecureNavigationsSet(set); |
| } |
| |
| void RenderFrameProxy::OnSetFrameOwnerProperties( |
| const FrameOwnerProperties& properties) { |
| web_frame_->SetFrameOwnerProperties( |
| ConvertFrameOwnerPropertiesToWebFrameOwnerProperties(properties)); |
| } |
| |
| void RenderFrameProxy::OnDidUpdateOrigin( |
| const url::Origin& origin, |
| bool is_potentially_trustworthy_unique_origin) { |
| web_frame_->SetReplicatedOrigin(origin, |
| is_potentially_trustworthy_unique_origin); |
| } |
| |
| void RenderFrameProxy::OnSetPageFocus(bool is_focused) { |
| render_view_->SetFocus(is_focused); |
| } |
| |
| void RenderFrameProxy::OnSetFocusedFrame() { |
| // This uses focusDocumentView rather than setFocusedFrame so that blur |
| // events are properly dispatched on any currently focused elements. |
| render_view_->webview()->FocusDocumentView(web_frame_); |
| } |
| |
| void RenderFrameProxy::OnWillEnterFullscreen() { |
| web_frame_->WillEnterFullscreen(); |
| } |
| |
| void RenderFrameProxy::OnUpdateUserActivationState( |
| blink::UserActivationUpdateType update_type) { |
| web_frame_->UpdateUserActivationState(update_type); |
| } |
| |
| void RenderFrameProxy::OnTransferUserActivationFrom(int32_t source_routing_id) { |
| RenderFrameProxy* source_proxy = |
| RenderFrameProxy::FromRoutingID(source_routing_id); |
| if (!source_proxy) |
| return; |
| web_frame()->TransferUserActivationFrom(source_proxy->web_frame()); |
| } |
| |
| void RenderFrameProxy::OnScrollRectToVisible( |
| const gfx::Rect& rect_to_scroll, |
| const blink::WebScrollIntoViewParams& params) { |
| web_frame_->ScrollRectToVisible(rect_to_scroll, params); |
| } |
| |
| void RenderFrameProxy::OnBubbleLogicalScroll( |
| blink::WebScrollDirection direction, |
| ui::input_types::ScrollGranularity granularity) { |
| web_frame_->BubbleLogicalScroll(direction, granularity); |
| } |
| |
| void RenderFrameProxy::OnDidUpdateVisualProperties( |
| const cc::RenderFrameMetadata& metadata) { |
| if (!parent_local_surface_id_allocator_->UpdateFromChild( |
| metadata.local_surface_id_allocation.value_or( |
| viz::LocalSurfaceIdAllocation()))) { |
| return; |
| } |
| |
| // The viz::LocalSurfaceId has changed so we call SynchronizeVisualProperties |
| // here to embed it. |
| SynchronizeVisualProperties(); |
| } |
| |
| void RenderFrameProxy::OnEnableAutoResize(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 RenderFrameProxy::OnDisableAutoResize() { |
| pending_visual_properties_.auto_resize_enabled = false; |
| SynchronizeVisualProperties(); |
| } |
| |
| void RenderFrameProxy::SynchronizeVisualProperties() { |
| if (!frame_sink_id_.is_valid() || crashed_) |
| return; |
| |
| // Note that the following flag is true if the capture sequence number |
| // actually changed. That is, it is false if we did not have |
| // |sent_visual_properties_|, which is different from |
| // |synchronized_props_changed| below. |
| bool capture_sequence_number_changed = |
| sent_visual_properties_ && |
| sent_visual_properties_->capture_sequence_number != |
| pending_visual_properties_.capture_sequence_number; |
| |
| if (web_frame_) { |
| pending_visual_properties_.compositor_viewport = |
| web_frame_->GetCompositingRect(); |
| } |
| |
| 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_->is_pinch_gesture_active != |
| pending_visual_properties_.is_pinch_gesture_active || |
| sent_visual_properties_->compositor_viewport != |
| pending_visual_properties_.compositor_viewport || |
| capture_sequence_number_changed; |
| |
| if (synchronized_props_changed) { |
| parent_local_surface_id_allocator_->GenerateId(); |
| pending_visual_properties_.local_surface_id_allocation = |
| parent_local_surface_id_allocator_ |
| ->GetCurrentLocalSurfaceIdAllocation(); |
| } |
| |
| // If we're synchronizing surfaces, then use an infinite deadline to ensure |
| // everything is synchronized. |
| cc::DeadlinePolicy deadline = capture_sequence_number_changed |
| ? cc::DeadlinePolicy::UseInfiniteDeadline() |
| : cc::DeadlinePolicy::UseDefaultDeadline(); |
| viz::SurfaceId surface_id(frame_sink_id_, GetLocalSurfaceId()); |
| compositing_helper_->SetSurfaceId( |
| surface_id, pending_visual_properties_.compositor_viewport.size(), |
| deadline); |
| |
| 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; |
| |
| // Let the browser know about the updated view rect. |
| Send(new FrameHostMsg_SynchronizeVisualProperties( |
| routing_id_, frame_sink_id_, pending_visual_properties_)); |
| 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_allocation |
| .local_surface_id() |
| .submission_trace_id()), |
| TRACE_EVENT_FLAG_FLOW_OUT, "message", |
| "FrameHostMsg_SynchronizeVisualProperties", "local_surface_id", |
| pending_visual_properties_.local_surface_id_allocation.local_surface_id() |
| .ToString()); |
| } |
| |
| void RenderFrameProxy::OnSetHasReceivedUserGestureBeforeNavigation(bool value) { |
| web_frame_->SetHasReceivedUserGestureBeforeNavigation(value); |
| } |
| |
| void RenderFrameProxy::OnRenderFallbackContent() const { |
| web_frame_->RenderFallbackContent(); |
| } |
| |
| void RenderFrameProxy::FrameDetached(DetachType type) { |
| if (type == DetachType::kRemove) { |
| // Let the browser process know this subframe is removed, so that it is |
| // destroyed in its current process. |
| Send(new FrameHostMsg_Detach(routing_id_)); |
| } |
| |
| web_frame_->Close(); |
| |
| // If this proxy was associated with a provisional RenderFrame, and we're not |
| // in the process of swapping with it, clean it up as well. |
| if (type == DetachType::kRemove && |
| provisional_frame_routing_id_ != MSG_ROUTING_NONE) { |
| RenderFrameImpl* provisional_frame = |
| RenderFrameImpl::FromRoutingID(provisional_frame_routing_id_); |
| // |provisional_frame| should always exist. If it was deleted via |
| // FrameMsg_Delete right before this proxy was removed, |
| // RenderFrameImpl::frameDetached would've cleared this proxy's |
| // |provisional_frame_routing_id_| and we wouldn't get here. |
| CHECK(provisional_frame); |
| provisional_frame->GetWebFrame()->Detach(); |
| } |
| |
| // Remove the entry in the WebFrame->RenderFrameProxy map, as the |web_frame_| |
| // is no longer valid. |
| auto it = g_frame_proxy_map.Get().find(web_frame_); |
| CHECK(it != g_frame_proxy_map.Get().end()); |
| CHECK_EQ(it->second, this); |
| g_frame_proxy_map.Get().erase(it); |
| |
| web_frame_ = nullptr; |
| |
| delete this; |
| } |
| |
| void RenderFrameProxy::CheckCompleted() { |
| Send(new FrameHostMsg_CheckCompleted(routing_id_)); |
| } |
| |
| void RenderFrameProxy::ForwardPostMessage( |
| blink::WebLocalFrame* source_frame, |
| blink::WebRemoteFrame* target_frame, |
| blink::WebSecurityOrigin target_origin, |
| blink::WebDOMMessageEvent event) { |
| DCHECK(!web_frame_ || web_frame_ == target_frame); |
| |
| FrameMsg_PostMessage_Params params; |
| params.message = |
| new base::RefCountedData<blink::TransferableMessage>(event.AsMessage()); |
| params.source_origin = event.Origin().Utf16(); |
| if (!target_origin.IsNull()) |
| params.target_origin = target_origin.ToString().Utf16(); |
| |
| // Include the routing ID for the source frame (if one exists), which the |
| // browser process will translate into the routing ID for the equivalent |
| // frame in the target process. |
| params.source_routing_id = MSG_ROUTING_NONE; |
| if (source_frame) { |
| RenderFrameImpl* source_render_frame = |
| RenderFrameImpl::FromWebFrame(source_frame); |
| if (source_render_frame) |
| params.source_routing_id = source_render_frame->GetRoutingID(); |
| } |
| |
| Send(new FrameHostMsg_RouteMessageEvent(routing_id_, params)); |
| } |
| |
| void RenderFrameProxy::Navigate( |
| const blink::WebURLRequest& request, |
| bool should_replace_current_entry, |
| bool is_opener_navigation, |
| bool has_download_sandbox_flag, |
| bool blocking_downloads_in_sandbox_without_user_activation_enabled, |
| bool initiator_frame_is_ad, |
| mojo::ScopedMessagePipeHandle blob_url_token) { |
| // The request must always have a valid initiator origin. |
| DCHECK(!request.RequestorOrigin().IsNull()); |
| |
| FrameHostMsg_OpenURL_Params params; |
| params.url = request.Url(); |
| params.initiator_origin = request.RequestorOrigin(); |
| params.uses_post = request.HttpMethod().Utf8() == "POST"; |
| params.resource_request_body = GetRequestBodyForWebURLRequest(request); |
| params.extra_headers = GetWebURLRequestHeadersAsString(request); |
| // TODO(domfarolino): Retrieve the referrer in the form of a referrer member |
| // instead of the header field. See https://crbug.com/850813. |
| params.referrer = Referrer(blink::WebStringToGURL(request.HttpHeaderField( |
| blink::WebString::FromUTF8("Referer"))), |
| request.GetReferrerPolicy()); |
| params.disposition = WindowOpenDisposition::CURRENT_TAB; |
| params.should_replace_current_entry = should_replace_current_entry; |
| params.user_gesture = request.HasUserGesture(); |
| params.triggering_event_info = blink::TriggeringEventInfo::kUnknown; |
| params.blob_url_token = blob_url_token.release(); |
| |
| // Note: For the AdFrame download policy here it only covers the case where |
| // the navigation initiator frame is ad. The download_policy may be further |
| // augmented in RenderFrameProxyHost::OnOpenURL if the navigating frame is ad. |
| RenderFrameImpl::MaybeSetDownloadFramePolicy( |
| is_opener_navigation, request, web_frame_->GetSecurityOrigin(), |
| has_download_sandbox_flag, |
| blocking_downloads_in_sandbox_without_user_activation_enabled, |
| initiator_frame_is_ad, ¶ms.download_policy); |
| |
| Send(new FrameHostMsg_OpenURL(routing_id_, params)); |
| } |
| |
| void RenderFrameProxy::FrameRectsChanged( |
| const blink::WebRect& local_frame_rect, |
| const blink::WebRect& 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); |
| if (render_widget_) { |
| pending_visual_properties_.screen_info = |
| render_widget_->GetOriginalScreenInfo(); |
| } |
| if (crashed_) { |
| // Update the sad page to match the current size. |
| compositing_helper_->ChildFrameGone(local_frame_size(), |
| screen_info().device_scale_factor); |
| return; |
| } |
| SynchronizeVisualProperties(); |
| } |
| |
| void RenderFrameProxy::UpdateRemoteViewportIntersection( |
| const blink::WebRect& viewport_intersection, |
| blink::FrameOcclusionState occlusion_state) { |
| // If the remote viewport intersection has changed, then we should check if |
| // the compositing rect has also changed: if it has, then we should update the |
| // visible properties. |
| // TODO(wjmaclean): Maybe we should always call SynchronizeVisualProperties() |
| // here? If nothing has changed, it will early out, and it avoids duplicate |
| // checks here. |
| gfx::Rect compositor_visible_rect = web_frame_->GetCompositingRect(); |
| bool compositor_visible_rect_changed = |
| compositor_visible_rect != pending_visual_properties_.compositor_viewport; |
| |
| if (compositor_visible_rect_changed) |
| SynchronizeVisualProperties(); |
| |
| Send(new FrameHostMsg_UpdateViewportIntersection( |
| routing_id_, gfx::Rect(viewport_intersection), compositor_visible_rect, |
| occlusion_state)); |
| } |
| |
| void RenderFrameProxy::VisibilityChanged( |
| blink::mojom::FrameVisibility visibility) { |
| Send(new FrameHostMsg_VisibilityChanged(routing_id_, visibility)); |
| } |
| |
| void RenderFrameProxy::SetIsInert(bool inert) { |
| Send(new FrameHostMsg_SetIsInert(routing_id_, inert)); |
| } |
| |
| void RenderFrameProxy::SetInheritedEffectiveTouchAction( |
| cc::TouchAction touch_action) { |
| Send(new FrameHostMsg_SetInheritedEffectiveTouchAction(routing_id_, |
| touch_action)); |
| } |
| |
| void RenderFrameProxy::UpdateRenderThrottlingStatus(bool is_throttled, |
| bool subtree_throttled) { |
| Send(new FrameHostMsg_UpdateRenderThrottlingStatus(routing_id_, is_throttled, |
| subtree_throttled)); |
| } |
| |
| void RenderFrameProxy::DidChangeOpener(blink::WebFrame* opener) { |
| // 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) |
| return; |
| |
| // Only a LocalFrame (i.e., the caller of window.open) should be able to |
| // update another frame's opener. |
| DCHECK(opener->IsWebLocalFrame()); |
| |
| int opener_routing_id = |
| RenderFrameImpl::FromWebFrame(opener->ToWebLocalFrame())->GetRoutingID(); |
| Send(new FrameHostMsg_DidChangeOpener(routing_id_, opener_routing_id)); |
| } |
| |
| void RenderFrameProxy::AdvanceFocus(blink::WebFocusType type, |
| blink::WebLocalFrame* source) { |
| int source_routing_id = RenderFrameImpl::FromWebFrame(source)->GetRoutingID(); |
| Send(new FrameHostMsg_AdvanceFocus(routing_id_, type, source_routing_id)); |
| } |
| |
| void RenderFrameProxy::FrameFocused() { |
| GetFrameProxyHost()->FrameFocused(); |
| } |
| |
| base::UnguessableToken RenderFrameProxy::GetDevToolsFrameToken() { |
| return devtools_frame_token_; |
| } |
| |
| cc::Layer* RenderFrameProxy::GetLayer() { |
| return embedded_layer_.get(); |
| } |
| |
| void RenderFrameProxy::SetLayer(scoped_refptr<cc::Layer> layer, |
| bool prevent_contents_opaque_changes, |
| bool is_surface_layer) { |
| if (web_frame()) { |
| web_frame()->SetCcLayer(layer.get(), prevent_contents_opaque_changes, |
| is_surface_layer); |
| } |
| embedded_layer_ = std::move(layer); |
| } |
| |
| SkBitmap* RenderFrameProxy::GetSadPageBitmap() { |
| return GetContentClient()->renderer()->GetSadWebViewBitmap(); |
| } |
| |
| uint32_t RenderFrameProxy::Print(const blink::WebRect& rect, |
| cc::PaintCanvas* canvas) { |
| #if BUILDFLAG(ENABLE_PRINTING) |
| auto* metafile = canvas->GetPrintingMetafile(); |
| DCHECK(metafile); |
| |
| // Create a place holder content for the remote frame so it can be replaced |
| // with actual content later. |
| uint32_t content_id = |
| metafile->CreateContentForRemoteFrame(rect, routing_id_); |
| |
| // Inform browser to print the remote subframe. |
| Send(new FrameHostMsg_PrintCrossProcessSubframe( |
| routing_id_, rect, metafile->GetDocumentCookie())); |
| return content_id; |
| #else |
| return 0; |
| #endif |
| } |
| |
| const viz::LocalSurfaceId& RenderFrameProxy::GetLocalSurfaceId() const { |
| return parent_local_surface_id_allocator_ |
| ->GetCurrentLocalSurfaceIdAllocation() |
| .local_surface_id(); |
| } |
| |
| mojom::RenderFrameProxyHost* RenderFrameProxy::GetFrameProxyHost() { |
| if (!frame_proxy_host_remote_.is_bound()) |
| GetRemoteAssociatedInterfaces()->GetInterface(&frame_proxy_host_remote_); |
| return frame_proxy_host_remote_.get(); |
| } |
| |
| blink::AssociatedInterfaceProvider* |
| RenderFrameProxy::GetRemoteAssociatedInterfaces() { |
| if (!remote_associated_interfaces_) { |
| ChildThreadImpl* thread = ChildThreadImpl::current(); |
| mojo::PendingAssociatedRemote<blink::mojom::AssociatedInterfaceProvider> |
| remote_interfaces; |
| thread->GetRemoteRouteProvider()->GetRoute( |
| routing_id_, remote_interfaces.InitWithNewEndpointAndPassReceiver()); |
| remote_associated_interfaces_ = |
| std::make_unique<blink::AssociatedInterfaceProvider>( |
| std::move(remote_interfaces)); |
| } |
| return remote_associated_interfaces_.get(); |
| } |
| |
| void RenderFrameProxy::WasEvicted() { |
| // On eviction, the last SurfaceId is invalidated. We need to allocate a new |
| // id. |
| ResendVisualProperties(); |
| } |
| |
| } // namespace content |