blob: 318a27b07fd090b21534926e65a6e94a9260b6ac [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_widget_host_view_base.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
#include "components/viz/common/features.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/service/surfaces/surface_hittest.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/frame_host/render_widget_host_view_guest.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/renderer_host/delegated_frame_host.h"
#include "content/browser/renderer_host/display_util.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_input_event_router.h"
#include "content/browser/renderer_host/render_widget_host_owner_delegate.h"
#include "content/browser/renderer_host/render_widget_host_view_base_observer.h"
#include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
#include "content/browser/renderer_host/text_input_manager.h"
#include "content/common/content_switches_internal.h"
#include "ui/base/layout.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_types.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 defined(USE_AURA)
#include "base/unguessable_token.h"
#include "content/common/render_widget_window_tree_client_factory.mojom.h"
#endif
namespace content {
RenderWidgetHostViewBase::RenderWidgetHostViewBase(RenderWidgetHost* host)
: use_viz_hit_test_(features::IsVizHitTestingEnabled()),
host_(RenderWidgetHostImpl::From(host)),
weak_factory_(this) {
host_->render_frame_metadata_provider()->AddObserver(this);
}
RenderWidgetHostViewBase::~RenderWidgetHostViewBase() {
DCHECK(!keyboard_locked_);
DCHECK(!IsMouseLocked());
// 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, as in RenderWidgetHostViewGuest. 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);
if (host_)
host_->render_frame_metadata_provider()->RemoveObserver(this);
}
RenderWidgetHostImpl* RenderWidgetHostViewBase::GetFocusedWidget() const {
return host() && host()->delegate()
? host()->delegate()->GetFocusedRenderWidgetHost(host())
: nullptr;
}
RenderWidgetHost* RenderWidgetHostViewBase::GetRenderWidgetHost() const {
return host();
}
void RenderWidgetHostViewBase::SetContentBackgroundColor(SkColor color) {
if (content_background_color_ == color)
return;
content_background_color_ = color;
UpdateBackgroundColor();
}
void RenderWidgetHostViewBase::NotifyObserversAboutShutdown() {
// Note: RenderWidgetHostInputEventRouter is an observer, and uses the
// following notification to remove this view from its surface owners map.
for (auto& observer : observers_)
observer.OnRenderWidgetHostViewBaseDestroyed(this);
// All observers are required to disconnect after they are notified.
DCHECK(!observers_.might_have_observers());
}
MouseWheelPhaseHandler* RenderWidgetHostViewBase::GetMouseWheelPhaseHandler() {
return nullptr;
}
void RenderWidgetHostViewBase::StopFlingingIfNecessary(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
// Reset view_stopped_flinging_for_test_ at the beginning of the scroll
// sequence.
if (event.GetType() == blink::WebInputEvent::kGestureScrollBegin)
view_stopped_flinging_for_test_ = false;
bool processed = INPUT_EVENT_ACK_STATE_CONSUMED == ack_result;
if (!processed &&
event.GetType() == blink::WebInputEvent::kGestureScrollUpdate &&
event.data.scroll_update.inertial_phase ==
blink::WebGestureEvent::kMomentumPhase &&
event.SourceDevice() != blink::kWebGestureDeviceSyntheticAutoscroll) {
StopFling();
view_stopped_flinging_for_test_ = true;
}
}
void RenderWidgetHostViewBase::OnRenderFrameMetadataChangedBeforeActivation(
const cc::RenderFrameMetadata& metadata) {}
void RenderWidgetHostViewBase::OnRenderFrameMetadataChangedAfterActivation() {
is_scroll_offset_at_top_ = host_->render_frame_metadata_provider()
->LastRenderFrameMetadata()
.is_scroll_offset_at_top;
}
void RenderWidgetHostViewBase::OnRenderFrameSubmission() {}
void RenderWidgetHostViewBase::OnLocalSurfaceIdChanged(
const cc::RenderFrameMetadata& metadata) {}
void RenderWidgetHostViewBase::UpdateIntrinsicSizingInfo(
const blink::WebIntrinsicSizingInfo& sizing_info) {}
gfx::Size RenderWidgetHostViewBase::GetCompositorViewportPixelSize() const {
return gfx::ScaleToCeiledSize(GetRequestedRendererSize(),
GetDeviceScaleFactor());
}
void RenderWidgetHostViewBase::SelectionBoundsChanged(
const WidgetHostMsg_SelectionBounds_Params& params) {
#if !defined(OS_ANDROID)
if (GetTextInputManager())
GetTextInputManager()->SelectionBoundsChanged(this, params);
#else
NOTREACHED() << "Selection bounds should be routed through the compositor.";
#endif
}
int RenderWidgetHostViewBase::GetMouseWheelMinimumGranularity() const {
// Most platforms can specify the floating-point delta in the wheel event so
// they don't have a minimum granularity. Android is currently the only
// platform that overrides this.
return 0;
}
RenderWidgetHostViewBase* RenderWidgetHostViewBase::GetRootView() {
return this;
}
void RenderWidgetHostViewBase::SelectionChanged(const base::string16& text,
size_t offset,
const gfx::Range& range) {
if (GetTextInputManager())
GetTextInputManager()->SelectionChanged(this, text, offset, range);
}
gfx::Size RenderWidgetHostViewBase::GetRequestedRendererSize() const {
return GetViewBounds().size();
}
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() {
NOTREACHED();
return nullptr;
}
void RenderWidgetHostViewBase::SetIsInVR(bool is_in_vr) {
NOTIMPLEMENTED_LOG_ONCE();
}
bool RenderWidgetHostViewBase::IsInVR() const {
return false;
}
viz::FrameSinkId RenderWidgetHostViewBase::GetRootFrameSinkId() {
return viz::FrameSinkId();
}
bool RenderWidgetHostViewBase::IsSurfaceAvailableForCopy() const {
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 defined(OS_ANDROID)
NOTREACHED()
<< "RenderWidgetHostViewAndroid::CopyFromSurface calls "
"DelegatedFrameHostAndroid::CopyFromCompositingSurface directly, "
"and popups are not supported.";
return;
#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);
canvas.drawBitmap(popup_image, 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());
}
std::unique_ptr<viz::ClientFrameSinkVideoCapturer>
RenderWidgetHostViewBase::CreateVideoCapturer() {
std::unique_ptr<viz::ClientFrameSinkVideoCapturer> video_capturer =
GetHostFrameSinkManager()->CreateVideoCapturer();
video_capturer->ChangeTarget(GetFrameSinkId());
return video_capturer;
}
base::string16 RenderWidgetHostViewBase::GetSelectedText() {
if (!GetTextInputManager())
return base::string16();
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
// RenderView instead.
DCHECK(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);
}
}
}
base::Optional<SkColor> RenderWidgetHostViewBase::GetBackgroundColor() const {
if (content_background_color_)
return content_background_color_;
return default_background_color_;
}
bool RenderWidgetHostViewBase::IsMouseLocked() {
return false;
}
bool RenderWidgetHostViewBase::LockKeyboard(
base::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>();
}
InputEventAckState RenderWidgetHostViewBase::FilterInputEvent(
const blink::WebInputEvent& input_event) {
// By default, input events are simply forwarded to the renderer.
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
InputEventAckState RenderWidgetHostViewBase::FilterChildGestureEvent(
const blink::WebGestureEvent& gesture_event) {
// By default, do nothing with the child's gesture events.
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
void RenderWidgetHostViewBase::WheelEventAck(
const blink::WebMouseWheelEvent& event,
InputEventAckState ack_result) {
}
void RenderWidgetHostViewBase::GestureEventAck(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
}
void RenderWidgetHostViewBase::ForwardTouchpadZoomEventIfNecessary(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
if (!event.IsTouchpadZoomEvent())
return;
if (!event.NeedsWheelEvent())
return;
switch (event.GetType()) {
case blink::WebInputEvent::kGesturePinchBegin:
// Don't send the begin event until we get the first unconsumed update, so
// that we elide pinch gesture steams consisting of only a begin and end.
pending_touchpad_pinch_begin_ = event;
pending_touchpad_pinch_begin_->SetNeedsWheelEvent(false);
break;
case blink::WebInputEvent::kGesturePinchUpdate:
if (ack_result != INPUT_EVENT_ACK_STATE_CONSUMED &&
!event.data.pinch_update.zoom_disabled) {
if (pending_touchpad_pinch_begin_) {
host()->ForwardGestureEvent(*pending_touchpad_pinch_begin_);
pending_touchpad_pinch_begin_.reset();
}
// Now that the synthetic wheel event has gone unconsumed, we have the
// pinch event actually change the page scale.
blink::WebGestureEvent pinch_event(event);
pinch_event.SetNeedsWheelEvent(false);
host()->ForwardGestureEvent(pinch_event);
}
break;
case blink::WebInputEvent::kGesturePinchEnd:
if (pending_touchpad_pinch_begin_) {
pending_touchpad_pinch_begin_.reset();
} else {
blink::WebGestureEvent pinch_end_event(event);
pinch_end_event.SetNeedsWheelEvent(false);
host()->ForwardGestureEvent(pinch_end_event);
}
break;
case blink::WebInputEvent::kGestureDoubleTap:
if (ack_result != INPUT_EVENT_ACK_STATE_CONSUMED) {
blink::WebGestureEvent double_tap(event);
double_tap.SetNeedsWheelEvent(false);
// TODO(mcnee): Support double-tap zoom gesture for OOPIFs. For now,
// we naively send this to the main frame. If this is over an OOPIF,
// then the iframe element will incorrectly be used for the scale
// calculation rather than the element in the OOPIF.
// https://crbug.com/758348
host()->ForwardGestureEvent(double_tap);
}
break;
default:
NOTREACHED();
}
}
bool RenderWidgetHostViewBase::HasFallbackSurface() const {
NOTREACHED();
return false;
}
void RenderWidgetHostViewBase::SetWidgetType(WidgetType widget_type) {
widget_type_ = widget_type;
}
WidgetType RenderWidgetHostViewBase::GetWidgetType() {
return widget_type_;
}
BrowserAccessibilityManager*
RenderWidgetHostViewBase::CreateBrowserAccessibilityManager(
BrowserAccessibilityDelegate* delegate, bool for_root_frame) {
NOTREACHED();
return nullptr;
}
void RenderWidgetHostViewBase::AccessibilityShowMenu(const gfx::Point& point) {
if (host())
host()->ShowContextMenuAtPoint(point, ui::MENU_SOURCE_NONE);
}
gfx::AcceleratedWidget
RenderWidgetHostViewBase::AccessibilityGetAcceleratedWidget() {
return gfx::kNullAcceleratedWidget;
}
gfx::NativeViewAccessible
RenderWidgetHostViewBase::AccessibilityGetNativeViewAccessible() {
return nullptr;
}
gfx::NativeViewAccessible
RenderWidgetHostViewBase::AccessibilityGetNativeViewAccessibleForWindow() {
return nullptr;
}
bool RenderWidgetHostViewBase::RequestRepaintForTesting() {
return false;
}
void RenderWidgetHostViewBase::ProcessAckedTouchEvent(
const TouchEventWithLatencyInfo& touch,
InputEventAckState ack_result) {
NOTREACHED();
}
void RenderWidgetHostViewBase::UpdateScreenInfo(gfx::NativeView view) {
if (host() && host()->delegate())
host()->delegate()->SendScreenRects();
if (HasDisplayPropertyChanged(view) && host()) {
OnSynchronizedDisplayPropertiesChanged();
host()->NotifyScreenInfoChanged();
}
}
bool RenderWidgetHostViewBase::HasDisplayPropertyChanged(gfx::NativeView view) {
display::Display display =
display::Screen::GetScreen()->GetDisplayNearestView(view);
if (current_display_area_ == display.work_area() &&
current_device_scale_factor_ == display.device_scale_factor() &&
current_display_rotation_ == display.rotation() &&
current_display_color_space_ == display.color_space()) {
return false;
}
current_display_area_ = display.work_area();
current_device_scale_factor_ = display.device_scale_factor();
current_display_rotation_ = display.rotation();
current_display_color_space_ = display.color_space();
return true;
}
void RenderWidgetHostViewBase::DidUnregisterFromTextInputManager(
TextInputManager* text_input_manager) {
DCHECK(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();
}
void RenderWidgetHostViewBase::DisableAutoResize(const gfx::Size& new_size) {
if (!new_size.IsEmpty())
SetSize(new_size);
// This clears the cached value in the WebContents, so that OOPIFs will
// stop using it.
if (host()->delegate())
host()->delegate()->ResetAutoResizeSize();
host()->SetAutoResize(false, gfx::Size(), gfx::Size());
host()->SynchronizeVisualProperties();
}
bool RenderWidgetHostViewBase::IsScrollOffsetAtTop() const {
return is_scroll_offset_at_top_;
}
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();
}
std::unique_ptr<SyntheticGestureTarget>
RenderWidgetHostViewBase::CreateSyntheticGestureTarget() {
return std::unique_ptr<SyntheticGestureTarget>(
new SyntheticGestureTargetBase(host()));
}
void RenderWidgetHostViewBase::FocusedNodeTouched(
bool editable) {
DVLOG(1) << "FocusedNodeTouched: " << editable;
}
void RenderWidgetHostViewBase::GetScreenInfo(ScreenInfo* screen_info) const {
DisplayUtil::GetNativeViewScreenInfo(screen_info, GetNativeView());
}
float RenderWidgetHostViewBase::GetDeviceScaleFactor() const {
ScreenInfo screen_info;
GetScreenInfo(&screen_info);
return screen_info.device_scale_factor;
}
uint32_t RenderWidgetHostViewBase::RendererFrameNumber() {
return renderer_frame_number_;
}
void RenderWidgetHostViewBase::DidReceiveRendererFrame() {
++renderer_frame_number_;
}
void RenderWidgetHostViewBase::OnAutoscrollStart() {
if (!GetMouseWheelPhaseHandler())
return;
// End the current scrolling seqeunce when autoscrolling starts.
GetMouseWheelPhaseHandler()->DispatchPendingWheelEndEvent();
}
gfx::Size RenderWidgetHostViewBase::GetVisibleViewportSize() const {
return GetViewBounds().size();
}
void RenderWidgetHostViewBase::SetInsets(const gfx::Insets& insets) {
NOTIMPLEMENTED_LOG_ONCE();
}
void RenderWidgetHostViewBase::DisplayCursor(const WebCursor& cursor) {
return;
}
CursorManager* RenderWidgetHostViewBase::GetCursorManager() {
return nullptr;
}
void RenderWidgetHostViewBase::TransformPointToRootSurface(gfx::PointF* point) {
return;
}
void RenderWidgetHostViewBase::OnDidNavigateMainFrameToNewPage() {
}
void RenderWidgetHostViewBase::OnFrameTokenChangedForView(
uint32_t frame_token) {
if (host())
host()->DidProcessFrame(frame_token);
}
viz::FrameSinkId RenderWidgetHostViewBase::FrameSinkIdAtPoint(
viz::SurfaceHittestDelegate* delegate,
const gfx::PointF& point,
gfx::PointF* transformed_point,
bool* out_query_renderer) {
float device_scale_factor = ui::GetScaleFactorForNativeView(GetNativeView());
DCHECK(device_scale_factor != 0.0f);
// The surface hittest happens in device pixels, so we need to convert the
// |point| from DIPs to pixels before hittesting.
gfx::PointF point_in_pixels =
gfx::ConvertPointToPixel(device_scale_factor, point);
viz::SurfaceId surface_id = GetCurrentSurfaceId();
if (!surface_id.is_valid()) {
// Force a query of the renderer if we don't have a surface id yet.
*out_query_renderer = true;
return GetFrameSinkId();
}
viz::SurfaceHittest hittest(delegate,
GetFrameSinkManager()->surface_manager());
gfx::Transform target_transform;
viz::SurfaceId target_local_surface_id = hittest.GetTargetSurfaceAtPoint(
surface_id, gfx::ToFlooredPoint(point_in_pixels), &target_transform,
out_query_renderer);
*transformed_point = point_in_pixels;
if (target_local_surface_id.is_valid()) {
target_transform.TransformPoint(transformed_point);
}
*transformed_point =
gfx::ConvertPointToDIP(device_scale_factor, *transformed_point);
// It is possible that the renderer has not yet produced a surface, in which
// case we return our current FrameSinkId.
auto frame_sink_id = target_local_surface_id.frame_sink_id();
return frame_sink_id.is_valid() ? frame_sink_id : GetFrameSinkId();
}
void RenderWidgetHostViewBase::ProcessMouseEvent(
const blink::WebMouseEvent& event,
const ui::LatencyInfo& latency) {
// TODO(crbug.com/814674): Figure out the reason |host| is null here in all
// Process* functions.
if (!host())
return;
PreProcessMouseEvent(event);
host()->ForwardMouseEventWithLatencyInfo(event, latency);
}
void RenderWidgetHostViewBase::ProcessMouseWheelEvent(
const blink::WebMouseWheelEvent& event,
const ui::LatencyInfo& latency) {
if (!host())
return;
host()->ForwardWheelEventWithLatencyInfo(event, latency);
}
void RenderWidgetHostViewBase::ProcessTouchEvent(
const blink::WebTouchEvent& event,
const ui::LatencyInfo& latency) {
if (!host())
return;
PreProcessTouchEvent(event);
host()->ForwardTouchEventWithLatencyInfo(event, latency);
}
void RenderWidgetHostViewBase::ProcessGestureEvent(
const blink::WebGestureEvent& event,
const ui::LatencyInfo& latency) {
if (!host())
return;
host()->ForwardGestureEventWithLatencyInfo(event, latency);
}
gfx::PointF RenderWidgetHostViewBase::TransformPointToRootCoordSpaceF(
const gfx::PointF& point) {
return point;
}
gfx::PointF RenderWidgetHostViewBase::TransformRootPointToViewCoordSpace(
const gfx::PointF& point) {
return point;
}
bool RenderWidgetHostViewBase::TransformPointToLocalCoordSpace(
const gfx::PointF& point,
const viz::SurfaceId& original_surface,
gfx::PointF* transformed_point,
viz::EventSource source) {
if (use_viz_hit_test_) {
return TransformPointToLocalCoordSpaceViz(point, original_surface,
transformed_point, source);
}
return TransformPointToLocalCoordSpaceLegacy(point, original_surface,
transformed_point);
}
bool RenderWidgetHostViewBase::TransformPointToLocalCoordSpaceLegacy(
const gfx::PointF& point,
const viz::SurfaceId& original_surface,
gfx::PointF* transformed_point) {
*transformed_point = point;
return true;
}
bool RenderWidgetHostViewBase::TransformPointToCoordSpaceForView(
const gfx::PointF& point,
RenderWidgetHostViewBase* target_view,
gfx::PointF* transformed_point,
viz::EventSource source) {
NOTREACHED();
return true;
}
bool RenderWidgetHostViewBase::IsRenderWidgetHostViewGuest() {
return false;
}
bool RenderWidgetHostViewBase::IsRenderWidgetHostViewChildFrame() {
return false;
}
bool RenderWidgetHostViewBase::HasSize() const {
return true;
}
void RenderWidgetHostViewBase::Destroy() {
if (host_) {
host_->render_frame_metadata_provider()->RemoveObserver(this);
host_ = nullptr;
}
}
void RenderWidgetHostViewBase::TextInputStateChanged(
const 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::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_;
}
void RenderWidgetHostViewBase::StopFling() {
if (!host())
return;
host()->StopFling();
// In case of scroll bubbling tells the child's fling controller which is in
// charge of generating GSUs to stop flinging.
if (host()->delegate() && host()->delegate()->GetInputEventRouter()) {
host()->delegate()->GetInputEventRouter()->StopFling();
}
}
void RenderWidgetHostViewBase::AddObserver(
RenderWidgetHostViewBaseObserver* observer) {
observers_.AddObserver(observer);
}
void RenderWidgetHostViewBase::RemoveObserver(
RenderWidgetHostViewBaseObserver* observer) {
observers_.RemoveObserver(observer);
}
TouchSelectionControllerClientManager*
RenderWidgetHostViewBase::GetTouchSelectionControllerClientManager() {
return nullptr;
}
#if defined(USE_AURA)
void RenderWidgetHostViewBase::EmbedChildFrameRendererWindowTreeClient(
RenderWidgetHostViewBase* root_view,
int routing_id,
ws::mojom::WindowTreeClientPtr renderer_window_tree_client) {
RenderWidgetHost* render_widget_host = GetRenderWidgetHost();
if (!render_widget_host)
return;
const int embed_id = ++next_embed_id_;
pending_embeds_[routing_id] = embed_id;
root_view->ScheduleEmbed(
std::move(renderer_window_tree_client),
base::BindOnce(&RenderWidgetHostViewBase::OnDidScheduleEmbed,
GetWeakPtr(), routing_id, embed_id));
}
void RenderWidgetHostViewBase::OnChildFrameDestroyed(int routing_id) {
pending_embeds_.erase(routing_id);
// Tests may not create |render_widget_window_tree_client_| (tests don't
// necessarily create RenderWidgetHostViewAura).
if (render_widget_window_tree_client_)
render_widget_window_tree_client_->DestroyFrame(routing_id);
}
#endif
void RenderWidgetHostViewBase::SynchronizeVisualProperties() {
if (host())
host()->SynchronizeVisualProperties();
}
#if defined(USE_AURA)
void RenderWidgetHostViewBase::OnDidScheduleEmbed(
int routing_id,
int embed_id,
const base::UnguessableToken& token) {
auto iter = pending_embeds_.find(routing_id);
if (iter == pending_embeds_.end() || iter->second != embed_id)
return;
pending_embeds_.erase(iter);
// Tests may not create |render_widget_window_tree_client_| (tests don't
// necessarily create RenderWidgetHostViewAura).
if (render_widget_window_tree_client_)
render_widget_window_tree_client_->Embed(routing_id, token);
}
void RenderWidgetHostViewBase::ScheduleEmbed(
ws::mojom::WindowTreeClientPtr client,
base::OnceCallback<void(const base::UnguessableToken&)> callback) {
NOTREACHED();
}
ws::mojom::WindowTreeClientPtr
RenderWidgetHostViewBase::GetWindowTreeClientFromRenderer() {
// NOTE: this function may be called multiple times.
RenderWidgetHost* render_widget_host = GetRenderWidgetHost();
mojom::RenderWidgetWindowTreeClientFactoryPtr factory;
BindInterface(render_widget_host->GetProcess(), &factory);
ws::mojom::WindowTreeClientPtr window_tree_client;
factory->CreateWindowTreeClientForRenderWidget(
render_widget_host->GetRoutingID(),
mojo::MakeRequest(&window_tree_client),
mojo::MakeRequest(&render_widget_window_tree_client_));
return window_tree_client;
}
#endif
#if defined(OS_MACOSX)
bool RenderWidgetHostViewBase::ShouldContinueToPauseForFrame() {
return false;
}
void RenderWidgetHostViewBase::SetParentUiLayer(ui::Layer* parent_ui_layer) {}
#endif
void RenderWidgetHostViewBase::DidNavigate() {
if (host())
host()->SynchronizeVisualProperties();
}
// TODO(wjmaclean): Would it simplify this function if we re-implemented it
// using GetTransformToViewCoordSpace()?
bool RenderWidgetHostViewBase::TransformPointToTargetCoordSpace(
RenderWidgetHostViewBase* original_view,
RenderWidgetHostViewBase* target_view,
const gfx::PointF& point,
gfx::PointF* transformed_point,
viz::EventSource source) const {
DCHECK(use_viz_hit_test_);
viz::FrameSinkId root_frame_sink_id = original_view->GetRootFrameSinkId();
if (!root_frame_sink_id.is_valid())
return false;
const auto& display_hit_test_query_map =
GetHostFrameSinkManager()->display_hit_test_query();
const auto iter = display_hit_test_query_map.find(root_frame_sink_id);
if (iter == display_hit_test_query_map.end())
return false;
viz::HitTestQuery* query = iter->second.get();
std::vector<viz::FrameSinkId> target_ancestors;
target_ancestors.push_back(target_view->GetFrameSinkId());
// Optimization using |target_ancestors| does not work with Window Service
// because the top-level window's ClientRoot registers a frame sink id that
// could not be derived here. HisTestQuery::TransformLocationForTarget fails
// because of the missed chain in |target_ancestors|. Passing only the target
// if Window Service used and TransformLocationForTarget would fallback to
// use GetTransformToTarget.
// TODO(crbug.com/895029): Bring back |target_ancestors| optimization for WS.
if (!features::IsUsingWindowService()) {
RenderWidgetHostViewBase* cur_view = target_view;
while (cur_view->IsRenderWidgetHostViewChildFrame()) {
if (cur_view->IsRenderWidgetHostViewGuest()) {
cur_view = static_cast<RenderWidgetHostViewGuest*>(cur_view)
->GetOwnerRenderWidgetHostView();
} else {
cur_view = static_cast<RenderWidgetHostViewChildFrame*>(cur_view)
->GetParentView();
}
if (!cur_view)
return false;
target_ancestors.push_back(cur_view->GetFrameSinkId());
}
target_ancestors.push_back(root_frame_sink_id);
}
float device_scale_factor = original_view->GetDeviceScaleFactor();
DCHECK_GT(device_scale_factor, 0.0f);
gfx::Point3F point_in_pixels(
gfx::ConvertPointToPixel(device_scale_factor, point));
// TODO(riajiang): Optimize so that |point_in_pixels| doesn't need to be in
// the coordinate space of the root surface in HitTestQuery.
gfx::Transform transform_root_to_original;
query->GetTransformToTarget(original_view->GetFrameSinkId(),
&transform_root_to_original);
if (!transform_root_to_original.TransformPointReverse(&point_in_pixels))
return false;
if (!query->TransformLocationForTarget(source, target_ancestors,
point_in_pixels.AsPointF(),
transformed_point)) {
return false;
}
*transformed_point =
gfx::ConvertPointToDIP(device_scale_factor, *transformed_point);
return true;
}
bool RenderWidgetHostViewBase::GetTransformToViewCoordSpace(
RenderWidgetHostViewBase* target_view,
gfx::Transform* transform) {
DCHECK(transform);
if (target_view == this) {
transform->MakeIdentity();
return true;
}
if (!use_viz_hit_test_)
return false;
viz::FrameSinkId root_frame_sink_id = GetRootFrameSinkId();
if (!root_frame_sink_id.is_valid())
return false;
const auto& display_hit_test_query_map =
GetHostFrameSinkManager()->display_hit_test_query();
const auto iter = display_hit_test_query_map.find(root_frame_sink_id);
if (iter == display_hit_test_query_map.end())
return false;
viz::HitTestQuery* query = iter->second.get();
gfx::Transform transform_this_to_root;
if (GetFrameSinkId() != root_frame_sink_id) {
gfx::Transform transform_root_to_this;
if (!query->GetTransformToTarget(GetFrameSinkId(), &transform_root_to_this))
return false;
if (!transform_root_to_this.GetInverse(&transform_this_to_root))
return false;
}
gfx::Transform transform_root_to_target;
if (!query->GetTransformToTarget(target_view->GetFrameSinkId(),
&transform_root_to_target)) {
return false;
}
// TODO(wjmaclean): In TransformPointToTargetCoordSpace the device scale
// factor is taken from the original view ... does that matter? Presumably
// all the views have the same dsf.
float device_scale_factor = GetDeviceScaleFactor();
gfx::Transform transform_to_pixel;
transform_to_pixel.Scale(device_scale_factor, device_scale_factor);
gfx::Transform transform_from_pixel;
transform_from_pixel.Scale(1.f / device_scale_factor,
1.f / device_scale_factor);
// Note: gfx::Transform includes optimizations to early-out for scale = 1 or
// concatenating an identity matrix, so we don't add those checks here.
transform->MakeIdentity();
transform->ConcatTransform(transform_to_pixel);
transform->ConcatTransform(transform_this_to_root);
transform->ConcatTransform(transform_root_to_target);
transform->ConcatTransform(transform_from_pixel);
return true;
}
bool RenderWidgetHostViewBase::TransformPointToLocalCoordSpaceViz(
const gfx::PointF& point,
const viz::SurfaceId& original_surface,
gfx::PointF* transformed_point,
viz::EventSource source) {
DCHECK(use_viz_hit_test_);
viz::FrameSinkId original_frame_sink_id = original_surface.frame_sink_id();
viz::FrameSinkId target_frame_sink_id = GetFrameSinkId();
if (!original_frame_sink_id.is_valid() || !target_frame_sink_id.is_valid())
return false;
if (original_frame_sink_id == target_frame_sink_id)
return true;
if (!host() || !host()->delegate())
return false;
auto* router = host()->delegate()->GetInputEventRouter();
if (!router)
return false;
*transformed_point = point;
return TransformPointToTargetCoordSpace(
router->FindViewFromFrameSinkId(original_frame_sink_id),
router->FindViewFromFrameSinkId(target_frame_sink_id), point,
transformed_point, source);
}
} // namespace content