blob: 50549a208ad2708a47309c5c712ad2cdaad79694 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/renderer_host/render_view_host_impl.h"
#include <set>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/debug/dump_without_crashing.h"
#include "base/feature_list.h"
#include "base/hash/hash.h"
#include "base/i18n/rtl.h"
#include "base/json/json_reader.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/supports_user_data.h"
#include "base/system/sys_info.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/typed_macros.h"
#include "base/values.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "content/browser/bad_message.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
#include "content/browser/fenced_frame/fenced_frame.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/renderer_host/agent_scheduling_group_host.h"
#include "content/browser/renderer_host/frame_tree.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/renderer_host/input/timeout_monitor.h"
#include "content/browser/renderer_host/navigation_controller_impl.h"
#include "content/browser/renderer_host/render_frame_proxy_host.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_view_host_delegate_view.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/browser/scoped_active_url.h"
#include "content/common/agent_scheduling_group.mojom.h"
#include "content/common/content_switches_internal.h"
#include "content/common/render_message_filter.mojom.h"
#include "content/common/renderer.mojom.h"
#include "content/public/browser/ax_event_notification_details.h"
#include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/context_menu_params.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
#include "media/base/media_switches.h"
#include "net/base/url_util.h"
#include "services/network/public/cpp/features.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/device_form_factor.h"
#include "ui/base/pointer/pointer_device.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/display/display.h"
#include "ui/display/display_switches.h"
#include "ui/display/screen.h"
#include "ui/events/blink/blink_features.h"
#include "ui/gfx/animation/animation.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gl/gpu_switching_manager.h"
#include "ui/native_theme/native_theme_features.h"
#include "url/url_constants.h"
#if BUILDFLAG(IS_WIN)
#include "ui/display/win/screen_win.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/system_fonts_win.h"
#endif
#if !BUILDFLAG(IS_ANDROID)
#include "content/browser/host_zoom_map_impl.h"
#endif
#if defined(USE_OZONE)
#include "ui/base/ui_base_features.h"
#endif
using blink::WebInputEvent;
namespace content {
namespace {
using perfetto::protos::pbzero::ChromeTrackEvent;
// <process id, routing id>
using RenderViewHostID = std::pair<int32_t, int32_t>;
using RoutingIDViewMap =
std::unordered_map<RenderViewHostID,
RenderViewHostImpl*,
base::IntPairHash<RenderViewHostID>>;
base::LazyInstance<RoutingIDViewMap>::Leaky g_routing_id_view_map =
LAZY_INSTANCE_INITIALIZER;
#if BUILDFLAG(IS_WIN)
// Fetches the name and font size of a particular Windows system font.
void GetFontInfo(gfx::win::SystemFont system_font,
std::u16string* name,
int32_t* size) {
const gfx::Font& font = gfx::win::GetSystemFont(system_font);
*name = base::UTF8ToUTF16(font.GetFontName());
*size = font.GetFontSize();
}
#endif // BUILDFLAG(IS_WIN)
// Set of RenderViewHostImpl* that can be attached as UserData to a
// RenderProcessHost. Used to keep track of whether any RenderViewHostImpl
// instances are in the bfcache.
class PerProcessRenderViewHostSet : public base::SupportsUserData::Data {
public:
static PerProcessRenderViewHostSet* GetOrCreateForProcess(
RenderProcessHost* process) {
DCHECK(process);
auto* set = static_cast<PerProcessRenderViewHostSet*>(
process->GetUserData(UserDataKey()));
if (!set) {
auto new_set = std::make_unique<PerProcessRenderViewHostSet>();
set = new_set.get();
process->SetUserData(UserDataKey(), std::move(new_set));
}
return set;
}
void Insert(const RenderViewHostImpl* rvh) {
render_view_host_instances_.insert(rvh);
}
void Erase(const RenderViewHostImpl* rvh) {
auto it = render_view_host_instances_.find(rvh);
DCHECK(it != render_view_host_instances_.end());
render_view_host_instances_.erase(it);
}
bool HasNonBackForwardCachedInstances() const {
return base::ranges::find_if_not(
render_view_host_instances_,
&RenderViewHostImpl::is_in_back_forward_cache) !=
render_view_host_instances_.end();
}
private:
static const void* UserDataKey() { return &kUserDataKey; }
static const int kUserDataKey = 0;
std::unordered_set<const RenderViewHostImpl*> render_view_host_instances_;
};
const int PerProcessRenderViewHostSet::kUserDataKey;
} // namespace
// static
const base::TimeDelta RenderViewHostImpl::kUnloadTimeout;
///////////////////////////////////////////////////////////////////////////////
// RenderViewHost, public:
// static
RenderViewHost* RenderViewHost::FromID(int render_process_id,
int render_view_id) {
return RenderViewHostImpl::FromID(render_process_id, render_view_id);
}
// static
RenderViewHost* RenderViewHost::From(RenderWidgetHost* rwh) {
return RenderViewHostImpl::From(rwh);
}
///////////////////////////////////////////////////////////////////////////////
// RenderViewHostImpl, public:
// static
RenderViewHostImpl* RenderViewHostImpl::FromID(int process_id, int routing_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RoutingIDViewMap* views = g_routing_id_view_map.Pointer();
auto it = views->find(RenderViewHostID(process_id, routing_id));
return it == views->end() ? nullptr : it->second;
}
// static
RenderViewHostImpl* RenderViewHostImpl::From(RenderWidgetHost* rwh) {
DCHECK(rwh);
RenderWidgetHostOwnerDelegate* owner_delegate =
RenderWidgetHostImpl::From(rwh)->owner_delegate();
if (!owner_delegate)
return nullptr;
RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(owner_delegate);
DCHECK_EQ(rwh, rvh->GetWidget());
return rvh;
}
// static
void RenderViewHostImpl::GetPlatformSpecificPrefs(
blink::RendererPreferences* prefs) {
#if BUILDFLAG(IS_WIN)
// Note that what is called "height" in this struct is actually the font size;
// font "height" typically includes ascender, descender, and padding and is
// often a third or so larger than the given font size.
GetFontInfo(gfx::win::SystemFont::kCaption, &prefs->caption_font_family_name,
&prefs->caption_font_height);
GetFontInfo(gfx::win::SystemFont::kSmallCaption,
&prefs->small_caption_font_family_name,
&prefs->small_caption_font_height);
GetFontInfo(gfx::win::SystemFont::kMenu, &prefs->menu_font_family_name,
&prefs->menu_font_height);
GetFontInfo(gfx::win::SystemFont::kMessage, &prefs->message_font_family_name,
&prefs->message_font_height);
GetFontInfo(gfx::win::SystemFont::kStatus, &prefs->status_font_family_name,
&prefs->status_font_height);
prefs->vertical_scroll_bar_width_in_dips =
display::win::ScreenWin::GetSystemMetricsInDIP(SM_CXVSCROLL);
prefs->horizontal_scroll_bar_height_in_dips =
display::win::ScreenWin::GetSystemMetricsInDIP(SM_CYHSCROLL);
prefs->arrow_bitmap_height_vertical_scroll_bar_in_dips =
display::win::ScreenWin::GetSystemMetricsInDIP(SM_CYVSCROLL);
prefs->arrow_bitmap_width_horizontal_scroll_bar_in_dips =
display::win::ScreenWin::GetSystemMetricsInDIP(SM_CXHSCROLL);
#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
prefs->system_font_family_name = gfx::Font().GetFontName();
#elif BUILDFLAG(IS_FUCHSIA)
// Make Blink's "focus ring" invisible. The focus ring is a hairline border
// that's rendered around clickable targets.
// TODO(crbug.com/1066605): Consider exposing this as a FIDL parameter.
prefs->focus_ring_color = SK_AlphaTRANSPARENT;
#endif
#if defined(USE_OZONE)
prefs->selection_clipboard_buffer_available =
ui::Clipboard::IsSupportedClipboardBuffer(
ui::ClipboardBuffer::kSelection);
#endif
}
// static
bool RenderViewHostImpl::HasNonBackForwardCachedInstancesForProcess(
RenderProcessHost* process) {
return PerProcessRenderViewHostSet::GetOrCreateForProcess(process)
->HasNonBackForwardCachedInstances();
}
RenderViewHostImpl::RenderViewHostImpl(
FrameTree* frame_tree,
SiteInstanceGroup* group,
const StoragePartitionConfig& storage_partition_config,
std::unique_ptr<RenderWidgetHostImpl> widget,
RenderViewHostDelegate* delegate,
int32_t routing_id,
int32_t main_frame_routing_id,
bool has_initialized_audio_host,
scoped_refptr<BrowsingContextState> main_browsing_context_state)
: render_widget_host_(std::move(widget)),
delegate_(delegate),
render_view_host_map_id_(frame_tree->GetRenderViewHostMapId(group)),
storage_partition_config_(storage_partition_config),
routing_id_(routing_id),
main_frame_routing_id_(main_frame_routing_id),
frame_tree_(frame_tree),
main_browsing_context_state_(
main_browsing_context_state
? absl::make_optional(main_browsing_context_state->GetSafeRef())
: absl::nullopt) {
TRACE_EVENT("navigation", "RenderViewHostImpl::RenderViewHostImpl",
ChromeTrackEvent::kRenderViewHost, *this);
TRACE_EVENT_BEGIN("navigation", "RenderViewHost",
perfetto::Track::FromPointer(this),
"render_view_host_when_created", this);
DCHECK(delegate_);
DCHECK_NE(GetRoutingID(), render_widget_host_->GetRoutingID());
PerProcessRenderViewHostSet::GetOrCreateForProcess(GetProcess())
->Insert(this);
std::pair<RoutingIDViewMap::iterator, bool> result =
g_routing_id_view_map.Get().emplace(
RenderViewHostID(GetProcess()->GetID(), routing_id_), this);
CHECK(result.second) << "Inserting a duplicate item!";
GetAgentSchedulingGroup().AddRoute(routing_id_, this);
GetProcess()->AddObserver(this);
ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
// New views may be created during RenderProcessHost::ProcessDied(), within a
// brief window where the internal ChannelProxy is null. This ensures that the
// ChannelProxy is re-initialized in such cases so that subsequent messages
// make their way to the new renderer once its restarted.
// TODO(crbug.com/1111231): Should this go via AgentSchedulingGroupHost? Is it
// even needed after the migration?
GetProcess()->EnableSendQueue();
if (!is_active())
GetWidget()->UpdatePriority();
close_timeout_ = std::make_unique<TimeoutMonitor>(base::BindRepeating(
&RenderViewHostImpl::ClosePageTimeout, weak_factory_.GetWeakPtr()));
input_device_change_observer_ =
std::make_unique<InputDeviceChangeObserver>(this);
bool initially_hidden = frame_tree_->delegate()->IsHidden();
page_lifecycle_state_manager_ = std::make_unique<PageLifecycleStateManager>(
this, initially_hidden ? blink::mojom::PageVisibilityState::kHidden
: blink::mojom::PageVisibilityState::kVisible);
GetWidget()->set_owner_delegate(this);
frame_tree_->RegisterRenderViewHost(render_view_host_map_id_, this);
}
RenderViewHostImpl::~RenderViewHostImpl() {
TRACE_EVENT_INSTANT("navigation", "~RenderViewHostImpl()",
ChromeTrackEvent::kRenderViewHost, *this);
// TODO(https://crbug.com/1234634): Remove this.
// If the view is destroyed while we were are still waiting for an ack,
// then log how long we have been waiting.
if (page_lifecycle_state_manager_->persisted_pageshow_timestamp_bug_1234634()
.has_value()) {
base::TimeDelta delta =
base::Time::Now() - page_lifecycle_state_manager_
->persisted_pageshow_timestamp_bug_1234634()
.value();
base::UmaHistogramMediumTimes("Event.PageShow.Persisted.ViewDestroyed.Time",
delta);
}
PerProcessRenderViewHostSet::GetOrCreateForProcess(GetProcess())->Erase(this);
// Destroy the RenderWidgetHost.
GetWidget()->ShutdownAndDestroyWidget(false);
ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
// Detach the routing ID as the object is going away.
GetAgentSchedulingGroup().RemoveRoute(GetRoutingID());
g_routing_id_view_map.Get().erase(
RenderViewHostID(GetProcess()->GetID(), GetRoutingID()));
delegate_->RenderViewDeleted(this);
GetProcess()->RemoveObserver(this);
// If |this| is in the BackForwardCache, then it was already removed from
// the FrameTree at the time it entered the BackForwardCache.
if (!is_in_back_forward_cache_)
frame_tree_->UnregisterRenderViewHost(render_view_host_map_id_, this);
// Corresponds to the TRACE_EVENT_BEGIN in RenderViewHostImpl's constructor.
TRACE_EVENT_END("navigation", perfetto::Track::FromPointer(this));
}
RenderViewHostDelegate* RenderViewHostImpl::GetDelegate() {
return delegate_;
}
bool RenderViewHostImpl::CreateRenderView(
const absl::optional<blink::FrameToken>& opener_frame_token,
int proxy_route_id,
bool window_was_opened_by_another_window) {
TRACE_EVENT0("renderer_host,navigation",
"RenderViewHostImpl::CreateRenderView");
DCHECK(!IsRenderViewLive()) << "Creating view twice";
// The process may (if we're sharing a process with another host that already
// initialized it) or may not (we have our own process or the old process
// crashed) have been initialized. Calling Init() multiple times will be
// ignored, so this is safe.
if (!GetAgentSchedulingGroup().Init())
return false;
DCHECK(GetProcess()->IsInitializedAndNotDead());
DCHECK(GetProcess()->GetBrowserContext());
// Exactly one of main_frame_routing_id_ or proxy_route_id should be set.
CHECK(!(main_frame_routing_id_ != MSG_ROUTING_NONE &&
proxy_route_id != MSG_ROUTING_NONE));
CHECK(!(main_frame_routing_id_ == MSG_ROUTING_NONE &&
proxy_route_id == MSG_ROUTING_NONE));
RenderFrameHostImpl* main_rfh = nullptr;
RenderFrameProxyHost* main_rfph = nullptr;
if (main_frame_routing_id_ != MSG_ROUTING_NONE) {
main_rfh = RenderFrameHostImpl::FromID(GetProcess()->GetID(),
main_frame_routing_id_);
DCHECK(main_rfh);
} else {
main_rfph =
RenderFrameProxyHost::FromID(GetProcess()->GetID(), proxy_route_id);
DCHECK(main_rfph);
}
const FrameTreeNode* const frame_tree_node =
main_rfh ? main_rfh->frame_tree_node() : main_rfph->frame_tree_node();
mojom::CreateViewParamsPtr params = mojom::CreateViewParams::New();
params->renderer_preferences = delegate_->GetRendererPrefs();
RenderViewHostImpl::GetPlatformSpecificPrefs(&params->renderer_preferences);
params->web_preferences = delegate_->GetOrCreateWebPreferences();
params->opener_frame_token = opener_frame_token;
params->replication_state =
frame_tree_node->current_replication_state().Clone();
params->devtools_main_frame_token = frame_tree_node->devtools_frame_token();
DCHECK_EQ(frame_tree_node->frame_tree(), frame_tree_);
params->is_prerendering = frame_tree_->is_prerendering();
if (main_rfh) {
auto local_frame_params = mojom::CreateLocalMainFrameParams::New();
local_frame_params->token = main_rfh->GetFrameToken();
local_frame_params->routing_id = main_frame_routing_id_;
mojo::PendingAssociatedRemote<mojom::Frame> pending_frame_remote;
local_frame_params->frame =
pending_frame_remote.InitWithNewEndpointAndPassReceiver();
main_rfh->SetMojomFrameRemote(std::move(pending_frame_remote));
main_rfh->BindBrowserInterfaceBrokerReceiver(
local_frame_params->interface_broker.InitWithNewPipeAndPassReceiver());
main_rfh->BindAssociatedInterfaceProviderReceiver(
local_frame_params->associated_interface_provider_remote
.InitWithNewEndpointAndPassReceiver());
local_frame_params->is_on_initial_empty_document =
main_rfh->frame_tree_node()->is_on_initial_empty_document();
// If this is a new RenderFrameHost for a frame that has already committed a
// document, we don't have a PolicyContainerHost yet. Indeed, in that case,
// this RenderFrameHost will not display any document until it commits a
// navigation. The policy container for the navigated document will be sent
// to Blink at CommitNavigation time and then stored in this RenderFrameHost
// in DidCommitNewDocument.
if (main_rfh->policy_container_host()) {
local_frame_params->policy_container =
main_rfh->policy_container_host()->CreatePolicyContainerForBlink();
}
local_frame_params->widget_params =
main_rfh->GetRenderWidgetHost()
->BindAndGenerateCreateFrameWidgetParams();
local_frame_params->subresource_loader_factories =
main_rfh->CreateSubresourceLoaderFactoriesForInitialEmptyDocument();
params->main_frame = mojom::CreateMainFrameUnion::NewLocalParams(
std::move(local_frame_params));
} else {
params->main_frame = mojom::CreateMainFrameUnion::NewRemoteParams(
mojom::CreateRemoteMainFrameParams::New(
main_rfph->GetFrameToken(),
main_rfph->CreateAndBindRemoteFrameInterfaces(),
main_rfph->CreateAndBindRemoteMainFrameInterfaces()));
}
params->session_storage_namespace_id =
frame_tree_->controller()
.GetSessionStorageNamespace(storage_partition_config_)
->id();
params->hidden = frame_tree_->delegate()->IsHidden();
params->never_composited = delegate_->IsNeverComposited();
params->window_was_opened_by_another_window =
window_was_opened_by_another_window;
params->base_background_color = delegate_->GetBaseBackgroundColor();
bool is_portal = frame_tree_->delegate()->IsPortal();
bool is_guest_view = delegate_->IsGuest();
bool is_fenced_frame = frame_tree_->type() == FrameTree::Type::kFencedFrame;
if (is_fenced_frame) {
params->type = mojom::ViewWidgetType::kFencedFrame;
params->fenced_frame_mode =
frame_tree_->root()->GetFencedFrameMode().value();
} else if (is_portal) {
DCHECK(!is_guest_view);
params->type = mojom::ViewWidgetType::kPortal;
} else if (is_guest_view) {
params->type = mojom::ViewWidgetType::kGuestView;
} else {
params->type = mojom::ViewWidgetType::kTopLevel;
}
// RenderViewHostImpl is reused after a crash, so reset any endpoint that
// might be a leftover from a crash.
page_broadcast_.reset();
params->blink_page_broadcast =
page_broadcast_.BindNewEndpointAndPassReceiver();
// The renderer process's `blink::WebView` is owned by this lifecycle of
// the `page_broadcast_` channel.
GetAgentSchedulingGroup().CreateView(std::move(params));
// Set the bit saying we've made the `blink::WebView` in the renderer and
// notify content public observers.
RenderViewCreated(main_rfh);
// This must be posted after the RenderViewHost is marked live, with
// `renderer_view_created_`.
PostRenderViewReady();
return true;
}
void RenderViewHostImpl::SetMainFrameRoutingId(int routing_id) {
main_frame_routing_id_ = routing_id;
GetWidget()->UpdatePriority();
// TODO(crbug.com/419087): If a local main frame is no longer attached to this
// `blink::WebView` then the RenderWidgetHostImpl owned by this class should
// be informed that its renderer widget is no longer created. The
// RenderViewHost will need to track its own live-ness then.
}
void RenderViewHostImpl::SetFrameTree(FrameTree& frame_tree) {
TRACE_EVENT("navigation", "RenderViewHostImpl::SetFrameTree",
ChromeTrackEvent::kRenderViewHost, *this);
frame_tree_->UnregisterRenderViewHost(render_view_host_map_id_, this);
frame_tree_ = &frame_tree;
frame_tree_->RegisterRenderViewHost(render_view_host_map_id_, this);
}
void RenderViewHostImpl::EnterBackForwardCache() {
if (!will_enter_back_forward_cache_callback_for_testing_.is_null())
will_enter_back_forward_cache_callback_for_testing_.Run();
TRACE_EVENT("navigation", "RenderViewHostImpl::EnterBackForwardCache",
ChromeTrackEvent::kRenderViewHost, *this);
frame_tree_->UnregisterRenderViewHost(render_view_host_map_id_, this);
is_in_back_forward_cache_ = true;
page_lifecycle_state_manager_->SetIsInBackForwardCache(
is_in_back_forward_cache_, /*page_restore_params=*/nullptr,
/*restoring_main_frame_from_back_forward_cache=*/false);
}
void RenderViewHostImpl::PrepareToLeaveBackForwardCache(
base::OnceClosure done_cb) {
page_lifecycle_state_manager_->SetIsLeavingBackForwardCache(
std::move(done_cb));
}
void RenderViewHostImpl::LeaveBackForwardCache(
blink::mojom::PageRestoreParamsPtr page_restore_params,
bool restoring_main_frame_from_back_forward_cache) {
TRACE_EVENT("navigation", "RenderViewHostImpl::LeaveBackForwardCache",
ChromeTrackEvent::kRenderViewHost, *this);
// At this point, the frames |this| RenderViewHostImpl belongs to are
// guaranteed to be committed, so it should be reused going forward.
frame_tree_->RegisterRenderViewHost(render_view_host_map_id_, this);
is_in_back_forward_cache_ = false;
page_lifecycle_state_manager_->SetIsInBackForwardCache(
is_in_back_forward_cache_, std::move(page_restore_params),
restoring_main_frame_from_back_forward_cache);
}
void RenderViewHostImpl::ActivatePrerenderedPage(
blink::mojom::PrerenderPageActivationParamsPtr
prerender_page_activation_params,
base::OnceClosure callback) {
// TODO(https://crbug.com/1217977): Consider using a ScopedClosureRunner here
// in case the renderer crashes before it can send us the callback. But we
// can't do that until the linked bug is fixed, or else we can reach
// DidActivateForPrerendering() outside of a Mojo message dispatch which
// breaks the DCHECK for releasing Mojo Capability Control.
page_broadcast_->ActivatePrerenderedPage(
std::move(prerender_page_activation_params), std::move(callback));
}
void RenderViewHostImpl::SetFrameTreeVisibility(
blink::mojom::PageVisibilityState visibility) {
page_lifecycle_state_manager_->SetFrameTreeVisibility(visibility);
}
void RenderViewHostImpl::SetIsFrozen(bool frozen) {
page_lifecycle_state_manager_->SetIsFrozen(frozen);
}
void RenderViewHostImpl::OnBackForwardCacheTimeout() {
// TODO(yuzus): Implement a method to get a list of RenderFrameHosts
// associated with |this|, instead of iterating through all the
// RenderFrameHosts in bfcache.
const auto& entries =
frame_tree_->controller().GetBackForwardCache().GetEntries();
for (auto& entry : entries) {
for (auto* const rvh : entry->render_view_hosts()) {
if (rvh == this) {
RenderFrameHostImpl* rfh = entry->render_frame_host();
rfh->EvictFromBackForwardCacheWithReason(
BackForwardCacheMetrics::NotRestoredReason::kTimeoutPuttingInCache);
break;
}
}
}
}
void RenderViewHostImpl::MaybeEvictFromBackForwardCache() {
// TODO(yuzus): Implement a method to get a list of RenderFrameHosts
// associated with |this|, instead of iterating through all the
// RenderFrameHosts in bfcache.
const auto& entries =
frame_tree_->controller().GetBackForwardCache().GetEntries();
for (auto& entry : entries) {
for (auto* const rvh : entry->render_view_hosts()) {
if (rvh == this) {
RenderFrameHostImpl* rfh = entry->render_frame_host();
rfh->MaybeEvictFromBackForwardCache();
break;
}
}
}
}
void RenderViewHostImpl::EnforceBackForwardCacheSizeLimit() {
frame_tree_->controller().GetBackForwardCache().EnforceCacheSizeLimit();
}
bool RenderViewHostImpl::DidReceiveBackForwardCacheAck() {
return GetPageLifecycleStateManager()->DidReceiveBackForwardCacheAck();
}
bool RenderViewHostImpl::IsRenderViewLive() const {
return GetProcess()->IsInitializedAndNotDead() && renderer_view_created_;
}
void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) {
GetWidget()->GetAssociatedFrameWidget()->SetBackgroundOpaque(opaque);
}
bool RenderViewHostImpl::IsMainFrameActive() {
return is_active();
}
bool RenderViewHostImpl::IsNeverComposited() {
return GetDelegate()->IsNeverComposited();
}
blink::web_pref::WebPreferences
RenderViewHostImpl::GetWebkitPreferencesForWidget() {
if (!delegate_)
return blink::web_pref::WebPreferences();
return delegate_->GetOrCreateWebPreferences();
}
void RenderViewHostImpl::RenderViewCreated(
RenderFrameHostImpl* local_main_frame) {
renderer_view_created_ = true;
if (local_main_frame) {
// If there is a main frame in this RenderViewHost, then the renderer-side
// main frame will be created along with the `blink::WebView`. The
// RenderFrameHost initializes its RenderWidgetHost as well, if it exists.
local_main_frame->RenderFrameCreated();
}
}
RenderFrameHostImpl* RenderViewHostImpl::GetMainRenderFrameHost() {
// If the RenderViewHost is active, it should always have a main frame
// RenderFrameHostImpl. If it is inactive, it could've been created for a
// speculative main frame navigation, in which case it will transition to
// active once that navigation commits. In this case, return the speculative
// main frame RenderFrameHostImpl, as that's expected by certain code paths,
// such as RenderViewHostImpl::SetUIProperty(). If there's no speculative
// main frame navigation, return nullptr.
//
// TODO(alexmos, creis): Migrate these code paths to use RenderFrameHost APIs
// and remove this fallback. See https://crbug.com/763548.
if (is_active()) {
return RenderFrameHostImpl::FromID(GetProcess()->GetID(),
main_frame_routing_id_);
}
return frame_tree_->root()->render_manager()->speculative_frame_host();
}
void RenderViewHostImpl::ClosePage() {
is_waiting_for_page_close_completion_ = true;
DCHECK(GetMainRenderFrameHost()->IsOutermostMainFrame());
if (IsRenderViewLive() && !SuddenTerminationAllowed()) {
close_timeout_->Start(kUnloadTimeout);
// TODO(creis): Should this be moved to Shutdown? It may not be called for
// RenderViewHosts that have been swapped out.
#if !BUILDFLAG(IS_ANDROID)
static_cast<HostZoomMapImpl*>(
HostZoomMap::Get(GetMainRenderFrameHost()->GetSiteInstance()))
->WillCloseRenderView(GetProcess()->GetID(), GetRoutingID());
#endif
GetMainRenderFrameHost()->GetAssociatedLocalMainFrame()->ClosePage(
base::BindOnce(&RenderViewHostImpl::OnPageClosed,
weak_factory_.GetWeakPtr()));
} else {
// This RenderViewHost doesn't have a live renderer, so just skip the close
// event and close the page.
ClosePageIgnoringUnloadEvents();
}
}
void RenderViewHostImpl::ClosePageIgnoringUnloadEvents() {
close_timeout_->Stop();
is_waiting_for_page_close_completion_ = false;
sudden_termination_allowed_ = true;
delegate_->Close(this);
}
void RenderViewHostImpl::ZoomToFindInPageRect(const gfx::Rect& rect_to_zoom) {
GetMainRenderFrameHost()->GetAssociatedLocalMainFrame()->ZoomToFindInPageRect(
rect_to_zoom);
}
void RenderViewHostImpl::RenderProcessExited(
RenderProcessHost* host,
const ChildProcessTerminationInfo& info) {
// TODO(https://crbug.com/1234634): Remove this.
// If the renderer has exited while we were are still waiting for a ack,
// then log information about the exit.
if (page_lifecycle_state_manager_->persisted_pageshow_timestamp_bug_1234634()
.has_value()) {
base::TimeDelta delta =
base::Time::Now() - page_lifecycle_state_manager_
->persisted_pageshow_timestamp_bug_1234634()
.value();
// We want to understand if we are losing pageshows because renderers are
// exiting soon after restoring from BFCache. We keep the normal exits
// separate from the unexpected.
const char* histogram =
info.status == base::TERMINATION_STATUS_NORMAL_TERMINATION
? "Event.PageShow.Persisted.Termination.Normal.Time"
: "Event.PageShow.Persisted.Termination.Unexpected.Time";
base::UmaHistogramMediumTimes(histogram, delta);
// We don't record this as an enum because the enum is platform dependent.
// Since this is temporary debugging, 20 seems a safe upper limit for the
// number of elements.
base::UmaHistogramExactLinear("Event.PageShow.Persisted.Termination.Status",
static_cast<int>(info.status), 20);
}
renderer_view_created_ = false;
GetWidget()->RendererExited();
delegate_->RenderViewTerminated(this, info.status, info.exit_code);
// |this| might have been deleted. Do not add code here.
}
RenderWidgetHostImpl* RenderViewHostImpl::GetWidget() const {
return render_widget_host_.get();
}
AgentSchedulingGroupHost& RenderViewHostImpl::GetAgentSchedulingGroup() const {
return render_widget_host_->agent_scheduling_group();
}
RenderProcessHost* RenderViewHostImpl::GetProcess() const {
return GetAgentSchedulingGroup().GetProcess();
}
int RenderViewHostImpl::GetRoutingID() const {
return routing_id_;
}
void RenderViewHostImpl::RenderWidgetGotFocus() {
RenderViewHostDelegateView* view = delegate_->GetDelegateView();
if (view)
view->GotFocus(GetWidget());
}
void RenderViewHostImpl::RenderWidgetLostFocus() {
RenderViewHostDelegateView* view = delegate_->GetDelegateView();
if (view)
view->LostFocus(GetWidget());
}
void RenderViewHostImpl::SetInitialFocus(bool reverse) {
GetMainRenderFrameHost()->GetAssociatedLocalMainFrame()->SetInitialFocus(
reverse);
}
void RenderViewHostImpl::AnimateDoubleTapZoom(const gfx::Point& point,
const gfx::Rect& rect) {
GetMainRenderFrameHost()->GetAssociatedLocalMainFrame()->AnimateDoubleTapZoom(
point, rect);
}
bool RenderViewHostImpl::SuddenTerminationAllowed() {
// If there is a JavaScript dialog up, don't bother sending the renderer the
// close event because it is known unresponsive, waiting for the reply from
// the dialog.
return sudden_termination_allowed_ ||
delegate_->IsJavaScriptDialogShowing() ||
GetMainRenderFrameHost()->BeforeUnloadTimedOut();
}
///////////////////////////////////////////////////////////////////////////////
// RenderViewHostImpl, IPC message handlers:
bool RenderViewHostImpl::OnMessageReceived(const IPC::Message& msg) {
return false;
}
std::string RenderViewHostImpl::ToDebugString() {
return "RVHI:" + delegate_->GetCreatorLocation().ToString();
}
void RenderViewHostImpl::OnTakeFocus(bool reverse) {
RenderViewHostDelegateView* view = delegate_->GetDelegateView();
if (view)
view->TakeFocus(reverse);
}
void RenderViewHostImpl::OnPageClosed() {
ClosePageIgnoringUnloadEvents();
}
void RenderViewHostImpl::OnFocus() {
// Note: We allow focus and blur from swapped out RenderViewHosts, even when
// the active RenderViewHost is in a different BrowsingInstance (e.g., WebUI).
delegate_->Activate();
}
void RenderViewHostImpl::BindPageBroadcast(
mojo::PendingAssociatedRemote<blink::mojom::PageBroadcast> page_broadcast) {
page_broadcast_.reset();
page_broadcast_.Bind(std::move(page_broadcast));
}
const mojo::AssociatedRemote<blink::mojom::PageBroadcast>&
RenderViewHostImpl::GetAssociatedPageBroadcast() {
return page_broadcast_;
}
void RenderViewHostImpl::RenderWidgetDidForwardMouseEvent(
const blink::WebMouseEvent& mouse_event) {
if (mouse_event.GetType() == WebInputEvent::Type::kMouseWheel &&
GetWidget()->IsIgnoringInputEvents()) {
delegate_->OnIgnoredUIEvent();
}
}
bool RenderViewHostImpl::MayRenderWidgetForwardKeyboardEvent(
const NativeWebKeyboardEvent& key_event) {
if (GetWidget()->IsIgnoringInputEvents()) {
if (key_event.GetType() == WebInputEvent::Type::kRawKeyDown)
delegate_->OnIgnoredUIEvent();
return false;
}
return true;
}
bool RenderViewHostImpl::ShouldContributePriorityToProcess() {
return is_active();
}
void RenderViewHostImpl::SendWebPreferencesToRenderer() {
if (auto& broadcast = GetAssociatedPageBroadcast())
broadcast->UpdateWebPreferences(delegate_->GetOrCreateWebPreferences());
}
void RenderViewHostImpl::SendRendererPreferencesToRenderer(
const blink::RendererPreferences& preferences) {
if (auto& broadcast = GetAssociatedPageBroadcast()) {
if (!will_send_renderer_preferences_callback_for_testing_.is_null())
will_send_renderer_preferences_callback_for_testing_.Run(preferences);
broadcast->UpdateRendererPreferences(preferences);
}
}
void RenderViewHostImpl::OnHardwareConfigurationChanged() {
delegate_->RecomputeWebPreferencesSlow();
}
void RenderViewHostImpl::EnablePreferredSizeMode() {
if (is_active()) {
GetMainRenderFrameHost()
->GetAssociatedLocalMainFrame()
->EnablePreferredSizeChangedMode();
}
}
void RenderViewHostImpl::PostRenderViewReady() {
GetProcess()->PostTaskWhenProcessIsReady(base::BindOnce(
&RenderViewHostImpl::RenderViewReady, weak_factory_.GetWeakPtr()));
}
void RenderViewHostImpl::OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {
OnHardwareConfigurationChanged();
}
void RenderViewHostImpl::RenderViewReady() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
delegate_->RenderViewReady(this);
}
void RenderViewHostImpl::ClosePageTimeout() {
if (delegate_->ShouldIgnoreUnresponsiveRenderer())
return;
ClosePageIgnoringUnloadEvents();
}
std::vector<viz::SurfaceId> RenderViewHostImpl::CollectSurfaceIdsForEviction() {
if (!is_active())
return {};
RenderFrameHostImpl* rfh = GetMainRenderFrameHost();
if (!rfh || !rfh->IsActive())
return {};
FrameTreeNode* root = rfh->frame_tree_node();
FrameTree* tree = root->frame_tree();
std::vector<viz::SurfaceId> ids;
for (FrameTreeNode* node : tree->SubtreeNodes(root)) {
if (!node->current_frame_host()->is_local_root())
continue;
RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
node->current_frame_host()->GetView());
if (!view)
continue;
viz::SurfaceId id = view->GetCurrentSurfaceId();
if (id.is_valid())
ids.push_back(id);
view->set_is_evicted();
}
return ids;
}
bool RenderViewHostImpl::IsTestRenderViewHost() const {
return false;
}
void RenderViewHostImpl::SetWillEnterBackForwardCacheCallbackForTesting(
const WillEnterBackForwardCacheCallbackForTesting& callback) {
will_enter_back_forward_cache_callback_for_testing_ = callback;
}
void RenderViewHostImpl::SetWillSendRendererPreferencesCallbackForTesting(
const WillSendRendererPreferencesCallbackForTesting& callback) {
will_send_renderer_preferences_callback_for_testing_ = callback;
}
void RenderViewHostImpl::WriteIntoTrace(
perfetto::TracedProto<TraceProto> proto) const {
proto->set_rvh_map_id(render_view_host_map_id_.value());
proto->set_routing_id(GetRoutingID());
proto.Set(TraceProto::kProcess, GetProcess());
proto->set_is_in_back_forward_cache(is_in_back_forward_cache_);
proto->set_renderer_view_created(renderer_view_created_);
}
} // namespace content