blob: 0c1aa9a2d536e762b2c3a9ee6bca6fd5f8df0a97 [file] [log] [blame]
// 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