blob: ff4037429687649cf9159fd88272b572cfe95c95 [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/exported/web_remote_frame_impl.h"
#include "third_party/blink/public/common/feature_policy/feature_policy.h"
#include "third_party/blink/public/platform/web_float_rect.h"
#include "third_party/blink/public/platform/web_intrinsic_sizing_info.h"
#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_frame_owner_properties.h"
#include "third_party/blink/public/web/web_performance.h"
#include "third_party/blink/public/web/web_range.h"
#include "third_party/blink/public/web/web_tree_scope_type.h"
#include "third_party/blink/renderer/bindings/core/v8/window_proxy.h"
#include "third_party/blink/renderer/core/execution_context/remote_security_context.h"
#include "third_party/blink/renderer/core/execution_context/security_context.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_frame_view.h"
#include "third_party/blink/renderer/core/frame/remote_frame_client_impl.h"
#include "third_party/blink/renderer/core/frame/remote_frame_owner.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen_options.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
#include "third_party/blink/renderer/core/timing/window_performance.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
#include "third_party/blink/renderer/platform/feature_policy/feature_policy.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "v8/include/v8.h"
namespace blink {
namespace {
FloatRect DeNormalizeRect(const WebFloatRect& normalized, const IntRect& base) {
FloatRect result = normalized;
result.Scale(base.Width(), base.Height());
result.MoveBy(base.Location());
return result;
}
} // namespace
WebRemoteFrame* WebRemoteFrame::Create(WebTreeScopeType scope,
WebRemoteFrameClient* client) {
return WebRemoteFrameImpl::Create(scope, client);
}
WebRemoteFrame* WebRemoteFrame::CreateMainFrame(WebView* web_view,
WebRemoteFrameClient* client,
WebFrame* opener) {
return WebRemoteFrameImpl::CreateMainFrame(web_view, client, opener);
}
WebRemoteFrameImpl* WebRemoteFrameImpl::Create(WebTreeScopeType scope,
WebRemoteFrameClient* client) {
WebRemoteFrameImpl* frame = new WebRemoteFrameImpl(scope, client);
return frame;
}
WebRemoteFrameImpl* WebRemoteFrameImpl::CreateMainFrame(
WebView* web_view,
WebRemoteFrameClient* client,
WebFrame* opener) {
WebRemoteFrameImpl* frame =
new WebRemoteFrameImpl(WebTreeScopeType::kDocument, client);
frame->SetOpener(opener);
Page& page = *static_cast<WebViewImpl*>(web_view)->GetPage();
// It would be nice to DCHECK that the main frame is not set yet here.
// Unfortunately, there is an edge case with a pending RenderFrameHost that
// violates this: the embedder may create a pending RenderFrameHost for
// navigating to a new page in a popup. If the navigation ends up redirecting
// to a site that requires a process swap, it doesn't go through the standard
// swapping path and instead directly overwrites the main frame.
// TODO(dcheng): Remove the need for this and strongly enforce this condition
// with a DCHECK.
frame->InitializeCoreFrame(page, nullptr, g_null_atom);
return frame;
}
WebRemoteFrameImpl::~WebRemoteFrameImpl() = default;
void WebRemoteFrameImpl::Trace(blink::Visitor* visitor) {
visitor->Trace(frame_client_);
visitor->Trace(frame_);
WebFrame::TraceFrames(visitor, this);
}
bool WebRemoteFrameImpl::IsWebLocalFrame() const {
return false;
}
WebLocalFrame* WebRemoteFrameImpl::ToWebLocalFrame() {
NOTREACHED();
return nullptr;
}
bool WebRemoteFrameImpl::IsWebRemoteFrame() const {
return true;
}
WebRemoteFrame* WebRemoteFrameImpl::ToWebRemoteFrame() {
return this;
}
void WebRemoteFrameImpl::Close() {
WebRemoteFrame::Close();
self_keep_alive_.Clear();
}
WebRect WebRemoteFrameImpl::VisibleContentRect() const {
NOTREACHED();
return WebRect();
}
WebView* WebRemoteFrameImpl::View() const {
if (!GetFrame()) {
return nullptr;
}
DCHECK(GetFrame()->GetPage());
return GetFrame()->GetPage()->GetChromeClient().GetWebView();
}
void WebRemoteFrameImpl::StopLoading() {
// TODO(dcheng,japhet): Calling this method should stop loads
// in all subframes, both remote and local.
}
WebLocalFrame* WebRemoteFrameImpl::CreateLocalChild(
WebTreeScopeType scope,
const WebString& name,
WebSandboxFlags sandbox_flags,
WebLocalFrameClient* client,
blink::InterfaceRegistry* interface_registry,
WebFrame* previous_sibling,
const ParsedFeaturePolicy& container_policy,
const WebFrameOwnerProperties& frame_owner_properties,
WebFrame* opener) {
WebLocalFrameImpl* child =
WebLocalFrameImpl::Create(scope, client, interface_registry, opener);
InsertAfter(child, previous_sibling);
RemoteFrameOwner* owner =
RemoteFrameOwner::Create(static_cast<SandboxFlags>(sandbox_flags),
container_policy, frame_owner_properties);
child->InitializeCoreFrame(*GetFrame()->GetPage(), owner, name);
DCHECK(child->GetFrame());
return child;
}
void WebRemoteFrameImpl::InitializeCoreFrame(Page& page,
FrameOwner* owner,
const AtomicString& name) {
SetCoreFrame(RemoteFrame::Create(frame_client_.Get(), page, owner));
GetFrame()->CreateView();
frame_->Tree().SetName(name);
}
WebRemoteFrame* WebRemoteFrameImpl::CreateRemoteChild(
WebTreeScopeType scope,
const WebString& name,
WebSandboxFlags sandbox_flags,
const ParsedFeaturePolicy& container_policy,
WebRemoteFrameClient* client,
WebFrame* opener) {
WebRemoteFrameImpl* child = WebRemoteFrameImpl::Create(scope, client);
child->SetOpener(opener);
AppendChild(child);
RemoteFrameOwner* owner =
RemoteFrameOwner::Create(static_cast<SandboxFlags>(sandbox_flags),
container_policy, WebFrameOwnerProperties());
child->InitializeCoreFrame(*GetFrame()->GetPage(), owner, name);
return child;
}
void WebRemoteFrameImpl::SetCcLayer(cc::Layer* layer,
bool prevent_contents_opaque_changes) {
if (!GetFrame())
return;
GetFrame()->SetCcLayer(layer, prevent_contents_opaque_changes);
}
void WebRemoteFrameImpl::SetCoreFrame(RemoteFrame* frame) {
frame_ = frame;
}
WebRemoteFrameImpl* WebRemoteFrameImpl::FromFrame(RemoteFrame& frame) {
if (!frame.Client())
return nullptr;
RemoteFrameClientImpl* client =
static_cast<RemoteFrameClientImpl*>(frame.Client());
return client->GetWebFrame();
}
void WebRemoteFrameImpl::SetReplicatedOrigin(
const WebSecurityOrigin& origin,
bool is_potentially_trustworthy_opaque_origin) {
DCHECK(GetFrame());
scoped_refptr<SecurityOrigin> security_origin = origin.Get()->IsolatedCopy();
security_origin->SetOpaqueOriginIsPotentiallyTrustworthy(
is_potentially_trustworthy_opaque_origin);
GetFrame()->GetSecurityContext()->SetReplicatedOrigin(security_origin);
// 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 = GetFrame()->Owner();
if (owner && owner->IsLocal()) {
HTMLElement* owner_element = ToHTMLFrameOwnerElement(owner);
AXObjectCache* cache = owner_element->GetDocument().ExistingAXObjectCache();
if (cache)
cache->ChildrenChanged(owner_element);
}
}
void WebRemoteFrameImpl::SetReplicatedSandboxFlags(WebSandboxFlags flags) {
DCHECK(GetFrame());
GetFrame()->GetSecurityContext()->ResetSandboxFlags();
GetFrame()->GetSecurityContext()->EnforceSandboxFlags(
static_cast<SandboxFlags>(flags));
}
void WebRemoteFrameImpl::SetReplicatedName(const WebString& name) {
DCHECK(GetFrame());
GetFrame()->Tree().SetName(name);
}
void WebRemoteFrameImpl::SetReplicatedFeaturePolicyHeader(
const ParsedFeaturePolicy& parsed_header) {
FeaturePolicy* parent_feature_policy = nullptr;
if (Parent()) {
Frame* parent_frame = GetFrame()->Client()->Parent();
parent_feature_policy =
parent_frame->GetSecurityContext()->GetFeaturePolicy();
}
ParsedFeaturePolicy container_policy;
if (GetFrame()->Owner())
container_policy = GetFrame()->Owner()->ContainerPolicy();
GetFrame()->GetSecurityContext()->InitializeFeaturePolicy(
parsed_header, container_policy, parent_feature_policy);
}
void WebRemoteFrameImpl::AddReplicatedContentSecurityPolicyHeader(
const WebString& header_value,
WebContentSecurityPolicyType type,
WebContentSecurityPolicySource source) {
GetFrame()
->GetSecurityContext()
->GetContentSecurityPolicy()
->AddPolicyFromHeaderValue(
header_value, static_cast<ContentSecurityPolicyHeaderType>(type),
static_cast<ContentSecurityPolicyHeaderSource>(source));
}
void WebRemoteFrameImpl::ResetReplicatedContentSecurityPolicy() {
GetFrame()->GetSecurityContext()->ResetReplicatedContentSecurityPolicy();
}
void WebRemoteFrameImpl::SetReplicatedInsecureRequestPolicy(
WebInsecureRequestPolicy policy) {
DCHECK(GetFrame());
GetFrame()->GetSecurityContext()->SetInsecureRequestPolicy(policy);
}
void WebRemoteFrameImpl::SetReplicatedInsecureNavigationsSet(
const std::vector<unsigned>& set) {
DCHECK(GetFrame());
GetFrame()->GetSecurityContext()->SetInsecureNavigationsSet(set);
}
void WebRemoteFrameImpl::ForwardResourceTimingToParent(
const WebResourceTimingInfo& info) {
DCHECK(Parent()->IsWebLocalFrame());
WebLocalFrameImpl* parent_frame =
ToWebLocalFrameImpl(Parent()->ToWebLocalFrame());
HTMLFrameOwnerElement* owner_element =
ToHTMLFrameOwnerElement(frame_->Owner());
DOMWindowPerformance::performance(*parent_frame->GetFrame()->DomWindow())
->AddResourceTiming(info, owner_element->localName());
}
void WebRemoteFrameImpl::DispatchLoadEventForFrameOwner() {
DCHECK(GetFrame()->Owner()->IsLocal());
GetFrame()->Owner()->DispatchLoad();
}
void WebRemoteFrameImpl::DidStartLoading() {
GetFrame()->SetIsLoading(true);
}
void WebRemoteFrameImpl::DidStopLoading() {
GetFrame()->SetIsLoading(false);
}
bool WebRemoteFrameImpl::IsIgnoredForHitTest() const {
HTMLFrameOwnerElement* owner = GetFrame()->DeprecatedLocalOwner();
if (!owner || !owner->GetLayoutObject())
return false;
return owner->GetLayoutObject()->Style()->PointerEvents() ==
EPointerEvents::kNone;
}
void WebRemoteFrameImpl::WillEnterFullscreen() {
// This should only ever be called when the FrameOwner is local.
HTMLFrameOwnerElement* owner_element =
ToHTMLFrameOwnerElement(GetFrame()->Owner());
// Call |requestFullscreen()| on |ownerElement| to make it the pending
// fullscreen element in anticipation of the coming |didEnterFullscreen()|
// call.
//
// PrefixedForCrossProcessDescendant 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 :-webkit-full-screen.
//
// TODO(alexmos): currently, this assumes prefixed requests, but in the
// future, this should plumb in information about which request type
// (prefixed or unprefixed) to use for firing fullscreen events.
Fullscreen::RequestFullscreen(
*owner_element, FullscreenOptions(),
Fullscreen::RequestType::kPrefixedForCrossProcessDescendant);
}
void WebRemoteFrameImpl::UpdateUserActivationState(
UserActivationUpdateType update_type) {
switch (update_type) {
case UserActivationUpdateType::kNotifyActivation:
GetFrame()->NotifyUserActivationInLocalTree();
break;
case UserActivationUpdateType::kConsumeTransientActivation:
GetFrame()->ConsumeTransientUserActivationInLocalTree();
break;
}
}
void WebRemoteFrameImpl::ScrollRectToVisible(
const WebRect& rect_to_scroll,
const WebScrollIntoViewParams& params) {
Element* owner_element = frame_->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.
LayoutRect absolute_rect = EnclosingLayoutRect(
owner_object
->LocalToAncestorQuad(FloatRect(rect_to_scroll), owner_object->View(),
kUseTransforms)
.BoundingBox());
if (!params.zoom_into_rect ||
!owner_object->GetDocument().GetFrame()->LocalFrameRoot().IsMainFrame()) {
owner_object->ScrollRectToVisible(absolute_rect, 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).
WebScrollIntoViewParams new_params(params);
new_params.stop_at_main_frame_layout_viewport = true;
absolute_rect = owner_object->ScrollRectToVisible(absolute_rect, new_params);
// 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* view_impl = static_cast<WebViewImpl*>(View());
IntRect rect_in_document =
view_impl->MainFrameImpl()->GetFrame()->View()->RootFrameToDocument(
EnclosingIntRect(
owner_element->GetDocument().View()->ConvertToRootFrame(
absolute_rect)));
IntRect element_bounds_in_document = EnclosingIntRect(
DeNormalizeRect(params.relative_element_bounds, rect_in_document));
IntRect caret_bounds_in_document = EnclosingIntRect(
DeNormalizeRect(params.relative_caret_bounds, rect_in_document));
view_impl->ZoomAndScrollToFocusedEditableElementRect(
element_bounds_in_document, caret_bounds_in_document, true);
}
void WebRemoteFrameImpl::IntrinsicSizingInfoChanged(
const WebIntrinsicSizingInfo& web_sizing_info) {
FrameOwner* owner = GetFrame()->Owner();
// Only communication from HTMLPluginElement-owned subframes is allowed
// at present. This includes <embed> and <object> tags.
if (!owner || !owner->IsPlugin())
return;
IntrinsicSizingInfo sizing_info;
sizing_info.size = web_sizing_info.size;
sizing_info.aspect_ratio = web_sizing_info.aspect_ratio;
sizing_info.has_width = web_sizing_info.has_width;
sizing_info.has_height = web_sizing_info.has_height;
frame_->View()->SetIntrinsicSizeInfo(sizing_info);
owner->IntrinsicSizingInfoChanged();
}
void WebRemoteFrameImpl::SetHasReceivedUserGestureBeforeNavigation(bool value) {
GetFrame()->SetDocumentHasReceivedUserGestureBeforeNavigation(value);
}
v8::Local<v8::Object> WebRemoteFrameImpl::GlobalProxy() const {
return GetFrame()
->GetWindowProxy(DOMWrapperWorld::MainWorld())
->GlobalProxyIfNotDetached();
}
WebRect WebRemoteFrameImpl::GetCompositingRect() {
return GetFrame()->View()->GetCompositingRect();
}
WebRemoteFrameImpl::WebRemoteFrameImpl(WebTreeScopeType scope,
WebRemoteFrameClient* client)
: WebRemoteFrame(scope),
client_(client),
frame_client_(RemoteFrameClientImpl::Create(this)),
self_keep_alive_(this) {
DCHECK(client);
}
} // namespace blink