[go: nahoru, domu]

blob: fe7f19e5719081a58c3df4dad543806682e67bed [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// 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/local_frame_mojo_handler.h"
#include "base/metrics/histogram_functions.h"
#include "base/numerics/safe_conversions.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/common/chrome_debug_urls.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/frame/frame_owner_element_type.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/media_player_action.mojom-blink.h"
#include "third_party/blink/public/mojom/opengraph/metadata.mojom-blink.h"
#include "third_party/blink/public/mojom/timing/resource_timing.mojom-blink-forward.h"
#include "third_party/blink/public/platform/interface_registry.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_local_frame_client.h"
#include "third_party/blink/public/web/web_plugin.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h"
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/ignore_opens_during_unload_count_incrementer.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/surrounding_text.h"
#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/frame_console.h"
#include "third_party/blink/renderer/core/frame/intervention.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/pausable_script_executor.h"
#include "third_party/blink/renderer/core/frame/remote_frame_owner.h"
#include "third_party/blink/renderer/core/frame/reporting_context.h"
#include "third_party/blink/renderer/core/frame/savable_resources.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/scoped_allow_fullscreen.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html/html_link_element.h"
#include "third_party/blink/renderer/core/html/html_meta_element.h"
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/html/portal/dom_window_portal_host.h"
#include "third_party/blink/renderer/core/html/portal/portal_activate_event.h"
#include "third_party/blink/renderer/core/html/portal/portal_host.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
#include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
#include "third_party/blink/renderer/core/messaging/message_port.h"
#include "third_party/blink/renderer/core/navigation_api/navigation_api.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/timing/paint_timing.h"
#include "third_party/blink/renderer/core/script/classic_script.h"
#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
#include "third_party/blink/renderer/core/view_transition/view_transition_supplement.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_utils.h"
#include "third_party/blink/renderer/platform/widget/frame_widget.h"
#if BUILDFLAG(IS_MAC)
#include "base/apple/foundation_util.h"
#include "third_party/blink/renderer/core/editing/substring_util.h"
#include "third_party/blink/renderer/platform/fonts/mac/attributed_string_type_converter.h"
#include "ui/base/mojom/attributed_string.mojom-blink.h"
#endif
namespace blink {
namespace {
constexpr char kInvalidWorldID[] =
"JavaScriptExecuteRequestInIsolatedWorld gets an invalid world id.";
#if BUILDFLAG(IS_MAC)
size_t GetCurrentCursorPositionInFrame(LocalFrame* local_frame) {
blink::WebRange range =
WebLocalFrameImpl::FromFrame(local_frame)->SelectionRange();
return range.IsNull() ? size_t{0} : static_cast<size_t>(range.StartOffset());
}
#endif
RemoteFrame* SourceFrameForOptionalToken(
const absl::optional<RemoteFrameToken>& source_frame_token) {
if (!source_frame_token)
return nullptr;
return RemoteFrame::FromFrameToken(source_frame_token.value());
}
v8::Local<v8::Context> MainWorldScriptContext(LocalFrame* local_frame) {
ScriptState* script_state = ToScriptStateForMainWorld(local_frame);
DCHECK(script_state);
return script_state->GetContext();
}
base::Value GetJavaScriptExecutionResult(v8::Local<v8::Value> result,
v8::Local<v8::Context> context,
WebV8ValueConverter* converter) {
if (!result.IsEmpty()) {
v8::Context::Scope context_scope(context);
std::unique_ptr<base::Value> new_value =
converter->FromV8Value(result, context);
if (new_value)
return std::move(*new_value);
}
return base::Value();
}
v8::MaybeLocal<v8::Value> GetProperty(v8::Local<v8::Context> context,
v8::Local<v8::Value> object,
const String& name) {
v8::Isolate* isolate = context->GetIsolate();
v8::Local<v8::String> name_str = V8String(isolate, name);
v8::Local<v8::Object> object_obj;
if (!object->ToObject(context).ToLocal(&object_obj)) {
return v8::MaybeLocal<v8::Value>();
}
return object_obj->Get(context, name_str);
}
v8::MaybeLocal<v8::Value> CallMethodOnFrame(LocalFrame* local_frame,
const String& object_name,
const String& method_name,
base::Value::List arguments,
WebV8ValueConverter* converter) {
v8::Local<v8::Context> context = MainWorldScriptContext(local_frame);
v8::Context::Scope context_scope(context);
WTF::Vector<v8::Local<v8::Value>> args;
for (const auto& argument : arguments) {
args.push_back(converter->ToV8Value(argument, context));
}
v8::Local<v8::Value> object;
v8::Local<v8::Value> method;
if (!GetProperty(context, context->Global(), object_name).ToLocal(&object) ||
!GetProperty(context, object, method_name).ToLocal(&method) ||
!method->IsFunction()) {
return v8::MaybeLocal<v8::Value>();
}
CHECK(method->IsFunction());
return local_frame->DomWindow()
->GetScriptController()
.EvaluateMethodInMainWorld(v8::Local<v8::Function>::Cast(method), object,
static_cast<int>(args.size()), args.data());
}
HitTestResult HitTestResultForRootFramePos(
LocalFrame* frame,
const PhysicalOffset& pos_in_root_frame) {
HitTestLocation location(
frame->View()->ConvertFromRootFrame(pos_in_root_frame));
HitTestResult result = frame->GetEventHandler().HitTestResultAtLocation(
location, HitTestRequest::kReadOnly | HitTestRequest::kActive);
result.SetToShadowHostIfInUAShadowRoot();
return result;
}
void ParseOpenGraphProperty(const HTMLMetaElement& element,
const Document& document,
mojom::blink::OpenGraphMetadata* metadata) {
if (element.Property() == "og:image" && !metadata->image)
metadata->image = document.CompleteURL(element.Content());
// Non-OpenGraph, non-standard thing that some sites use the same way:
// using <meta itemprop="image" content="$url">, which means the same thing
// as <meta property="og:image" content="$url".
if (element.Itemprop() == "image" && !metadata->image)
metadata->image = document.CompleteURL(element.Content());
}
// Convert the error to a string so it can be sent back to the test.
//
// We try to use .stack property so that the error message contains a stack
// trace, but otherwise fallback to .toString().
v8::Local<v8::String> ErrorToString(ScriptState* script_state,
v8::Local<v8::Value> error) {
if (!error.IsEmpty()) {
v8::Local<v8::Context> context = script_state->GetContext();
v8::Local<v8::Value> value =
v8::TryCatch::StackTrace(context, error).FromMaybe(error);
v8::Local<v8::String> value_string;
if (value->ToString(context).ToLocal(&value_string))
return value_string;
}
v8::Isolate* isolate = script_state->GetIsolate();
return v8::String::NewFromUtf8Literal(isolate, "Unknown Failure");
}
class JavaScriptExecuteRequestForTestsHandler
: public GarbageCollected<JavaScriptExecuteRequestForTestsHandler> {
public:
class PromiseCallback : public ScriptFunction::Callable {
public:
PromiseCallback(JavaScriptExecuteRequestForTestsHandler& handler,
mojom::blink::JavaScriptExecutionResultType type)
: handler_(handler), type_(type) {}
ScriptValue Call(ScriptState* script_state, ScriptValue value) override {
DCHECK(script_state);
if (type_ == mojom::blink::JavaScriptExecutionResultType::kSuccess)
handler_->SendSuccess(script_state, value.V8Value());
else
handler_->SendException(script_state, value.V8Value());
return {};
}
void Trace(Visitor* visitor) const override {
visitor->Trace(handler_);
ScriptFunction::Callable::Trace(visitor);
}
private:
Member<JavaScriptExecuteRequestForTestsHandler> handler_;
const mojom::blink::JavaScriptExecutionResultType type_;
};
explicit JavaScriptExecuteRequestForTestsHandler(
LocalFrameMojoHandler::JavaScriptExecuteRequestForTestsCallback callback)
: callback_(std::move(callback)) {}
~JavaScriptExecuteRequestForTestsHandler() {
if (callback_) {
std::move(callback_).Run(
mojom::blink::JavaScriptExecutionResultType::kException,
base::Value(
"JavaScriptExecuteRequestForTestsHandler was destroyed without "
"running the callback. This is usually caused by Promise "
"resolution functions getting destroyed without being called."));
}
}
ScriptFunction* CreateResolveCallback(ScriptState* script_state,
LocalFrame* frame) {
return MakeGarbageCollected<ScriptFunction>(
script_state,
MakeGarbageCollected<PromiseCallback>(
*this, mojom::blink::JavaScriptExecutionResultType::kSuccess));
}
ScriptFunction* CreateRejectCallback(ScriptState* script_state,
LocalFrame* frame) {
return MakeGarbageCollected<ScriptFunction>(
script_state,
MakeGarbageCollected<PromiseCallback>(
*this, mojom::blink::JavaScriptExecutionResultType::kException));
}
void SendSuccess(ScriptState* script_state, v8::Local<v8::Value> value) {
SendResponse(script_state,
mojom::blink::JavaScriptExecutionResultType::kSuccess, value);
}
void SendException(ScriptState* script_state, v8::Local<v8::Value> error) {
SendResponse(script_state,
mojom::blink::JavaScriptExecutionResultType::kException,
ErrorToString(script_state, error));
}
void Trace(Visitor* visitor) const {}
private:
void SendResponse(ScriptState* script_state,
mojom::blink::JavaScriptExecutionResultType type,
v8::Local<v8::Value> value) {
std::unique_ptr<WebV8ValueConverter> converter =
Platform::Current()->CreateWebV8ValueConverter();
converter->SetDateAllowed(true);
converter->SetRegExpAllowed(true);
CHECK(callback_) << "Promise resolved twice";
std::move(callback_).Run(
type, GetJavaScriptExecutionResult(value, script_state->GetContext(),
converter.get()));
}
LocalFrameMojoHandler::JavaScriptExecuteRequestForTestsCallback callback_;
};
} // namespace
ActiveURLMessageFilter::~ActiveURLMessageFilter() {
if (debug_url_set_) {
Platform::Current()->SetActiveURL(WebURL(), WebString());
}
}
bool ActiveURLMessageFilter::WillDispatch(mojo::Message* message) {
// We expect local_frame_ always to be set because this MessageFilter
// is owned by the LocalFrame. We do not want to introduce a Persistent
// reference so we don't cause a cycle. If you hit this CHECK then you
// likely didn't reset your mojo receiver in Detach.
CHECK(local_frame_);
debug_url_set_ = true;
Platform::Current()->SetActiveURL(local_frame_->GetDocument()->Url(),
local_frame_->Top()
->GetSecurityContext()
->GetSecurityOrigin()
->ToString());
return true;
}
void ActiveURLMessageFilter::DidDispatchOrReject(mojo::Message* message,
bool accepted) {
Platform::Current()->SetActiveURL(WebURL(), WebString());
debug_url_set_ = false;
}
LocalFrameMojoHandler::LocalFrameMojoHandler(blink::LocalFrame& frame)
: frame_(frame) {
frame.GetRemoteNavigationAssociatedInterfaces()->GetInterface(
back_forward_cache_controller_host_remote_.BindNewEndpointAndPassReceiver(
frame.GetTaskRunner(TaskType::kInternalDefault)));
#if BUILDFLAG(IS_MAC)
// It should be bound before accessing TextInputHost which is the interface to
// respond to GetCharacterIndexAtPoint.
frame.GetBrowserInterfaceBroker().GetInterface(
text_input_host_.BindNewPipeAndPassReceiver(
frame.GetTaskRunner(TaskType::kInternalDefault)));
#endif
frame.GetBrowserInterfaceBroker().GetInterface(
non_associated_local_frame_host_remote_.BindNewPipeAndPassReceiver(
frame.GetTaskRunner(TaskType::kInternalHighPriorityLocalFrame)));
frame.GetRemoteNavigationAssociatedInterfaces()->GetInterface(
local_frame_host_remote_.BindNewEndpointAndPassReceiver(
frame.GetTaskRunner(TaskType::kInternalDefault)));
auto* registry = frame.GetInterfaceRegistry();
registry->AddAssociatedInterface(
WTF::BindRepeating(&LocalFrameMojoHandler::BindToLocalFrameReceiver,
WrapWeakPersistent(this)));
registry->AddInterface(
WTF::BindRepeating(&LocalFrameMojoHandler::BindToHighPriorityReceiver,
WrapWeakPersistent(this)),
frame.GetTaskRunner(TaskType::kInternalHighPriorityLocalFrame));
registry->AddAssociatedInterface(WTF::BindRepeating(
&LocalFrameMojoHandler::BindFullscreenVideoElementReceiver,
WrapWeakPersistent(this)));
}
void LocalFrameMojoHandler::Trace(Visitor* visitor) const {
visitor->Trace(frame_);
visitor->Trace(back_forward_cache_controller_host_remote_);
#if BUILDFLAG(IS_MAC)
visitor->Trace(text_input_host_);
#endif
visitor->Trace(reporting_service_);
visitor->Trace(device_posture_provider_service_);
visitor->Trace(local_frame_host_remote_);
visitor->Trace(non_associated_local_frame_host_remote_);
visitor->Trace(local_frame_receiver_);
visitor->Trace(main_frame_receiver_);
visitor->Trace(high_priority_frame_receiver_);
visitor->Trace(fullscreen_video_receiver_);
visitor->Trace(device_posture_receiver_);
}
void LocalFrameMojoHandler::WasAttachedAsLocalMainFrame() {
frame_->GetInterfaceRegistry()->AddAssociatedInterface(
WTF::BindRepeating(&LocalFrameMojoHandler::BindToMainFrameReceiver,
WrapWeakPersistent(this)));
}
void LocalFrameMojoHandler::DidDetachFrame() {
// We reset receivers explicitly because HeapMojoReceiver does not
// automatically reset on context destruction.
local_frame_receiver_.reset();
main_frame_receiver_.reset();
high_priority_frame_receiver_.reset();
// TODO(tkent): Should we reset other receivers?
}
void LocalFrameMojoHandler::ClosePageForTesting() {
ClosePage(base::DoNothing());
}
mojom::blink::BackForwardCacheControllerHost&
LocalFrameMojoHandler::BackForwardCacheControllerHostRemote() {
return *back_forward_cache_controller_host_remote_.get();
}
#if BUILDFLAG(IS_MAC)
mojom::blink::TextInputHost& LocalFrameMojoHandler::TextInputHost() {
DCHECK(text_input_host_.is_bound());
return *text_input_host_.get();
}
void LocalFrameMojoHandler::ResetTextInputHostForTesting() {
text_input_host_.reset();
}
void LocalFrameMojoHandler::RebindTextInputHostForTesting() {
frame_->GetBrowserInterfaceBroker().GetInterface(
text_input_host_.BindNewPipeAndPassReceiver(
frame_->GetTaskRunner(TaskType::kInternalDefault)));
}
#endif
mojom::blink::ReportingServiceProxy* LocalFrameMojoHandler::ReportingService() {
if (!reporting_service_.is_bound()) {
frame_->GetBrowserInterfaceBroker().GetInterface(
reporting_service_.BindNewPipeAndPassReceiver(
frame_->GetTaskRunner(TaskType::kInternalDefault)));
}
return reporting_service_.get();
}
device::mojom::blink::DevicePostureType
LocalFrameMojoHandler::GetDevicePosture() {
if (device_posture_provider_service_.is_bound())
return current_device_posture_;
auto task_runner = frame_->GetTaskRunner(TaskType::kInternalDefault);
frame_->GetBrowserInterfaceBroker().GetInterface(
device_posture_provider_service_.BindNewPipeAndPassReceiver(task_runner));
device_posture_provider_service_->AddListenerAndGetCurrentPosture(
device_posture_receiver_.BindNewPipeAndPassRemote(task_runner),
WTF::BindOnce(&LocalFrameMojoHandler::OnPostureChanged,
WrapPersistent(this)));
return current_device_posture_;
}
Page* LocalFrameMojoHandler::GetPage() const {
return frame_->GetPage();
}
LocalDOMWindow* LocalFrameMojoHandler::DomWindow() const {
return frame_->DomWindow();
}
Document* LocalFrameMojoHandler::GetDocument() const {
return frame_->GetDocument();
}
void LocalFrameMojoHandler::BindToLocalFrameReceiver(
mojo::PendingAssociatedReceiver<mojom::blink::LocalFrame> receiver) {
if (frame_->IsDetached())
return;
local_frame_receiver_.Bind(std::move(receiver),
frame_->GetTaskRunner(TaskType::kInternalDefault));
local_frame_receiver_.SetFilter(
std::make_unique<ActiveURLMessageFilter>(frame_));
}
void LocalFrameMojoHandler::BindToMainFrameReceiver(
mojo::PendingAssociatedReceiver<mojom::blink::LocalMainFrame> receiver) {
if (frame_->IsDetached())
return;
main_frame_receiver_.Bind(std::move(receiver),
frame_->GetTaskRunner(TaskType::kInternalDefault));
main_frame_receiver_.SetFilter(
std::make_unique<ActiveURLMessageFilter>(frame_));
}
void LocalFrameMojoHandler::BindToHighPriorityReceiver(
mojo::PendingReceiver<mojom::blink::HighPriorityLocalFrame> receiver) {
if (frame_->IsDetached())
return;
high_priority_frame_receiver_.Bind(
std::move(receiver),
frame_->GetTaskRunner(TaskType::kInternalHighPriorityLocalFrame));
high_priority_frame_receiver_.SetFilter(
std::make_unique<ActiveURLMessageFilter>(frame_));
}
void LocalFrameMojoHandler::BindFullscreenVideoElementReceiver(
mojo::PendingAssociatedReceiver<mojom::blink::FullscreenVideoElementHandler>
receiver) {
if (frame_->IsDetached())
return;
fullscreen_video_receiver_.Bind(
std::move(receiver), frame_->GetTaskRunner(TaskType::kInternalDefault));
fullscreen_video_receiver_.SetFilter(
std::make_unique<ActiveURLMessageFilter>(frame_));
}
void LocalFrameMojoHandler::GetTextSurroundingSelection(
uint32_t max_length,
GetTextSurroundingSelectionCallback callback) {
SurroundingText surrounding_text(frame_, max_length);
// |surrounding_text| might not be correctly initialized, for example if
// |frame_->SelectionRange().IsNull()|, in other words, if there was no
// selection.
if (surrounding_text.IsEmpty()) {
// Don't use WTF::String's default constructor so that we make sure that we
// always send a valid empty string over the wire instead of a null pointer.
std::move(callback).Run(g_empty_string, 0, 0);
return;
}
std::move(callback).Run(surrounding_text.TextContent(),
surrounding_text.StartOffsetInTextContent(),
surrounding_text.EndOffsetInTextContent());
}
void LocalFrameMojoHandler::SendInterventionReport(const String& id,
const String& message) {
Intervention::GenerateReport(frame_, id, message);
}
void LocalFrameMojoHandler::SetFrameOwnerProperties(
mojom::blink::FrameOwnerPropertiesPtr properties) {
GetDocument()->WillChangeFrameOwnerProperties(
properties->margin_width, properties->margin_height,
properties->scrollbar_mode, properties->is_display_none,
properties->color_scheme);
frame_->ApplyFrameOwnerProperties(std::move(properties));
}
void LocalFrameMojoHandler::NotifyUserActivation(
mojom::blink::UserActivationNotificationType notification_type) {
frame_->NotifyUserActivation(notification_type);
}
void LocalFrameMojoHandler::NotifyVirtualKeyboardOverlayRect(
const gfx::Rect& keyboard_rect) {
Page* page = GetPage();
if (!page)
return;
// The rect passed to us from content is in DIP, relative to the main frame.
// This doesn't take the page's zoom factor into account so we must scale by
// the inverse of the page zoom in order to get correct client coordinates.
// WindowToViewportScalar is the device scale factor while PageZoomFactor is
// the combination of the device scale factor and the zoom factor of the
// page.
blink::LocalFrame& local_frame_root = frame_->LocalFrameRoot();
const float window_to_viewport_factor =
page->GetChromeClient().WindowToViewportScalar(&local_frame_root, 1.0f);
const float zoom_factor = local_frame_root.PageZoomFactor();
const float scale_factor = zoom_factor / window_to_viewport_factor;
gfx::Rect scaled_rect(keyboard_rect.x() / scale_factor,
keyboard_rect.y() / scale_factor,
keyboard_rect.width() / scale_factor,
keyboard_rect.height() / scale_factor);
frame_->NotifyVirtualKeyboardOverlayRectObservers(scaled_rect);
}
void LocalFrameMojoHandler::AddMessageToConsole(
mojom::blink::ConsoleMessageLevel level,
const WTF::String& message,
bool discard_duplicates) {
GetDocument()->AddConsoleMessage(
MakeGarbageCollected<ConsoleMessage>(
mojom::blink::ConsoleMessageSource::kOther, level, message),
discard_duplicates);
}
void LocalFrameMojoHandler::AddInspectorIssue(
mojom::blink::InspectorIssueInfoPtr info) {
if (auto* page = GetPage()) {
page->GetInspectorIssueStorage().AddInspectorIssue(DomWindow(),
std::move(info));
}
}
void LocalFrameMojoHandler::SwapInImmediately() {
frame_->SwapIn();
// Normally, this happens as part of committing a cross-Document navigation.
// However, there is no navigation being committed here. Instead, the browser
// navigation code is optimistically early-swapping in this frame to replace a
// crashed subframe after starting a navigation.
//
// While the provisional frame has a unique opaque origin, the Blink bindings
// code still expects the WindowProxy to be initialized for the access check
// failed callbacks.
DomWindow()->GetScriptController().UpdateDocument();
}
void LocalFrameMojoHandler::CheckCompleted() {
frame_->CheckCompleted();
}
void LocalFrameMojoHandler::StopLoading() {
frame_->Loader().StopAllLoaders(/*abort_client=*/true);
// The stopLoading handler may run script, which may cause this frame to be
// detached/deleted. If that happens, return immediately.
if (!frame_->IsAttached())
return;
// Notify RenderFrame observers.
WebLocalFrameClient* client = frame_->Client()->GetWebFrame()->Client();
if (client)
client->OnStopLoading();
}
void LocalFrameMojoHandler::Collapse(bool collapsed) {
FrameOwner* owner = frame_->Owner();
To<HTMLFrameOwnerElement>(owner)->SetCollapsed(collapsed);
}
void LocalFrameMojoHandler::EnableViewSourceMode() {
DCHECK(frame_->IsOutermostMainFrame());
frame_->SetInViewSourceMode(true);
}
void LocalFrameMojoHandler::Focus() {
frame_->FocusImpl();
}
void LocalFrameMojoHandler::ClearFocusedElement() {
Document* document = GetDocument();
Element* old_focused_element = document->FocusedElement();
document->ClearFocusedElement();
if (!old_focused_element)
return;
// If a text field has focus, we need to make sure the selection controller
// knows to remove selection from it. Otherwise, the text field is still
// processing keyboard events even though focus has been moved to the page and
// keystrokes get eaten as a result.
document->UpdateStyleAndLayoutTree();
if (IsEditable(*old_focused_element) ||
old_focused_element->IsTextControl()) {
frame_->Selection().Clear();
}
}
void LocalFrameMojoHandler::CopyImageAt(const gfx::Point& window_point) {
gfx::Point viewport_position =
frame_->GetWidgetForLocalRoot()->DIPsToRoundedBlinkSpace(window_point);
frame_->CopyImageAtViewportPoint(viewport_position);
}
void LocalFrameMojoHandler::SaveImageAt(const gfx::Point& window_point) {
frame_->SaveImageAt(window_point);
}
void LocalFrameMojoHandler::ReportBlinkFeatureUsage(
const Vector<mojom::blink::WebFeature>& features) {
DCHECK(!features.empty());
// Assimilate all features used/performed by the browser into UseCounter.
auto* document = GetDocument();
DCHECK(document);
for (const auto& feature : features)
document->CountUse(feature);
}
void LocalFrameMojoHandler::RenderFallbackContent() {
frame_->RenderFallbackContent();
}
void LocalFrameMojoHandler::BeforeUnload(bool is_reload,
BeforeUnloadCallback callback) {
base::TimeTicks before_unload_start_time = base::TimeTicks::Now();
// This will execute the BeforeUnload event in this frame and all of its
// local descendant frames, including children of remote frames. The browser
// process will send separate IPCs to dispatch beforeunload in any
// out-of-process child frames.
bool proceed = frame_->Loader().ShouldClose(is_reload);
DCHECK(!callback.is_null());
base::TimeTicks before_unload_end_time = base::TimeTicks::Now();
std::move(callback).Run(proceed, before_unload_start_time,
before_unload_end_time);
}
void LocalFrameMojoHandler::MediaPlayerActionAt(
const gfx::Point& window_point,
blink::mojom::blink::MediaPlayerActionPtr action) {
gfx::Point viewport_position =
frame_->GetWidgetForLocalRoot()->DIPsToRoundedBlinkSpace(window_point);
frame_->MediaPlayerActionAtViewportPoint(viewport_position, action->type,
action->enable);
}
void LocalFrameMojoHandler::AdvanceFocusInFrame(
mojom::blink::FocusType focus_type,
const absl::optional<RemoteFrameToken>& source_frame_token) {
RemoteFrame* source_frame =
source_frame_token ? SourceFrameForOptionalToken(*source_frame_token)
: nullptr;
if (!source_frame) {
SetInitialFocus(focus_type == mojom::blink::FocusType::kBackward);
return;
}
GetPage()->GetFocusController().AdvanceFocusAcrossFrames(
focus_type, source_frame, frame_);
}
void LocalFrameMojoHandler::AdvanceFocusForIME(
mojom::blink::FocusType focus_type) {
auto* focused_frame = GetPage()->GetFocusController().FocusedFrame();
if (focused_frame != frame_)
return;
DCHECK(GetDocument());
Element* element = GetDocument()->FocusedElement();
if (!element)
return;
Element* next_element =
GetPage()->GetFocusController().NextFocusableElementForImeAndAutofill(
element, focus_type);
if (!next_element)
return;
next_element->scrollIntoViewIfNeeded(true /*centerIfNeeded*/);
next_element->Focus();
}
void LocalFrameMojoHandler::ReportContentSecurityPolicyViolation(
network::mojom::blink::CSPViolationPtr violation) {
auto source_location = std::make_unique<SourceLocation>(
violation->source_location->url, String(),
violation->source_location->line, violation->source_location->column,
nullptr);
frame_->Console().AddMessage(MakeGarbageCollected<ConsoleMessage>(
mojom::blink::ConsoleMessageSource::kSecurity,
mojom::blink::ConsoleMessageLevel::kError, violation->console_message,
source_location->Clone()));
auto directive_type =
ContentSecurityPolicy::GetDirectiveType(violation->effective_directive);
blink::LocalFrame* context_frame =
directive_type == network::mojom::blink::CSPDirectiveName::FrameAncestors
? frame_
: nullptr;
DomWindow()->GetContentSecurityPolicy()->ReportViolation(
violation->directive, directive_type, violation->console_message,
violation->blocked_url, violation->report_endpoints,
violation->use_reporting_api, violation->header, violation->type,
ContentSecurityPolicyViolationType::kURLViolation,
std::move(source_location), context_frame, nullptr /* Element */);
}
void LocalFrameMojoHandler::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>(frame_->Owner()));
To<RemoteFrameOwner>(frame_->Owner())->SetFramePolicy(frame_policy);
}
void LocalFrameMojoHandler::OnPostureChanged(
device::mojom::blink::DevicePostureType posture) {
if (!RuntimeEnabledFeatures::DevicePostureEnabled())
return;
current_device_posture_ = posture;
// A change of the device posture requires re-evaluation of media queries
// for the local frame subtree (the device posture affect the
// "device-posture" feature).
frame_->MediaQueryAffectingValueChangedForLocalSubtree(
MediaValueChange::kOther);
}
void LocalFrameMojoHandler::PostMessageEvent(
const absl::optional<RemoteFrameToken>& source_frame_token,
const String& source_origin,
const String& target_origin,
BlinkTransferableMessage message) {
frame_->PostMessageEvent(source_frame_token, source_origin, target_origin,
std::move(message));
}
void LocalFrameMojoHandler::JavaScriptMethodExecuteRequest(
const String& object_name,
const String& method_name,
base::Value::List arguments,
bool wants_result,
JavaScriptMethodExecuteRequestCallback callback) {
TRACE_EVENT_INSTANT0("test_tracing", "JavaScriptMethodExecuteRequest",
TRACE_EVENT_SCOPE_THREAD);
std::unique_ptr<WebV8ValueConverter> converter =
Platform::Current()->CreateWebV8ValueConverter();
converter->SetDateAllowed(true);
converter->SetRegExpAllowed(true);
v8::HandleScope handle_scope(ToIsolate(frame_));
v8::Local<v8::Value> result;
if (!CallMethodOnFrame(frame_, object_name, method_name, std::move(arguments),
converter.get())
.ToLocal(&result)) {
std::move(callback).Run({});
} else if (wants_result) {
v8::Local<v8::Context> context = MainWorldScriptContext(frame_);
std::move(callback).Run(
GetJavaScriptExecutionResult(result, context, converter.get()));
} else {
std::move(callback).Run({});
}
}
void LocalFrameMojoHandler::JavaScriptExecuteRequest(
const String& javascript,
bool wants_result,
JavaScriptExecuteRequestCallback callback) {
TRACE_EVENT_INSTANT0("test_tracing", "JavaScriptExecuteRequest",
TRACE_EVENT_SCOPE_THREAD);
v8::HandleScope handle_scope(ToIsolate(frame_));
v8::Local<v8::Value> result =
ClassicScript::CreateUnspecifiedScript(javascript)
->RunScriptAndReturnValue(DomWindow())
.GetSuccessValueOrEmpty();
if (wants_result) {
std::unique_ptr<WebV8ValueConverter> converter =
Platform::Current()->CreateWebV8ValueConverter();
converter->SetDateAllowed(true);
converter->SetRegExpAllowed(true);
v8::Local<v8::Context> context = MainWorldScriptContext(frame_);
std::move(callback).Run(
GetJavaScriptExecutionResult(result, context, converter.get()));
} else {
std::move(callback).Run({});
}
}
void LocalFrameMojoHandler::JavaScriptExecuteRequestForTests(
const String& javascript,
bool has_user_gesture,
bool resolve_promises,
int32_t world_id,
JavaScriptExecuteRequestForTestsCallback callback) {
TRACE_EVENT_INSTANT0("test_tracing", "JavaScriptExecuteRequestForTests",
TRACE_EVENT_SCOPE_THREAD);
// A bunch of tests expect to run code in the context of a user gesture, which
// can grant additional privileges (e.g. the ability to create popups).
if (has_user_gesture)
NotifyUserActivation(mojom::blink::UserActivationNotificationType::kTest);
v8::Isolate* isolate = ToIsolate(frame_);
ScriptState* script_state =
(world_id == DOMWrapperWorld::kMainWorldId)
? ToScriptStateForMainWorld(frame_)
: ToScriptState(frame_, *DOMWrapperWorld::EnsureIsolatedWorld(
isolate, world_id));
ScriptState::Scope script_state_scope(script_state);
// `kDoNotSanitize` is used because this is only for tests and some tests
// need `kDoNotSanitize` for dynamic imports.
ClassicScript* script = ClassicScript::CreateUnspecifiedScript(
javascript, ScriptSourceLocationType::kUnknown,
SanitizeScriptErrors::kDoNotSanitize);
ScriptEvaluationResult result =
script->RunScriptOnScriptStateAndReturnValue(script_state);
auto* handler = MakeGarbageCollected<JavaScriptExecuteRequestForTestsHandler>(
std::move(callback));
v8::Local<v8::Value> error;
switch (result.GetResultType()) {
case ScriptEvaluationResult::ResultType::kSuccess: {
v8::Local<v8::Value> value = result.GetSuccessValue();
if (resolve_promises && !value.IsEmpty() && value->IsPromise()) {
ScriptPromise promise = ScriptPromise::Cast(script_state, value);
promise.Then(handler->CreateResolveCallback(script_state, frame_),
handler->CreateRejectCallback(script_state, frame_));
} else {
handler->SendSuccess(script_state, value);
}
return;
}
case ScriptEvaluationResult::ResultType::kException:
error = result.GetExceptionForClassicForTesting();
break;
case ScriptEvaluationResult::ResultType::kAborted:
error = v8::String::NewFromUtf8Literal(isolate, "Script aborted");
break;
case ScriptEvaluationResult::ResultType::kNotRun:
error = v8::String::NewFromUtf8Literal(isolate, "Script not run");
break;
}
DCHECK_NE(result.GetResultType(),
ScriptEvaluationResult::ResultType::kSuccess);
handler->SendException(script_state, error);
}
void LocalFrameMojoHandler::JavaScriptExecuteRequestInIsolatedWorld(
const String& javascript,
bool wants_result,
int32_t world_id,
JavaScriptExecuteRequestInIsolatedWorldCallback callback) {
TRACE_EVENT_INSTANT0("test_tracing",
"JavaScriptExecuteRequestInIsolatedWorld",
TRACE_EVENT_SCOPE_THREAD);
if (world_id <= DOMWrapperWorld::kMainWorldId ||
world_id > DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit) {
// Returns if the world_id is not valid. world_id is passed as a plain int
// over IPC and needs to be verified here, in the IPC endpoint.
std::move(callback).Run(base::Value());
mojo::ReportBadMessage(kInvalidWorldID);
return;
}
WebScriptSource web_script_source(javascript);
frame_->RequestExecuteScript(
world_id, {&web_script_source, 1u},
mojom::blink::UserActivationOption::kDoNotActivate,
mojom::blink::EvaluationTiming::kSynchronous,
mojom::blink::LoadEventBlockingOption::kDoNotBlock,
WTF::BindOnce(
[](JavaScriptExecuteRequestInIsolatedWorldCallback callback,
absl::optional<base::Value> value, base::TimeTicks start_time) {
std::move(callback).Run(value ? std::move(*value) : base::Value());
},
std::move(callback)),
BackForwardCacheAware::kAllow,
wants_result
? mojom::blink::WantResultOption::kWantResultDateAndRegExpAllowed
: mojom::blink::WantResultOption::kNoResult,
mojom::blink::PromiseResultOption::kDoNotWait);
}
#if BUILDFLAG(IS_MAC)
void LocalFrameMojoHandler::GetCharacterIndexAtPoint(const gfx::Point& point) {
frame_->GetCharacterIndexAtPoint(point);
}
void LocalFrameMojoHandler::GetFirstRectForRange(const gfx::Range& range) {
gfx::Rect rect;
WebLocalFrameClient* client = WebLocalFrameImpl::FromFrame(frame_)->Client();
if (!client)
return;
WebPluginContainerImpl* plugin_container = frame_->GetWebPluginContainer();
if (plugin_container) {
// Pepper-free PDF will reach here.
FrameWidget* frame_widget = frame_->GetWidgetForLocalRoot();
rect = frame_widget->BlinkSpaceToEnclosedDIPs(
plugin_container->Plugin()->GetPluginCaretBounds());
} else {
// TODO(crbug.com/702990): Remove `pepper_has_caret` once pepper is removed.
bool pepper_has_caret = client->GetCaretBoundsFromFocusedPlugin(rect);
if (!pepper_has_caret) {
// When request range is invalid we will try to obtain it from current
// frame selection. The fallback value will be 0.
size_t start = range.IsValid()
? range.start()
: GetCurrentCursorPositionInFrame(frame_);
WebLocalFrameImpl::FromFrame(frame_)->FirstRectForCharacterRange(
base::checked_cast<uint32_t>(start),
base::checked_cast<uint32_t>(range.length()), rect);
}
}
TextInputHost().GotFirstRectForRange(rect);
}
void LocalFrameMojoHandler::GetStringForRange(
const gfx::Range& range,
GetStringForRangeCallback callback) {
gfx::Point baseline_point;
ui::mojom::blink::AttributedStringPtr attributed_string = nullptr;
base::ScopedCFTypeRef<CFAttributedStringRef> string =
SubstringUtil::AttributedSubstringInRange(
frame_, base::checked_cast<WTF::wtf_size_t>(range.start()),
base::checked_cast<WTF::wtf_size_t>(range.length()), baseline_point);
if (string) {
attributed_string = ui::mojom::blink::AttributedString::From(string.get());
}
std::move(callback).Run(std::move(attributed_string), baseline_point);
}
#endif
void LocalFrameMojoHandler::BindReportingObserver(
mojo::PendingReceiver<mojom::blink::ReportingObserver> receiver) {
ReportingContext::From(DomWindow())->Bind(std::move(receiver));
}
void LocalFrameMojoHandler::UpdateOpener(
const absl::optional<blink::FrameToken>& opener_frame_token) {
if (auto* web_frame = WebFrame::FromCoreFrame(frame_)) {
Frame* opener_frame = nullptr;
if (opener_frame_token)
opener_frame = Frame::ResolveFrame(opener_frame_token.value());
frame_->SetOpenerDoNotNotify(opener_frame);
}
}
void LocalFrameMojoHandler::GetSavableResourceLinks(
GetSavableResourceLinksCallback callback) {
Vector<KURL> resources_list;
Vector<mojom::blink::SavableSubframePtr> subframes;
SavableResources::Result result(&resources_list, &subframes);
if (!SavableResources::GetSavableResourceLinksForFrame(frame_, &result)) {
std::move(callback).Run(nullptr);
return;
}
auto referrer = mojom::blink::Referrer::New(GetDocument()->Url(),
DomWindow()->GetReferrerPolicy());
auto reply = mojom::blink::GetSavableResourceLinksReply::New();
reply->resources_list = std::move(resources_list);
reply->referrer = std::move(referrer);
reply->subframes = std::move(subframes);
std::move(callback).Run(std::move(reply));
}
void LocalFrameMojoHandler::MixedContentFound(
const KURL& main_resource_url,
const KURL& mixed_content_url,
mojom::blink::RequestContextType request_context,
bool was_allowed,
const KURL& url_before_redirects,
bool had_redirect,
network::mojom::blink::SourceLocationPtr source_location) {
std::unique_ptr<SourceLocation> source;
if (source_location) {
source = std::make_unique<SourceLocation>(source_location->url, String(),
source_location->line,
source_location->column, nullptr);
}
MixedContentChecker::MixedContentFound(
frame_, main_resource_url, mixed_content_url, request_context,
was_allowed, url_before_redirects, had_redirect, std::move(source));
}
void LocalFrameMojoHandler::BindDevToolsAgent(
mojo::PendingAssociatedRemote<mojom::blink::DevToolsAgentHost> host,
mojo::PendingAssociatedReceiver<mojom::blink::DevToolsAgent> receiver) {
DCHECK(frame_->Client());
frame_->Client()->BindDevToolsAgent(std::move(host), std::move(receiver));
}
#if BUILDFLAG(IS_ANDROID)
void LocalFrameMojoHandler::ExtractSmartClipData(
const gfx::Rect& rect,
ExtractSmartClipDataCallback callback) {
String clip_text;
String clip_html;
gfx::Rect clip_rect;
frame_->ExtractSmartClipDataInternal(rect, clip_text, clip_html, clip_rect);
std::move(callback).Run(clip_text.IsNull() ? g_empty_string : clip_text,
clip_html.IsNull() ? g_empty_string : clip_html,
clip_rect);
}
#endif // BUILDFLAG(IS_ANDROID)
void LocalFrameMojoHandler::HandleRendererDebugURL(const KURL& url) {
DCHECK(IsRendererDebugURL(GURL(url)));
if (url.ProtocolIs("javascript")) {
// JavaScript URLs should be sent to Blink for handling.
frame_->LoadJavaScriptURL(url);
} else {
// This is a Chrome Debug URL. Handle it.
HandleChromeDebugURL(GURL(url));
}
// The browser sets its status as loading before calling this IPC. Inform it
// that the load stopped if needed, while leaving the debug URL visible in the
// address bar.
if (!frame_->IsLoading())
frame_->Client()->DidStopLoading();
}
void LocalFrameMojoHandler::GetCanonicalUrlForSharing(
GetCanonicalUrlForSharingCallback callback) {
#if BUILDFLAG(IS_ANDROID)
base::TimeTicks start_time = base::TimeTicks::Now();
#endif
KURL canon_url;
HTMLLinkElement* link_element = GetDocument()->LinkCanonical();
if (link_element) {
canon_url = link_element->Href();
KURL doc_url = GetDocument()->Url();
// When sharing links to pages, the fragment identifier often serves to mark a specific place
// within the page that the user wishes to point the recipient to. Canonical URLs generally
// don't and can't contain this state, so try to match user expectations a little more closely
// here by splicing the fragment identifier (if there is one) into the shared URL.
if (doc_url.HasFragmentIdentifier() && !canon_url.HasFragmentIdentifier())
canon_url.SetFragmentIdentifier(doc_url.FragmentIdentifier());
}
std::move(callback).Run(canon_url.IsNull() ? absl::nullopt
: absl::make_optional(canon_url));
#if BUILDFLAG(IS_ANDROID)
base::UmaHistogramMicrosecondsTimes("Blink.Frame.GetCanonicalUrlRendererTime",
base::TimeTicks::Now() - start_time);
#endif
}
void LocalFrameMojoHandler::GetOpenGraphMetadata(
GetOpenGraphMetadataCallback callback) {
auto metadata = mojom::blink::OpenGraphMetadata::New();
for (const auto& child : Traversal<HTMLMetaElement>::DescendantsOf(
*frame_->GetDocument()->documentElement())) {
// If there are multiple OpenGraph tags for the same property, we always
// take the value from the first one - this is the specified behavior in
// the OpenGraph spec:
// The first tag (from top to bottom) is given preference during conflicts
ParseOpenGraphProperty(child, *frame_->GetDocument(), metadata.get());
}
std::move(callback).Run(std::move(metadata));
}
void LocalFrameMojoHandler::SetNavigationApiHistoryEntriesForRestore(
mojom::blink::NavigationApiHistoryEntryArraysPtr entry_arrays) {
frame_->DomWindow()->navigation()->SetEntriesForRestore(entry_arrays);
}
void LocalFrameMojoHandler::NotifyNavigationApiOfDisposedEntries(
const WTF::Vector<WTF::String>& keys) {
frame_->DomWindow()->navigation()->DisposeEntriesForSessionHistoryRemoval(
keys);
}
void LocalFrameMojoHandler::TraverseCancelled(
const String& navigation_api_key,
mojom::blink::TraverseCancelledReason reason) {
frame_->DomWindow()->navigation()->TraverseCancelled(navigation_api_key,
reason);
}
void LocalFrameMojoHandler::AnimateDoubleTapZoom(const gfx::Point& point,
const gfx::Rect& rect) {
frame_->GetPage()->GetChromeClient().AnimateDoubleTapZoom(point, rect);
}
void LocalFrameMojoHandler::SetScaleFactor(float scale_factor) {
frame_->SetScaleFactor(scale_factor);
}
void LocalFrameMojoHandler::ClosePage(
mojom::blink::LocalMainFrame::ClosePageCallback completion_callback) {
SECURITY_CHECK(frame_->IsOutermostMainFrame());
// There are two ways to close a page:
//
// 1/ Via webview()->Close() that currently sets the WebView's delegate_ to
// NULL, and prevent any JavaScript dialogs in the onunload handler from
// appearing.
//
// 2/ Calling the FrameLoader's CloseURL method directly.
//
// TODO(creis): Having a single way to close that can run onunload is also
// useful for fixing http://b/issue?id=753080.
SubframeLoadingDisabler disabler(frame_->GetDocument());
// https://html.spec.whatwg.org/C/browsing-the-web.html#unload-a-document
// The ignore-opens-during-unload counter of a Document must be incremented
// when unloading itself.
IgnoreOpensDuringUnloadCountIncrementer ignore_opens_during_unload(
frame_->GetDocument());
frame_->Loader().DispatchUnloadEventAndFillOldDocumentInfoIfNeeded(
false /* need_unload_info_for_new_document */);
std::move(completion_callback).Run();
}
void LocalFrameMojoHandler::GetFullPageSize(
mojom::blink::LocalMainFrame::GetFullPageSizeCallback callback) {
// PageZoomFactor takes CSS pixels to device/physical pixels. It includes
// both browser ctrl+/- zoom as well as the device scale factor for screen
// density. Note: we don't account for pinch-zoom, even though it scales a
// CSS pixel, since "device pixels" coming from Blink are also unscaled by
// pinch-zoom.
float css_to_physical = frame_->PageZoomFactor();
float physical_to_css = 1.f / css_to_physical;
gfx::Size full_page_size =
frame_->View()->GetScrollableArea()->ContentsSize();
// `content_size` is in physical pixels. Normlisation is needed to convert it
// to CSS pixels. Details: https://crbug.com/1181313
gfx::Size css_full_page_size =
gfx::ScaleToFlooredSize(full_page_size, physical_to_css);
std::move(callback).Run(
gfx::Size(css_full_page_size.width(), css_full_page_size.height()));
}
void LocalFrameMojoHandler::PluginActionAt(
const gfx::Point& location,
mojom::blink::PluginActionType action) {
// TODO(bokan): Location is probably in viewport coordinates
HitTestResult result =
HitTestResultForRootFramePos(frame_, PhysicalOffset(location));
Node* node = result.InnerNode();
if (!IsA<HTMLObjectElement>(*node) && !IsA<HTMLEmbedElement>(*node))
return;
auto* embedded = DynamicTo<LayoutEmbeddedContent>(node->GetLayoutObject());
if (!embedded)
return;
WebPluginContainerImpl* plugin_view = embedded->Plugin();
if (!plugin_view)
return;
switch (action) {
case mojom::blink::PluginActionType::kRotate90Clockwise:
plugin_view->Plugin()->RotateView(WebPlugin::RotationType::k90Clockwise);
return;
case mojom::blink::PluginActionType::kRotate90Counterclockwise:
plugin_view->Plugin()->RotateView(
WebPlugin::RotationType::k90Counterclockwise);
return;
}
NOTREACHED();
}
void LocalFrameMojoHandler::SetInitialFocus(bool reverse) {
frame_->SetInitialFocus(reverse);
}
void LocalFrameMojoHandler::EnablePreferredSizeChangedMode() {
frame_->GetPage()->GetChromeClient().EnablePreferredSizeChangedMode();
}
void LocalFrameMojoHandler::ZoomToFindInPageRect(
const gfx::Rect& rect_in_root_frame) {
frame_->GetPage()->GetChromeClient().ZoomToFindInPageRect(rect_in_root_frame);
}
void LocalFrameMojoHandler::InstallCoopAccessMonitor(
const FrameToken& accessed_window,
network::mojom::blink::CrossOriginOpenerPolicyReporterParamsPtr
coop_reporter_params,
bool is_in_same_virtual_coop_related_group) {
blink::Frame* accessed_frame = Frame::ResolveFrame(accessed_window);
// The Frame might have been deleted during the cross-process communication.
if (!accessed_frame)
return;
accessed_frame->DomWindow()->InstallCoopAccessMonitor(
frame_, std::move(coop_reporter_params),
is_in_same_virtual_coop_related_group);
}
void LocalFrameMojoHandler::OnPortalActivated(
const PortalToken& portal_token,
mojo::PendingAssociatedRemote<mojom::blink::Portal> portal,
mojo::PendingAssociatedReceiver<mojom::blink::PortalClient> portal_client,
BlinkTransferableMessage data,
uint64_t trace_id,
OnPortalActivatedCallback callback) {
DCHECK(frame_->GetDocument());
LocalDOMWindow* dom_window = frame_->DomWindow();
PaintTiming::From(*frame_->GetDocument()).OnPortalActivate();
TRACE_EVENT_WITH_FLOW0("navigation", "LocalFrame::OnPortalActivated",
TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN);
DOMWindowPortalHost::portalHost(*dom_window)->OnPortalActivated();
frame_->GetPage()->SetInsidePortal(false);
DCHECK(!data.locked_to_sender_agent_cluster)
<< "portal activation is always cross-agent-cluster and should be "
"diagnosed early";
MessagePortArray* ports =
MessagePort::EntanglePorts(*dom_window, std::move(data.ports));
PortalActivateEvent* event = PortalActivateEvent::Create(
frame_, portal_token, std::move(portal), std::move(portal_client),
std::move(data.message), ports, std::move(callback));
ThreadDebugger* debugger = MainThreadDebugger::Instance();
if (debugger)
debugger->ExternalAsyncTaskStarted(data.sender_stack_trace_id);
dom_window->DispatchEvent(*event);
if (debugger)
debugger->ExternalAsyncTaskFinished(data.sender_stack_trace_id);
event->ExpireAdoptionLifetime();
}
void LocalFrameMojoHandler::ForwardMessageFromHost(
BlinkTransferableMessage message,
const scoped_refptr<const SecurityOrigin>& source_origin) {
PortalHost::From(*frame_->DomWindow())
.ReceiveMessage(std::move(message), source_origin);
}
void LocalFrameMojoHandler::UpdateBrowserControlsState(
cc::BrowserControlsState constraints,
cc::BrowserControlsState current,
bool animate) {
DCHECK(frame_->IsOutermostMainFrame());
TRACE_EVENT2("renderer", "LocalFrame::UpdateBrowserControlsState",
"Constraint", static_cast<int>(constraints), "Current",
static_cast<int>(current));
TRACE_EVENT_INSTANT1("renderer", "is_animated", TRACE_EVENT_SCOPE_THREAD,
"animated", animate);
frame_->GetWidgetForLocalRoot()->UpdateBrowserControlsState(constraints,
current, animate);
}
void LocalFrameMojoHandler::SnapshotDocumentForViewTransition(
SnapshotDocumentForViewTransitionCallback callback) {
ViewTransitionSupplement::SnapshotDocumentForNavigation(
*frame_->GetDocument(), std::move(callback));
}
void LocalFrameMojoHandler::DispatchBeforeUnload(
bool is_reload,
mojom::blink::LocalFrame::BeforeUnloadCallback callback) {
BeforeUnload(is_reload, std::move(callback));
}
void LocalFrameMojoHandler::AddResourceTimingEntryForFailedSubframeNavigation(
const FrameToken& subframe_token,
const KURL& initial_url,
base::TimeTicks start_time,
base::TimeTicks redirect_time,
base::TimeTicks request_start,
base::TimeTicks response_start,
uint32_t response_code,
const WTF::String& mime_type,
network::mojom::blink::LoadTimingInfoPtr load_timing_info,
net::HttpResponseInfo::ConnectionInfo connection_info,
const WTF::String& alpn_negotiated_protocol,
bool is_secure_transport,
bool is_validated,
const WTF::String& normalized_server_timing,
const network::URLLoaderCompletionStatus& completion_status) {
Frame* subframe = Frame::ResolveFrame(subframe_token);
if (!subframe || !subframe->Owner()) {
return;
}
ResourceResponse response;
response.SetAlpnNegotiatedProtocol(AtomicString(alpn_negotiated_protocol));
response.SetConnectionInfo(connection_info);
response.SetConnectionReused(load_timing_info->socket_reused);
response.SetTimingAllowPassed(true);
response.SetIsValidated(is_validated);
response.SetDecodedBodyLength(completion_status.decoded_body_length);
response.SetEncodedBodyLength(completion_status.encoded_body_length);
response.SetEncodedDataLength(completion_status.encoded_data_length);
response.SetHttpStatusCode(response_code);
if (!normalized_server_timing.empty()) {
response.SetHttpHeaderField(http_names::kServerTiming,
AtomicString(normalized_server_timing));
}
mojom::blink::ResourceTimingInfoPtr info =
CreateResourceTimingInfo(start_time, initial_url, &response);
info->response_end = completion_status.completion_time;
info->last_redirect_end_time = redirect_time;
info->is_secure_transport = is_secure_transport;
info->timing = std::move(load_timing_info);
subframe->Owner()->AddResourceTiming(std::move(info));
}
void LocalFrameMojoHandler::RequestFullscreenDocumentElement() {
// Bail early and report failure if fullscreen is not enabled.
if (!Fullscreen::FullscreenEnabled(*frame_->GetDocument(),
ReportOptions::kReportOnFailure)) {
return;
}
if (auto* document_element = frame_->GetDocument()->documentElement()) {
// `kWindowOpen` assumes this function is only invoked for newly created
// windows (e.g. fullscreen popups). Update this if additional callers are
// added. See: https://chromestatus.com/feature/6002307972464640
ScopedAllowFullscreen allow_fullscreen(ScopedAllowFullscreen::kWindowOpen);
Fullscreen::RequestFullscreen(*document_element);
}
}
void LocalFrameMojoHandler::RequestFullscreenVideoElement() {
// Find the first video element of the frame.
for (auto* child = frame_->GetDocument()->documentElement(); child;
child = Traversal<HTMLElement>::Next(*child)) {
if (IsA<HTMLVideoElement>(child)) {
// This is always initiated from browser side (which should require the
// user interacting with ui) which suffices for a user gesture even though
// there will have been no input to the frame at this point.
frame_->NotifyUserActivation(
mojom::blink::UserActivationNotificationType::kInteraction);
Fullscreen::RequestFullscreen(*child);
return;
}
}
}
} // namespace blink