blob: 2784ede8d6d7f809faff48fbc3777698555698ff [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// 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_widget_host_view_base.h"
#include <optional>
#include "base/check.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/notimplemented.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
#include "components/input/event_with_latency_info.h"
#include "components/input/render_widget_host_input_event_router.h"
#include "components/input/render_widget_host_view_input_observer.h"
#include "components/viz/common/features.h"
#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/device_posture/device_posture_provider_impl.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/renderer_host/delegated_frame_host.h"
#include "content/browser/renderer_host/frame_tree.h"
#include "content/browser/renderer_host/input/mouse_wheel_phase_handler.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target_base.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_owner_delegate.h"
#include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
#include "content/browser/renderer_host/scoped_view_transition_resources.h"
#include "content/browser/renderer_host/text_input_manager.h"
#include "content/browser/renderer_host/visible_time_request_trigger.h"
#include "content/common/content_switches_internal.h"
#include "content/public/common/page_visibility_state.h"
#include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom.h"
#include "ui/base/ui_base_types.h"
#include "ui/display/display_util.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/size_f.h"
#if BUILDFLAG(IS_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#endif
namespace content {
RenderWidgetHostViewBase::RenderWidgetHostViewBase(RenderWidgetHost* host)
: host_(RenderWidgetHostImpl::From(host)),
// `screen_infos_` must be initialized, to permit unconditional access to
// its current display. A placeholder ScreenInfo is used here, so the
// first call to UpdateScreenInfo will trigger the expected updates.
screen_infos_(display::ScreenInfos(display::ScreenInfo())) {}
RenderWidgetHostViewBase::~RenderWidgetHostViewBase() {
CHECK(!keyboard_locked_);
CHECK(!IsPointerLocked());
// We call this here to guarantee that observers are notified before we go
// away. However, some subclasses may wish to call this earlier in their
// shutdown process, e.g. to force removal from
// RenderWidgetHostInputEventRouter's surface map before relinquishing a
// host pointer. There is no harm in calling NotifyObserversAboutShutdown()
// twice, as the observers are required to de-register on the first call, and
// so the second call does nothing.
NotifyObserversAboutShutdown();
// If we have a live reference to |text_input_manager_|, we should unregister
// so that the |text_input_manager_| will free its state.
if (text_input_manager_)
text_input_manager_->Unregister(this);
}
RenderWidgetHostImpl* RenderWidgetHostViewBase::GetFocusedWidget() const {
return host() && host()->delegate()
? host()->delegate()->GetFocusedRenderWidgetHost(host())
: nullptr;
}
RenderWidgetHost* RenderWidgetHostViewBase::GetRenderWidgetHost() {
return host();
}
void RenderWidgetHostViewBase::SetContentBackgroundColor(SkColor color) {
if (content_background_color_ == color)
return;
content_background_color_ = color;
UpdateBackgroundColor();
}
MouseWheelPhaseHandler* RenderWidgetHostViewBase::GetMouseWheelPhaseHandler() {
return nullptr;
}
void RenderWidgetHostViewBase::UpdateIntrinsicSizingInfo(
blink::mojom::IntrinsicSizingInfoPtr sizing_info) {}
gfx::Size RenderWidgetHostViewBase::GetCompositorViewportPixelSize() {
return gfx::ScaleToCeiledSize(GetRequestedRendererSize(),
GetDeviceScaleFactor());
}
void RenderWidgetHostViewBase::SelectionBoundsChanged(
const gfx::Rect& anchor_rect,
base::i18n::TextDirection anchor_dir,
const gfx::Rect& focus_rect,
base::i18n::TextDirection focus_dir,
const gfx::Rect& bounding_box,
bool is_anchor_first) {
#if !BUILDFLAG(IS_ANDROID)
if (GetTextInputManager())
GetTextInputManager()->SelectionBoundsChanged(
this, anchor_rect, anchor_dir, focus_rect, focus_dir, bounding_box,
is_anchor_first);
#else
NOTREACHED() << "Selection bounds should be routed through the compositor.";
#endif
}
RenderWidgetHostViewBase* RenderWidgetHostViewBase::GetRootView() {
return this;
}
void RenderWidgetHostViewBase::SelectionChanged(const std::u16string& text,
size_t offset,
const gfx::Range& range) {
if (GetTextInputManager())
GetTextInputManager()->SelectionChanged(this, text, offset, range);
}
gfx::Size RenderWidgetHostViewBase::GetRequestedRendererSize() {
return GetViewBounds().size();
}
gfx::Size RenderWidgetHostViewBase::GetRequestedRendererSizeDevicePx() {
return gfx::ScaleToCeiledSize(GetRequestedRendererSize(),
GetDeviceScaleFactor());
}
uint32_t RenderWidgetHostViewBase::GetCaptureSequenceNumber() const {
// TODO(vmpstr): Implement this for overrides other than aura and child frame.
NOTIMPLEMENTED_LOG_ONCE();
return 0u;
}
ui::TextInputClient* RenderWidgetHostViewBase::GetTextInputClient() {
return nullptr;
}
bool RenderWidgetHostViewBase::IsSurfaceAvailableForCopy() {
return false;
}
void RenderWidgetHostViewBase::CopyMainAndPopupFromSurface(
base::WeakPtr<RenderWidgetHostImpl> main_host,
base::WeakPtr<DelegatedFrameHost> main_frame_host,
base::WeakPtr<RenderWidgetHostImpl> popup_host,
base::WeakPtr<DelegatedFrameHost> popup_frame_host,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
float scale_factor,
base::OnceCallback<void(const SkBitmap&)> callback) {
if (!main_host || !main_frame_host)
return;
#if BUILDFLAG(IS_ANDROID)
NOTREACHED()
<< "RenderWidgetHostViewAndroid::CopyFromSurface calls "
"DelegatedFrameHostAndroid::CopyFromCompositingSurface directly, "
"and popups are not supported.";
#else
if (!popup_host || !popup_frame_host) {
// No popup - just call CopyFromCompositingSurface once.
main_frame_host->CopyFromCompositingSurface(src_subrect, dst_size,
std::move(callback));
return;
}
// First locate the popup relative to the main page, in DIPs
const gfx::Point parent_location =
main_host->GetView()->GetBoundsInRootWindow().origin();
const gfx::Point popup_location =
popup_host->GetView()->GetBoundsInRootWindow().origin();
const gfx::Point offset_dips =
PointAtOffsetFromOrigin(popup_location - parent_location);
const gfx::Vector2d offset_physical =
ScaleToFlooredPoint(offset_dips, scale_factor).OffsetFromOrigin();
// Queue up the request for the MAIN frame image first, but with a
// callback that launches a second request for the popup image.
// 1. Call CopyFromCompositingSurface for the main frame, with callback
// |main_image_done_callback|. Inside |main_image_done_callback|:
// a. Call CopyFromCompositingSurface again, this time on the popup
// frame. For this call, build a new callback, |popup_done_callback|,
// which:
// i. Takes the main image as a parameter, combines the main image with
// the just-acquired popup image, and then calls the original
// (outer) callback with the combined image.
auto main_image_done_callback = base::BindOnce(
[](base::OnceCallback<void(const SkBitmap&)> final_callback,
const gfx::Vector2d offset,
base::WeakPtr<DelegatedFrameHost> popup_frame_host,
const gfx::Rect src_subrect, const gfx::Size dst_size,
const SkBitmap& main_image) {
if (!popup_frame_host)
return;
// Build a new callback that actually combines images.
auto popup_done_callback = base::BindOnce(
[](base::OnceCallback<void(const SkBitmap&)> final_callback,
const gfx::Vector2d offset, const SkBitmap& main_image,
const SkBitmap& popup_image) {
// Draw popup_image into main_image.
SkCanvas canvas(main_image, SkSurfaceProps{});
canvas.drawImage(popup_image.asImage(), offset.x(), offset.y());
std::move(final_callback).Run(main_image);
},
std::move(final_callback), offset, std::move(main_image));
// Second, request the popup image.
gfx::Rect popup_subrect(src_subrect - offset);
popup_frame_host->CopyFromCompositingSurface(
popup_subrect, dst_size, std::move(popup_done_callback));
},
std::move(callback), offset_physical, popup_frame_host, src_subrect,
dst_size);
// Request the main image (happens first).
main_frame_host->CopyFromCompositingSurface(
src_subrect, dst_size, std::move(main_image_done_callback));
#endif
}
void RenderWidgetHostViewBase::CopyFromSurface(
const gfx::Rect& src_rect,
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback) {
NOTIMPLEMENTED_LOG_ONCE();
std::move(callback).Run(SkBitmap());
}
void RenderWidgetHostViewBase::CopyFromExactSurface(
const gfx::Rect& src_rect,
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback) {
NOTIMPLEMENTED_LOG_ONCE();
std::move(callback).Run(SkBitmap());
}
#if BUILDFLAG(IS_ANDROID)
void RenderWidgetHostViewBase::CopyFromExactSurfaceWithIpcDelay(
const gfx::Rect& src_rect,
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback,
base::TimeDelta ipc_delay) {
NOTIMPLEMENTED_LOG_ONCE();
std::move(callback).Run(SkBitmap());
}
#endif
std::unique_ptr<viz::ClientFrameSinkVideoCapturer>
RenderWidgetHostViewBase::CreateVideoCapturer() {
std::unique_ptr<viz::ClientFrameSinkVideoCapturer> video_capturer =
GetHostFrameSinkManager()->CreateVideoCapturer();
video_capturer->ChangeTarget(viz::VideoCaptureTarget(GetFrameSinkId()),
/*sub_capture_target_version=*/0);
return video_capturer;
}
std::u16string RenderWidgetHostViewBase::GetSelectedText() {
if (!GetTextInputManager())
return std::u16string();
return GetTextInputManager()->GetTextSelection(this)->selected_text();
}
void RenderWidgetHostViewBase::SetBackgroundColor(SkColor color) {
// TODO(danakj): OPAQUE colors only make sense for main frame widgets,
// as child frames are always transparent background. We should move this to
// `blink::WebView` instead.
CHECK(SkColorGetA(color) == SK_AlphaOPAQUE ||
SkColorGetA(color) == SK_AlphaTRANSPARENT);
if (default_background_color_ == color)
return;
bool opaque = default_background_color_
? SkColorGetA(*default_background_color_)
: SK_AlphaOPAQUE;
default_background_color_ = color;
UpdateBackgroundColor();
if (opaque != (SkColorGetA(color) == SK_AlphaOPAQUE)) {
if (host()->owner_delegate()) {
host()->owner_delegate()->SetBackgroundOpaque(SkColorGetA(color) ==
SK_AlphaOPAQUE);
}
}
}
std::optional<SkColor> RenderWidgetHostViewBase::GetBackgroundColor() {
if (content_background_color_)
return content_background_color_;
return default_background_color_;
}
bool RenderWidgetHostViewBase::IsBackgroundColorOpaque() {
std::optional<SkColor> bg_color = GetBackgroundColor();
return bg_color ? SkColorGetA(*bg_color) == SK_AlphaOPAQUE : true;
}
void RenderWidgetHostViewBase::CopyBackgroundColorIfPresentFrom(
const RenderWidgetHostView& other) {
const RenderWidgetHostViewBase& other_base =
static_cast<const RenderWidgetHostViewBase&>(other);
if (!other_base.content_background_color_ &&
!other_base.default_background_color_) {
return;
}
if (content_background_color_ == other_base.content_background_color_ &&
default_background_color_ == other_base.default_background_color_) {
return;
}
bool was_opaque = IsBackgroundColorOpaque();
content_background_color_ = other_base.content_background_color_;
default_background_color_ = other_base.default_background_color_;
UpdateBackgroundColor();
bool opaque = IsBackgroundColorOpaque();
if (was_opaque != opaque && host()->owner_delegate()) {
host()->owner_delegate()->SetBackgroundOpaque(opaque);
}
}
bool RenderWidgetHostViewBase::IsPointerLocked() {
return false;
}
const viz::DisplayHitTestQueryMap&
RenderWidgetHostViewBase::GetDisplayHitTestQuery() const {
return GetHostFrameSinkManager()->GetDisplayHitTestQuery();
}
bool RenderWidgetHostViewBase::
GetIsPointerLockedUnadjustedMovementForTesting() {
return false;
}
bool RenderWidgetHostViewBase::CanBePointerLocked() {
return HasFocus();
}
bool RenderWidgetHostViewBase::AccessibilityHasFocus() {
return HasFocus();
}
bool RenderWidgetHostViewBase::LockKeyboard(
std::optional<base::flat_set<ui::DomCode>> codes) {
NOTIMPLEMENTED_LOG_ONCE();
return false;
}
void RenderWidgetHostViewBase::UnlockKeyboard() {
NOTIMPLEMENTED_LOG_ONCE();
}
bool RenderWidgetHostViewBase::IsKeyboardLocked() {
return keyboard_locked_;
}
base::flat_map<std::string, std::string>
RenderWidgetHostViewBase::GetKeyboardLayoutMap() {
NOTIMPLEMENTED_LOG_ONCE();
return base::flat_map<std::string, std::string>();
}
bool RenderWidgetHostViewBase::HasFallbackSurface() const {
NOTREACHED();
}
viz::SurfaceId RenderWidgetHostViewBase::GetFallbackSurfaceIdForTesting()
const {
NOTREACHED();
}
void RenderWidgetHostViewBase::SetWidgetType(WidgetType widget_type) {
widget_type_ = widget_type;
}
WidgetType RenderWidgetHostViewBase::GetWidgetType() {
return widget_type_;
}
gfx::AcceleratedWidget
RenderWidgetHostViewBase::AccessibilityGetAcceleratedWidget() {
return gfx::kNullAcceleratedWidget;
}
gfx::NativeViewAccessible
RenderWidgetHostViewBase::AccessibilityGetNativeViewAccessible() {
return gfx::NativeViewAccessible();
}
gfx::NativeViewAccessible
RenderWidgetHostViewBase::AccessibilityGetNativeViewAccessibleForWindow() {
return gfx::NativeViewAccessible();
}
bool RenderWidgetHostViewBase::ShouldInitiateStylusWriting() {
return false;
}
bool RenderWidgetHostViewBase::RequestRepaintOnNewSurface() {
return false;
}
// Send system cursor size to the renderer via UpdateScreenInfo().
void RenderWidgetHostViewBase::UpdateSystemCursorSize(
const gfx::Size& cursor_size) {
system_cursor_size_ = cursor_size;
UpdateScreenInfo();
}
void RenderWidgetHostViewBase::UpdateScreenInfo() {
bool force_sync_visual_properties = false;
// Delegate, which is usually WebContentsImpl, do not send rect updates for
// popups as they are not registered as FrameTreeNodes. Instead, send screen
// rects directly to host and force synchronization of visual properties so
// that blink knows host changed bounds. This only happens if the change was
// instantiated by system server/compositor (for example, Wayland, which
// may reposition a popup if part of it is going to be shown outside a
// display's work area. Note that Wayland clients cannot know where their
// windows are located and cannot adjust bounds).
if (widget_type_ == WidgetType::kPopup) {
if (host()) {
force_sync_visual_properties = true;
host()->SendScreenRects();
}
} else {
if (host() && host()->delegate())
host()->delegate()->SendScreenRects();
}
auto new_screen_infos = GetNewScreenInfosForUpdate();
if (scale_override_for_capture_ != 1.0f) {
// If HiDPI capture mode is active, adjust the device scale factor to
// increase the rendered pixel count. |new_screen_infos| always contains the
// unmodified original values for the display, and a copy of it is saved in
// |screen_infos_|, with a modification applied if applicable. When HiDPI
// mode is turned off (the scale override is 1.0), the original
// |new_screen_infos| value gets copied unchanged to |screen_infos_|.
const float old_device_scale_factor =
new_screen_infos.current().device_scale_factor;
new_screen_infos.mutable_current().device_scale_factor =
old_device_scale_factor * scale_override_for_capture_;
DVLOG(1) << __func__ << ": Overriding device_scale_factor from "
<< old_device_scale_factor << " to "
<< new_screen_infos.current().device_scale_factor
<< " for capture.";
}
#if BUILDFLAG(IS_OZONE)
// There are platforms where no global screen coordinates are available for
// client applications, and scaling is done in a per-window basis (rather than
// per-display) and controlled by the display server. In such cases, the
// ScreenInfo Web API is mostly pointless. To avoid distorted graphics in web
// contents, override the display scale with the preferred window scale here.
// TODO(crbug.com/336007385): Consolidate screen representation and a less
// hacky scale handling in platforms that support per-window scaling.
if (ui::OzonePlatform::GetInstance()
->GetPlatformRuntimeProperties()
.supports_per_window_scaling) {
const float window_scale =
display::Screen::GetScreen()
->GetPreferredScaleFactorForView(GetNativeView())
.value_or(1.0f);
auto& screen = new_screen_infos.mutable_current();
const float old = screen.device_scale_factor;
if (window_scale != old) {
VLOG(1) << __func__ << ": Overriding scale for screen '" << screen.label
<< "' from " << old << " with windows scale " << window_scale;
screen.device_scale_factor = window_scale;
force_sync_visual_properties = true;
}
}
#endif // BUILDFLAG(IS_OZONE)
if (screen_infos_ == new_screen_infos && !force_sync_visual_properties)
return;
// We need to look at `orientation_type` which is marked as kUndefined at
// startup. Unlike `orientation_angle` that uses 0 degrees as the default.
// This accounts for devices which have a default landscape orientation, such
// as tablets. We do not want the first UpdateScreenInfo to be treated as a
// rotation.
const bool has_rotation_changed =
screen_infos_.current().orientation_type !=
display::mojom::ScreenOrientation::kUndefined &&
screen_infos_.current().orientation_type !=
new_screen_infos.current().orientation_type;
screen_infos_ = std::move(new_screen_infos);
// Notify the associated RenderWidgetHostImpl when screen info has changed.
// That will synchronize visual properties needed for frame tree rendering
// and for web platform APIs that expose screen and window info and events.
if (host()) {
OnSynchronizedDisplayPropertiesChanged(has_rotation_changed);
host()->NotifyScreenInfoChanged();
}
}
void RenderWidgetHostViewBase::UpdateActiveState(bool active) {
// Send active state through the delegate if there is one to make sure
// it stays consistent across all widgets in the tab. Not every
// RenderWidgetHost has a delegate (for example, drop-down widgets).
if (host()->delegate())
host()->delegate()->SendActiveState(active);
else
host()->SetActive(active);
}
void RenderWidgetHostViewBase::DidUnregisterFromTextInputManager(
TextInputManager* text_input_manager) {
CHECK(text_input_manager && text_input_manager_ == text_input_manager);
text_input_manager_ = nullptr;
}
void RenderWidgetHostViewBase::EnableAutoResize(const gfx::Size& min_size,
const gfx::Size& max_size) {
host()->SetAutoResize(true, min_size, max_size);
host()->SynchronizeVisualProperties();
}
bool RenderWidgetHostViewBase::IsAutoResizeEnabled() {
return host()->auto_resize_enabled();
}
void RenderWidgetHostViewBase::DisableAutoResize(const gfx::Size& new_size) {
// Note that for some subclasses, such as RenderWidgetHostViewAura, setting
// the view size may trigger the synchronization on the visual properties. As
// a result, it may crete the intermediate status that the view size has
// changed while the auto resize status is obsolete, and then brings
// unnecessary updates in view layout. Hence we should disable the auto
// resize before setting the view size.
host()->SetAutoResize(false, gfx::Size(), gfx::Size());
if (!new_size.IsEmpty())
SetSize(new_size);
host()->SynchronizeVisualProperties();
}
viz::ScopedSurfaceIdAllocator
RenderWidgetHostViewBase::DidUpdateVisualProperties(
const cc::RenderFrameMetadata& metadata) {
// This doesn't suppress allocation. Derived classes that need suppression
// should override this function.
base::OnceCallback<void()> allocation_task =
base::BindOnce(&RenderWidgetHostViewBase::SynchronizeVisualProperties,
weak_factory_.GetWeakPtr());
return viz::ScopedSurfaceIdAllocator(std::move(allocation_task));
}
base::WeakPtr<RenderWidgetHostViewBase> RenderWidgetHostViewBase::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
display::ScreenInfo RenderWidgetHostViewBase::GetScreenInfo() const {
return screen_infos_.current();
}
display::ScreenInfos RenderWidgetHostViewBase::GetScreenInfos() const {
return screen_infos_;
}
void RenderWidgetHostViewBase::ResetGestureDetection() {}
float RenderWidgetHostViewBase::GetDeviceScaleFactor() const {
return GetScreenInfos().current().device_scale_factor;
}
base::WeakPtr<input::RenderWidgetHostViewInput>
RenderWidgetHostViewBase::GetInputWeakPtr() {
return weak_factory_.GetWeakPtr();
}
input::RenderInputRouter* RenderWidgetHostViewBase::GetViewRenderInputRouter() {
return host()->GetRenderInputRouter();
}
void RenderWidgetHostViewBase::SetScaleOverrideForCapture(float scale) {
DVLOG(1) << __func__ << ": override=" << scale;
scale_override_for_capture_ = scale;
UpdateScreenInfo();
}
float RenderWidgetHostViewBase::GetScaleOverrideForCapture() const {
return scale_override_for_capture_;
}
void RenderWidgetHostViewBase::OnAutoscrollStart() {
if (!GetMouseWheelPhaseHandler())
return;
// End the current scrolling seqeunce when autoscrolling starts.
GetMouseWheelPhaseHandler()->DispatchPendingWheelEndEvent();
}
DevicePosturePlatformProvider*
RenderWidgetHostViewBase::GetDevicePosturePlatformProvider() {
if (!host() || !host()->delegate()) {
return nullptr;
}
DevicePostureProviderImpl* posture_provider =
static_cast<DevicePostureProviderImpl*>(
host()->delegate()->GetDevicePostureProvider());
if (!posture_provider) {
return nullptr;
}
return posture_provider->platform_provider();
}
gfx::Size RenderWidgetHostViewBase::GetVisibleViewportSize() {
return GetViewBounds().size();
}
gfx::Size RenderWidgetHostViewBase::GetVisibleViewportSizeDevicePx() {
return gfx::ScaleToCeiledSize(GetViewBounds().size(), GetDeviceScaleFactor());
}
void RenderWidgetHostViewBase::SetInsets(const gfx::Insets& insets) {
NOTIMPLEMENTED_LOG_ONCE();
}
const viz::LocalSurfaceId&
RenderWidgetHostViewBase::IncrementSurfaceIdForNavigation() {
NOTREACHED();
}
void RenderWidgetHostViewBase::OnOldViewDidNavigatePreCommit() {}
void RenderWidgetHostViewBase::OnNewViewDidNavigatePostCommit() {}
void RenderWidgetHostViewBase::OnFrameTokenChangedForView(
uint32_t frame_token,
base::TimeTicks activation_time) {
if (host())
host()->DidProcessFrame(frame_token, activation_time);
}
void RenderWidgetHostViewBase::ProcessMouseEvent(
const blink::WebMouseEvent& event,
const ui::LatencyInfo& latency) {
// TODO(crbug.com/40564125): Figure out the reason |host| is null here in all
// Process* functions.
if (!host())
return;
// Ensure the event is not routed to a prerendered page.
if (host()->frame_tree() && host()->frame_tree()->is_prerendering()) {
NOTREACHED();
}
PreProcessMouseEvent(event);
host()->ForwardMouseEventWithLatencyInfo(event, latency);
}
void RenderWidgetHostViewBase::ProcessMouseWheelEvent(
const blink::WebMouseWheelEvent& event,
const ui::LatencyInfo& latency) {
if (!host())
return;
// Ensure the event is not routed to a prerendered page.
if (host()->frame_tree() && host()->frame_tree()->is_prerendering()) {
NOTREACHED();
}
host()->ForwardWheelEventWithLatencyInfo(event, latency);
}
void RenderWidgetHostViewBase::ProcessTouchEvent(
const blink::WebTouchEvent& event,
const ui::LatencyInfo& latency) {
if (!host())
return;
// Ensure the event is not routed to a prerendered page.
if (host()->frame_tree() && host()->frame_tree()->is_prerendering()) {
NOTREACHED();
}
PreProcessTouchEvent(event);
host()->GetRenderInputRouter()->ForwardTouchEventWithLatencyInfo(event,
latency);
}
void RenderWidgetHostViewBase::ProcessGestureEvent(
const blink::WebGestureEvent& event,
const ui::LatencyInfo& latency) {
if (!host())
return;
// Ensure the event is not routed to a prerendered page.
if (host()->frame_tree() && host()->frame_tree()->is_prerendering()) {
NOTREACHED();
}
host()->GetRenderInputRouter()->ForwardGestureEventWithLatencyInfo(event,
latency);
}
gfx::PointF RenderWidgetHostViewBase::TransformPointToRootCoordSpaceF(
const gfx::PointF& point) const {
return RenderWidgetHostViewInput::TransformPointToRootCoordSpaceF(point);
}
bool RenderWidgetHostViewBase::IsRenderWidgetHostViewChildFrame() const {
return false;
}
bool RenderWidgetHostViewBase::HasSize() const {
return true;
}
void RenderWidgetHostViewBase::Show() {
ShowWithVisibility(PageVisibilityState::kVisible);
}
void RenderWidgetHostViewBase::Destroy() {
host_ = nullptr;
}
bool RenderWidgetHostViewBase::CanSynchronizeVisualProperties() {
return true;
}
double RenderWidgetHostViewBase::GetCSSZoomFactor() const {
return 1.0;
}
void RenderWidgetHostViewBase::TextInputStateChanged(
const ui::mojom::TextInputState& text_input_state) {
if (GetTextInputManager())
GetTextInputManager()->UpdateTextInputState(this, text_input_state);
}
void RenderWidgetHostViewBase::ImeCancelComposition() {
if (GetTextInputManager())
GetTextInputManager()->ImeCancelComposition(this);
}
void RenderWidgetHostViewBase::ImeCompositionRangeChanged(
const gfx::Range& range,
const std::optional<std::vector<gfx::Rect>>& character_bounds) {
if (GetTextInputManager()) {
GetTextInputManager()->ImeCompositionRangeChanged(this, range,
character_bounds);
}
}
TextInputManager* RenderWidgetHostViewBase::GetTextInputManager() {
if (text_input_manager_)
return text_input_manager_;
if (!host() || !host()->delegate())
return nullptr;
// This RWHV needs to be registered with the TextInputManager so that the
// TextInputManager starts tracking its state, and observing its lifetime.
text_input_manager_ = host()->delegate()->GetTextInputManager();
if (text_input_manager_)
text_input_manager_->Register(this);
return text_input_manager_;
}
TouchSelectionControllerClientManager*
RenderWidgetHostViewBase::GetTouchSelectionControllerClientManager() {
return nullptr;
}
TouchSelectionControllerInputObserver*
RenderWidgetHostViewBase::GetTouchSelectionControllerInputObserver() {
return nullptr;
}
RenderWidgetHost::InputEventObserver*
RenderWidgetHostViewBase::GetInputTransferHandlerObserver() {
return nullptr;
}
void RenderWidgetHostViewBase::SynchronizeVisualProperties() {
if (host())
host()->SynchronizeVisualProperties();
}
display::ScreenInfos RenderWidgetHostViewBase::GetNewScreenInfosForUpdate() {
// RWHVChildFrame gets its ScreenInfos from the CrossProcessFrameConnector.
CHECK(!IsRenderWidgetHostViewChildFrame());
display::ScreenInfos screen_infos;
if (auto* screen = display::Screen::GetScreen()) {
gfx::NativeView native_view = GetNativeView();
const auto& display = native_view
? screen->GetDisplayNearestView(native_view)
: screen->GetPrimaryDisplay();
screen_infos = screen->GetScreenInfosNearestDisplay(display.id());
} else {
// If there is no Screen, create fake ScreenInfos (for tests).
screen_infos = display::ScreenInfos(display::ScreenInfo());
}
// Set system cursor size separately as it's not a property of screen or
// display.
screen_infos.system_cursor_size = system_cursor_size_;
return screen_infos;
}
void RenderWidgetHostViewBase::DidNavigate() {
if (host())
host()->SynchronizeVisualProperties();
}
WebContentsAccessibility*
RenderWidgetHostViewBase::GetWebContentsAccessibility() {
return nullptr;
}
void RenderWidgetHostViewBase::SetTooltipObserverForTesting(
TooltipObserver* observer) {
tooltip_observer_for_testing_ = observer;
}
ui::Compositor* RenderWidgetHostViewBase::GetCompositor() {
return nullptr;
}
ui::mojom::VirtualKeyboardMode
RenderWidgetHostViewBase::GetVirtualKeyboardMode() {
// Only platforms supporting these APIs will implement this.
return ui::mojom::VirtualKeyboardMode::kUnset;
}
bool RenderWidgetHostViewBase::IsHTMLFormPopup() const {
return false;
}
void RenderWidgetHostViewBase::OnShowWithPageVisibility(
PageVisibilityState page_visibility) {
if (!host())
return;
EnsurePlatformVisibility(page_visibility);
VisibleTimeRequestTrigger& visible_time_request_trigger =
host_->GetVisibleTimeRequestTrigger();
// NB: don't call visible_time_request_trigger.TakeRequest() unless the
// request will be used. If it isn't used here it must be left in the trigger
// for the next call.
const bool web_contents_is_visible =
page_visibility == PageVisibilityState::kVisible;
if (host_->is_hidden()) {
// If the WebContents is becoming visible, ask the compositor to report the
// visibility time for metrics. Otherwise the widget is being rendered even
// though the WebContents is hidden or occluded, for example due to being
// captured, so it should not be included in visibility time metrics.
NotifyHostAndDelegateOnWasShown(
web_contents_is_visible ? visible_time_request_trigger.TakeRequest()
: nullptr);
return;
}
// `page_visibility` changed while the widget remains visible (kVisible ->
// kHiddenButPainting or vice versa). Nothing to do except update the
// visible time request, if any.
if (web_contents_is_visible) {
// The widget is already rendering, but now the WebContents is becoming
// visible, so send any visibility time request to the compositor now.
if (auto visible_time_request =
visible_time_request_trigger.TakeRequest()) {
RequestSuccessfulPresentationTimeFromHostOrDelegate(
std::move(visible_time_request));
}
return;
}
// The widget should keep rendering but the WebContents is no longer
// visible. If the compositor didn't already report the visibility time,
// it's too late. (For example, if the WebContents is being captured and
// was put in the foreground and then quickly hidden again before the
// compositor submitted a frame. The compositor will keep submitting
// frames for the capture but they should not be included in the
// visibility metrics.)
CancelSuccessfulPresentationTimeRequestForHostAndDelegate();
return;
}
void RenderWidgetHostViewBase::SetIsFrameSinkIdOwner(bool is_owner) {
if (is_frame_sink_id_owner_ == is_owner) {
return;
}
is_frame_sink_id_owner_ = is_owner;
UpdateFrameSinkIdRegistration();
}
void RenderWidgetHostViewBase::UpdateFrameSinkIdRegistration() {
// If Destroy() has been called before we get here, host_ may be null.
if (!host() || !host()->delegate() ||
!host()->delegate()->GetInputEventRouter()) {
return;
}
// Let the page-level input event router know about our frame sink ID
// for surface-based hit testing.
auto* router = host()->delegate()->GetInputEventRouter();
if (is_frame_sink_id_owner_) {
if (!router->IsViewInMap(this)) {
router->AddFrameSinkIdOwner(GetFrameSinkId(), this);
}
} else if (router->IsViewInMap(this)) {
// Ensure this view is the owner before removing the associated FrameSinkId
// from input tracking. Speculative views start as non-owing and will not
// register until ownership has been transferred.
router->RemoveFrameSinkIdOwner(GetFrameSinkId());
}
}
void RenderWidgetHostViewBase::SetViewTransitionResources(
std::unique_ptr<ScopedViewTransitionResources> resources) {
view_transition_resources_ = std::move(resources);
}
} // namespace content