blob: 09d512fa3a92c2cf08e1745b223901912887f47b [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/frame_host/render_widget_host_view_guest.h"
#include <memory>
#include <utility>
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/service/surfaces/surface.h"
#include "components/viz/service/surfaces/surface_hittest.h"
#include "components/viz/service/surfaces/surface_manager.h"
#include "content/browser/browser_plugin/browser_plugin_guest.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/renderer_host/cursor_manager.h"
#include "content/browser/renderer_host/input/input_router.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/common/browser_plugin/browser_plugin_messages.h"
#include "content/common/frame_messages.h"
#include "content/common/input/web_touch_event_traits.h"
#include "content/common/view_messages.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/use_zoom_for_dsf_policy.h"
#include "gpu/ipc/common/gpu_messages.h"
#include "skia/ext/platform_canvas.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches_util.h"
#include "ui/events/base_event_utils.h"
#include "ui/gfx/geometry/dip_util.h"
#if defined(USE_AURA)
#include "content/browser/renderer_host/ui_events_helper.h"
#include "ui/aura/env.h"
#endif
namespace content {
namespace {
class ScopedInputScaleDisabler {
public:
ScopedInputScaleDisabler(RenderWidgetHostImpl* host, float scale_factor)
: host_(host), scale_factor_(scale_factor) {
if (IsUseZoomForDSFEnabled())
host_->input_router()->SetDeviceScaleFactor(1.0f);
}
~ScopedInputScaleDisabler() {
if (IsUseZoomForDSFEnabled())
host_->input_router()->SetDeviceScaleFactor(scale_factor_);
}
private:
RenderWidgetHostImpl* host_;
float scale_factor_;
DISALLOW_COPY_AND_ASSIGN(ScopedInputScaleDisabler);
};
} // namespace
// static
RenderWidgetHostViewGuest* RenderWidgetHostViewGuest::Create(
RenderWidgetHost* widget,
BrowserPluginGuest* guest,
base::WeakPtr<RenderWidgetHostViewBase> platform_view) {
RenderWidgetHostViewGuest* view =
new RenderWidgetHostViewGuest(widget, guest, platform_view);
view->Init();
return view;
}
// static
RenderWidgetHostViewBase* RenderWidgetHostViewGuest::GetRootView(
RenderWidgetHostViewBase* rwhv) {
// If we're a pdf in a WebView, we could have nested guest views here.
while (rwhv && rwhv->IsRenderWidgetHostViewGuest()) {
rwhv = static_cast<RenderWidgetHostViewGuest*>(rwhv)
->GetOwnerRenderWidgetHostView();
}
if (!rwhv)
return nullptr;
// We could be a guest inside an oopif frame, in which case we're not the
// root.
if (rwhv->IsRenderWidgetHostViewChildFrame()) {
rwhv = static_cast<RenderWidgetHostViewChildFrame*>(rwhv)
->GetRootRenderWidgetHostView();
}
return rwhv;
}
RenderWidgetHostViewBase* RenderWidgetHostViewGuest::GetParentView() {
return GetOwnerRenderWidgetHostView();
}
RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
RenderWidgetHost* widget_host,
BrowserPluginGuest* guest,
base::WeakPtr<RenderWidgetHostViewBase> platform_view)
: RenderWidgetHostViewChildFrame(widget_host),
// |guest| is NULL during test.
guest_(guest ? guest->AsWeakPtr() : base::WeakPtr<BrowserPluginGuest>()),
platform_view_(platform_view),
weak_ptr_factory_(this) {
// In tests |guest_| and therefore |owner| can be null.
auto* owner = GetOwnerRenderWidgetHostView();
if (owner)
SetParentFrameSinkId(owner->GetFrameSinkId());
gfx::NativeView view = GetNativeView();
if (view)
UpdateScreenInfo(view);
}
RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {}
bool RenderWidgetHostViewGuest::OnMessageReceivedFromEmbedder(
const IPC::Message& message,
RenderWidgetHostImpl* embedder) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(RenderWidgetHostViewGuest, message,
embedder)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent,
OnHandleInputEvent)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void RenderWidgetHostViewGuest::Show() {
// If the WebContents associated with us showed an interstitial page in the
// beginning, the teardown path might call WasShown() while |host_| is in
// the process of destruction. Avoid calling WasShown below in this case.
// TODO(lazyboy): We shouldn't be showing interstitial pages in guests in the
// first place: http://crbug.com/273089.
//
// |guest_| is NULL during test.
if ((guest_ && guest_->is_in_destruction()) || !host()->is_hidden())
return;
// Make sure the size of this view matches the size of the WebContentsView.
// The two sizes may fall out of sync if we switch RenderWidgetHostViews,
// resize, and then switch page, as is the case with interstitial pages.
// NOTE: |guest_| is NULL in unit tests.
if (guest_) {
SetSize(guest_->web_contents()->GetViewBounds().size());
// Since we were last shown, our renderer may have had a different surface
// set (e.g. showing an interstitial), so we resend our current surface to
// the renderer.
SendSurfaceInfoToEmbedder();
}
host()->WasShown(false /* record_presentation_time */);
}
void RenderWidgetHostViewGuest::Hide() {
// |guest_| is NULL during test.
if ((guest_ && guest_->is_in_destruction()) || host()->is_hidden())
return;
host()->WasHidden();
}
void RenderWidgetHostViewGuest::SetSize(const gfx::Size& size) {
}
void RenderWidgetHostViewGuest::SetBounds(const gfx::Rect& rect) {
}
void RenderWidgetHostViewGuest::Focus() {
// InterstitialPageImpl focuses views directly, so we place focus logic here.
// InterstitialPages are not WebContents, and so BrowserPluginGuest does not
// have direct access to the interstitial page's RenderWidgetHost.
if (guest_)
guest_->SetFocus(host(), true, blink::kWebFocusTypeNone);
}
bool RenderWidgetHostViewGuest::HasFocus() const {
if (!guest_)
return false;
return guest_->focused();
}
#if defined(USE_AURA)
void RenderWidgetHostViewGuest::ProcessAckedTouchEvent(
const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) {
// TODO(tdresser): Since all ProcessAckedTouchEvent() uses is the event id,
// don't pass the full event object here. https://crbug.com/550581.
GetOwnerRenderWidgetHostView()->ProcessAckedTouchEvent(touch, ack_result);
}
#endif
void RenderWidgetHostViewGuest::PreProcessMouseEvent(
const blink::WebMouseEvent& event) {
if (event.GetType() == blink::WebInputEvent::kMouseDown) {
DCHECK(guest_->GetOwnerRenderWidgetHostView());
RenderWidgetHost* embedder =
guest_->GetOwnerRenderWidgetHostView()->GetRenderWidgetHost();
if (!embedder->GetView()->HasFocus())
embedder->GetView()->Focus();
// With direct routing, the embedder would not know to focus the guest on
// click. Sends a synthetic event for the focusing side effect.
// TODO(wjmaclean): When we remove BrowserPlugin, delete this code.
// http://crbug.com/533069
MaybeSendSyntheticTapGesture(event.PositionInWidget(),
event.PositionInScreen());
}
}
void RenderWidgetHostViewGuest::PreProcessTouchEvent(
const blink::WebTouchEvent& event) {
if (event.GetType() == blink::WebInputEvent::kTouchStart) {
DCHECK(guest_->GetOwnerRenderWidgetHostView());
RenderWidgetHost* embedder =
guest_->GetOwnerRenderWidgetHostView()->GetRenderWidgetHost();
if (!embedder->GetView()->HasFocus())
embedder->GetView()->Focus();
// With direct routing, the embedder would not know to focus the guest on
// touch. Sends a synthetic event for the focusing side effect.
// TODO(wjmaclean): When we remove BrowserPlugin, delete this code.
// http://crbug.com/533069
MaybeSendSyntheticTapGesture(event.touches[0].PositionInWidget(),
event.touches[0].PositionInScreen());
}
}
gfx::Rect RenderWidgetHostViewGuest::GetViewBounds() const {
if (!guest_)
return gfx::Rect();
RenderWidgetHostViewBase* rwhv = GetOwnerRenderWidgetHostView();
gfx::Rect embedder_bounds;
if (rwhv)
embedder_bounds = rwhv->GetViewBounds();
return gfx::Rect(guest_->GetScreenCoordinates(embedder_bounds.origin()),
guest_->frame_rect().size());
}
gfx::Rect RenderWidgetHostViewGuest::GetBoundsInRootWindow() {
return GetViewBounds();
}
gfx::PointF RenderWidgetHostViewGuest::TransformPointToRootCoordSpaceF(
const gfx::PointF& point) {
// LocalSurfaceId is not needed in Viz hit-test.
if (!guest_ ||
(!use_viz_hit_test_ && !last_activated_surface_info_.is_valid())) {
return point;
}
RenderWidgetHostViewBase* root_rwhv = GetRootView(this);
if (!root_rwhv)
return point;
gfx::PointF transformed_point = point;
// TODO(wjmaclean): If we knew that TransformPointToLocalCoordSpace would
// guarantee not to change transformed_point on failure, then we could skip
// checking the function return value and directly return transformed_point.
if (!root_rwhv->TransformPointToLocalCoordSpace(
point, last_activated_surface_info_.id(), &transformed_point)) {
return point;
}
return transformed_point;
}
bool RenderWidgetHostViewGuest::TransformPointToLocalCoordSpaceLegacy(
const gfx::PointF& point,
const viz::SurfaceId& original_surface,
gfx::PointF* transformed_point) {
*transformed_point = point;
if (!guest_ || !last_activated_surface_info_.is_valid())
return false;
if (original_surface == last_activated_surface_info_.id())
return true;
*transformed_point =
gfx::ConvertPointToPixel(current_surface_scale_factor(), point);
viz::SurfaceHittest hittest(nullptr,
GetFrameSinkManager()->surface_manager());
if (!hittest.TransformPointToTargetSurface(original_surface,
last_activated_surface_info_.id(),
transformed_point)) {
return false;
}
*transformed_point = gfx::ConvertPointToDIP(current_surface_scale_factor(),
*transformed_point);
return true;
}
gfx::PointF RenderWidgetHostViewGuest::TransformRootPointToViewCoordSpace(
const gfx::PointF& point) {
RenderWidgetHostViewBase* root_rwhv = GetRootView(this);
if (!root_rwhv)
return point;
gfx::PointF transformed_point;
if (!root_rwhv->TransformPointToCoordSpaceForView(point, this,
&transformed_point)) {
return point;
}
return transformed_point;
}
void RenderWidgetHostViewGuest::RenderProcessGone(
base::TerminationStatus status,
int error_code) {
// The |platform_view_| gets destroyed before we get here if this view
// is for an InterstitialPage.
if (platform_view_)
platform_view_->RenderProcessGone(status, error_code);
RenderWidgetHostViewChildFrame::RenderProcessGone(status, error_code);
}
void RenderWidgetHostViewGuest::Destroy() {
if (platform_view_) // The platform view might have been destroyed already.
platform_view_->Destroy();
RenderWidgetHostViewBase* root_view = GetRootView(this);
if (root_view)
root_view->GetCursorManager()->ViewBeingDestroyed(this);
// RenderWidgetHostViewChildFrame::Destroy destroys this object.
RenderWidgetHostViewChildFrame::Destroy();
}
gfx::Size RenderWidgetHostViewGuest::GetCompositorViewportPixelSize() const {
gfx::Size size;
if (guest_) {
size = gfx::ScaleToCeiledSize(guest_->frame_rect().size(),
guest_->screen_info().device_scale_factor);
}
return size;
}
base::string16 RenderWidgetHostViewGuest::GetSelectedText() {
return platform_view_->GetSelectedText();
}
base::string16 RenderWidgetHostViewGuest::GetSurroundingText() {
return platform_view_->GetSurroundingText();
}
gfx::Range RenderWidgetHostViewGuest::GetSelectedRange() {
return platform_view_->GetSelectedRange();
}
size_t RenderWidgetHostViewGuest::GetOffsetForSurroundingText() {
return platform_view_->GetOffsetForSurroundingText();
}
void RenderWidgetHostViewGuest::SetNeedsBeginFrames(bool needs_begin_frames) {
if (platform_view_)
platform_view_->SetNeedsBeginFrames(needs_begin_frames);
}
TouchSelectionControllerClientManager*
RenderWidgetHostViewGuest::GetTouchSelectionControllerClientManager() {
RenderWidgetHostView* root_view = GetRootView(this);
if (!root_view)
return nullptr;
// There is only ever one manager, and it's owned by the root view.
return root_view->GetTouchSelectionControllerClientManager();
}
void RenderWidgetHostViewGuest::SetTooltipText(
const base::string16& tooltip_text) {
RenderWidgetHostViewBase* root_view = GetRootView(this);
if (root_view)
root_view->GetCursorManager()->SetTooltipTextForView(this, tooltip_text);
}
void RenderWidgetHostViewGuest::FirstSurfaceActivation(
const viz::SurfaceInfo& surface_info) {
if (guest_ && !guest_->is_in_destruction())
guest_->FirstSurfaceActivation(surface_info);
}
void RenderWidgetHostViewGuest::OnDidUpdateVisualPropertiesComplete(
const cc::RenderFrameMetadata& metadata) {
if (guest_)
guest_->DidUpdateVisualProperties(metadata);
host()->SynchronizeVisualProperties();
}
void RenderWidgetHostViewGuest::OnAttached() {
RegisterFrameSinkId();
#if defined(USE_AURA)
if (!features::IsAshInBrowserProcess()) {
aura::Env::GetInstance()->ScheduleEmbed(
GetWindowTreeClientFromRenderer(),
base::BindOnce(&RenderWidgetHostViewGuest::OnGotEmbedToken,
weak_ptr_factory_.GetWeakPtr()));
}
#endif
SendSurfaceInfoToEmbedder();
}
bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message& msg) {
if (!platform_view_) {
// In theory, we can get here if there's a delay between Destroy()
// being called and when our destructor is invoked.
return false;
}
return platform_view_->OnMessageReceived(msg);
}
void RenderWidgetHostViewGuest::InitAsChild(
gfx::NativeView parent_view) {
// This should never get called.
NOTREACHED();
}
void RenderWidgetHostViewGuest::InitAsPopup(
RenderWidgetHostView* parent_host_view, const gfx::Rect& bounds) {
// This should never get called.
NOTREACHED();
}
void RenderWidgetHostViewGuest::InitAsFullscreen(
RenderWidgetHostView* reference_host_view) {
// This should never get called.
NOTREACHED();
}
gfx::NativeView RenderWidgetHostViewGuest::GetNativeView() const {
if (!guest_)
return gfx::NativeView();
RenderWidgetHostView* rwhv = guest_->GetOwnerRenderWidgetHostView();
if (!rwhv)
return gfx::NativeView();
return rwhv->GetNativeView();
}
gfx::NativeViewAccessible RenderWidgetHostViewGuest::GetNativeViewAccessible() {
if (!guest_)
return gfx::NativeViewAccessible();
RenderWidgetHostView* rwhv = guest_->GetOwnerRenderWidgetHostView();
if (!rwhv)
return gfx::NativeViewAccessible();
return rwhv->GetNativeViewAccessible();
}
void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor& cursor) {
// InterstitialPages are not WebContents so we cannot intercept
// ViewHostMsg_SetCursor for interstitial pages in BrowserPluginGuest.
// All guest RenderViewHosts have RenderWidgetHostViewGuests however,
// and so we will always hit this code path.
if (!guest_)
return;
RenderWidgetHostViewBase* rwhvb = GetRootView(this);
if (rwhvb && rwhvb->GetCursorManager())
rwhvb->GetCursorManager()->UpdateCursor(this, cursor);
}
void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading) {
platform_view_->SetIsLoading(is_loading);
}
bool RenderWidgetHostViewGuest::HasSize() const {
// RenderWidgetHostViewGuests are always hosting main frames, so the renderer
// always have a size, which is sent on the CreateView IPC.
return true;
}
void RenderWidgetHostViewGuest::TextInputStateChanged(
const TextInputState& params) {
if (!guest_)
return;
RenderWidgetHostViewBase* rwhv = GetOwnerRenderWidgetHostView();
if (!rwhv)
return;
// Forward the information to embedding RWHV.
rwhv->TextInputStateChanged(params);
should_forward_text_selection_ =
(params.type != ui::TEXT_INPUT_TYPE_NONE) && guest_ && guest_->focused();
}
void RenderWidgetHostViewGuest::ImeCancelComposition() {
if (!guest_)
return;
RenderWidgetHostViewBase* rwhv = GetOwnerRenderWidgetHostView();
if (!rwhv)
return;
// Forward the information to embedding RWHV.
rwhv->ImeCancelComposition();
}
#if defined(OS_MACOSX) || defined(USE_AURA)
void RenderWidgetHostViewGuest::ImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds) {
if (!guest_)
return;
RenderWidgetHostViewBase* rwhv = GetOwnerRenderWidgetHostView();
if (!rwhv)
return;
std::vector<gfx::Rect> guest_character_bounds;
for (size_t i = 0; i < character_bounds.size(); ++i) {
guest_character_bounds.push_back(gfx::Rect(
guest_->GetScreenCoordinates(character_bounds[i].origin()),
character_bounds[i].size()));
}
// Forward the information to embedding RWHV.
rwhv->ImeCompositionRangeChanged(range, guest_character_bounds);
}
#endif
void RenderWidgetHostViewGuest::SelectionChanged(const base::string16& text,
size_t offset,
const gfx::Range& range) {
RenderWidgetHostViewBase* view = should_forward_text_selection_
? GetOwnerRenderWidgetHostView()
: platform_view_.get();
if (view)
view->SelectionChanged(text, offset, range);
}
void RenderWidgetHostViewGuest::SelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params& params) {
if (!guest_)
return;
RenderWidgetHostViewBase* rwhv = GetOwnerRenderWidgetHostView();
if (!rwhv)
return;
ViewHostMsg_SelectionBounds_Params guest_params(params);
guest_params.anchor_rect.set_origin(
guest_->GetScreenCoordinates(params.anchor_rect.origin()));
guest_params.focus_rect.set_origin(
guest_->GetScreenCoordinates(params.focus_rect.origin()));
rwhv->SelectionBoundsChanged(guest_params);
}
void RenderWidgetHostViewGuest::DidStopFlinging() {
RenderWidgetHostViewBase* rwhv = this;
// If we're a pdf in a WebView, we could have nested guest views here.
while (rwhv && rwhv->IsRenderWidgetHostViewGuest()) {
rwhv = static_cast<RenderWidgetHostViewGuest*>(rwhv)
->GetOwnerRenderWidgetHostView();
}
// DidStopFlinging() is used by TouchSelection to correctly detect the end of
// scroll events, so we forward this to the top-level RenderWidgetHostViewBase
// so it can be passed along to its TouchSelectionController.
if (rwhv)
rwhv->DidStopFlinging();
}
bool RenderWidgetHostViewGuest::LockMouse() {
return platform_view_->LockMouse();
}
void RenderWidgetHostViewGuest::UnlockMouse() {
platform_view_->UnlockMouse();
}
viz::FrameSinkId RenderWidgetHostViewGuest::GetRootFrameSinkId() {
RenderWidgetHostViewBase* root_rwhv = GetRootView(this);
if (root_rwhv)
return root_rwhv->GetRootFrameSinkId();
return viz::FrameSinkId();
}
const viz::LocalSurfaceId& RenderWidgetHostViewGuest::GetLocalSurfaceId()
const {
if (guest_)
return guest_->local_surface_id();
return viz::ParentLocalSurfaceIdAllocator::InvalidLocalSurfaceId();
}
void RenderWidgetHostViewGuest::DidCreateNewRendererCompositorFrameSink(
viz::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink) {
RenderWidgetHostViewChildFrame::DidCreateNewRendererCompositorFrameSink(
renderer_compositor_frame_sink);
platform_view_->DidCreateNewRendererCompositorFrameSink(
renderer_compositor_frame_sink);
}
#if defined(OS_MACOSX)
void RenderWidgetHostViewGuest::SetActive(bool active) {
platform_view_->SetActive(active);
}
void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
// Note that if there were a dictionary overlay, that dictionary overlay
// would target |guest_|. This path does not actually support getting the
// attributed string and its point on the page, so it will not create an
// overlay (it will open Dictionary.app), so the target NSView need not be
// specified.
// https://crbug.com/152438
platform_view_->ShowDefinitionForSelection();
}
void RenderWidgetHostViewGuest::SpeakSelection() {
platform_view_->SpeakSelection();
}
#endif // defined(OS_MACOSX)
RenderWidgetHostViewBase*
RenderWidgetHostViewGuest::GetOwnerRenderWidgetHostView() const {
return guest_ ? static_cast<RenderWidgetHostViewBase*>(
guest_->GetOwnerRenderWidgetHostView())
: nullptr;
}
// TODO(wjmaclean): When we remove BrowserPlugin, delete this code.
// http://crbug.com/533069
void RenderWidgetHostViewGuest::MaybeSendSyntheticTapGesture(
const blink::WebFloatPoint& position,
const blink::WebFloatPoint& screenPosition) const {
if (!HasFocus()) {
// We need to a account for the position of the guest view within the
// embedder, as well as the fact that the embedder's host will add its
// offset in screen coordinates before sending the event (with the latter
// component just serving to confuse the renderer, hence why it should be
// removed).
gfx::Vector2d offset =
GetViewBounds().origin() -
GetOwnerRenderWidgetHostView()->GetBoundsInRootWindow().origin();
blink::WebGestureEvent gesture_tap_event(
blink::WebGestureEvent::kGestureTapDown,
blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow(),
blink::kWebGestureDeviceTouchscreen);
gesture_tap_event.SetPositionInWidget(
blink::WebFloatPoint(position.x + offset.x(), position.y + offset.y()));
gesture_tap_event.SetPositionInScreen(screenPosition);
GetOwnerRenderWidgetHostView()->ProcessGestureEvent(
gesture_tap_event, ui::LatencyInfo(ui::SourceEventType::TOUCH));
gesture_tap_event.SetType(blink::WebGestureEvent::kGestureTapCancel);
GetOwnerRenderWidgetHostView()->ProcessGestureEvent(
gesture_tap_event, ui::LatencyInfo(ui::SourceEventType::TOUCH));
}
}
void RenderWidgetHostViewGuest::WheelEventAck(
const blink::WebMouseWheelEvent& event,
InputEventAckState ack_result) {
if (ack_result == INPUT_EVENT_ACK_STATE_NOT_CONSUMED ||
ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) {
guest_->ResendEventToEmbedder(event);
}
}
void RenderWidgetHostViewGuest::GestureEventAck(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
bool not_consumed = ack_result == INPUT_EVENT_ACK_STATE_NOT_CONSUMED ||
ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
// GestureScrollBegin/End are always consumed by the guest, so we only
// forward GestureScrollUpdate.
// Consumed GestureScrollUpdates and GestureScrollBegins must still be
// forwarded to the owner RWHV so it may update its state.
if (event.GetType() == blink::WebInputEvent::kGestureScrollUpdate &&
not_consumed) {
guest_->ResendEventToEmbedder(event);
} else if (event.GetType() == blink::WebInputEvent::kGestureScrollUpdate ||
event.GetType() == blink::WebInputEvent::kGestureScrollBegin) {
GetOwnerRenderWidgetHostView()->GestureEventAck(event, ack_result);
}
if (blink::WebInputEvent::IsPinchGestureEventType(event.GetType()))
ProcessTouchpadPinchAckInRoot(event, ack_result);
}
void RenderWidgetHostViewGuest::ProcessTouchpadPinchAckInRoot(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
DCHECK(blink::WebInputEvent::IsPinchGestureEventType(event.GetType()));
RenderWidgetHostViewBase* root_rwhv = GetRootView(this);
if (!root_rwhv)
return;
blink::WebGestureEvent pinch_event(event);
const gfx::PointF root_point =
TransformPointToRootCoordSpaceF(event.PositionInWidget());
pinch_event.SetPositionInWidget(root_point);
root_rwhv->GestureEventAck(pinch_event, ack_result);
}
InputEventAckState RenderWidgetHostViewGuest::FilterInputEvent(
const blink::WebInputEvent& input_event) {
InputEventAckState ack_state =
RenderWidgetHostViewChildFrame::FilterInputEvent(input_event);
if (ack_state != INPUT_EVENT_ACK_STATE_NOT_CONSUMED)
return ack_state;
// The owner RWHV may want to consume the guest's GestureScrollUpdates.
// Also, we don't resend GestureFlingStarts, GestureScrollBegins, or
// GestureScrollEnds, so we let the owner RWHV know about them here.
if (input_event.GetType() == blink::WebInputEvent::kGestureScrollUpdate ||
input_event.GetType() == blink::WebInputEvent::kGestureFlingStart ||
input_event.GetType() == blink::WebInputEvent::kGestureScrollBegin ||
input_event.GetType() == blink::WebInputEvent::kGestureScrollEnd) {
const blink::WebGestureEvent& gesture_event =
static_cast<const blink::WebGestureEvent&>(input_event);
return GetOwnerRenderWidgetHostView()->FilterChildGestureEvent(
gesture_event);
}
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
void RenderWidgetHostViewGuest::GetScreenInfo(ScreenInfo* screen_info) const {
DCHECK(screen_info);
if (guest_)
*screen_info = guest_->screen_info();
else
RenderWidgetHostViewBase::GetScreenInfo(screen_info);
}
void RenderWidgetHostViewGuest::EnableAutoResize(const gfx::Size& min_size,
const gfx::Size& max_size) {
if (guest_)
guest_->EnableAutoResize(min_size, max_size);
}
void RenderWidgetHostViewGuest::DisableAutoResize(const gfx::Size& new_size) {
if (guest_)
guest_->DisableAutoResize();
}
viz::ScopedSurfaceIdAllocator
RenderWidgetHostViewGuest::DidUpdateVisualProperties(
const cc::RenderFrameMetadata& metadata) {
base::OnceCallback<void()> allocation_task = base::BindOnce(
&RenderWidgetHostViewGuest::OnDidUpdateVisualPropertiesComplete,
weak_ptr_factory_.GetWeakPtr(), metadata);
return viz::ScopedSurfaceIdAllocator(std::move(allocation_task));
}
bool RenderWidgetHostViewGuest::IsRenderWidgetHostViewGuest() {
return true;
}
void RenderWidgetHostViewGuest::OnHandleInputEvent(
RenderWidgetHostImpl* embedder,
int browser_plugin_instance_id,
const blink::WebInputEvent* event) {
// WebMouseWheelEvents go into a queue, and may not be forwarded to the
// renderer until after this method goes out of scope. Therefore we need to
// explicitly remove the additional device scale factor from the coordinates
// before allowing the event to be queued.
if (IsUseZoomForDSFEnabled() &&
event->GetType() == blink::WebInputEvent::kMouseWheel) {
blink::WebMouseWheelEvent rescaled_event =
*static_cast<const blink::WebMouseWheelEvent*>(event);
rescaled_event.SetPositionInWidget(
rescaled_event.PositionInWidget().x / current_device_scale_factor(),
rescaled_event.PositionInWidget().y / current_device_scale_factor());
rescaled_event.delta_x /= current_device_scale_factor();
rescaled_event.delta_y /= current_device_scale_factor();
rescaled_event.wheel_ticks_x /= current_device_scale_factor();
rescaled_event.wheel_ticks_y /= current_device_scale_factor();
ui::LatencyInfo latency_info(ui::SourceEventType::WHEEL);
host()->ForwardWheelEventWithLatencyInfo(rescaled_event, latency_info);
return;
}
ScopedInputScaleDisabler disable(host(), current_device_scale_factor());
if (blink::WebInputEvent::IsMouseEventType(event->GetType())) {
host()->ForwardMouseEvent(*static_cast<const blink::WebMouseEvent*>(event));
return;
}
if (event->GetType() == blink::WebInputEvent::kMouseWheel) {
ui::LatencyInfo latency_info(ui::SourceEventType::WHEEL);
host()->ForwardWheelEventWithLatencyInfo(
*static_cast<const blink::WebMouseWheelEvent*>(event), latency_info);
return;
}
if (blink::WebInputEvent::IsKeyboardEventType(event->GetType())) {
NativeWebKeyboardEvent keyboard_event(
*static_cast<const blink::WebKeyboardEvent*>(event), GetNativeView());
host()->ForwardKeyboardEvent(keyboard_event);
return;
}
if (blink::WebInputEvent::IsTouchEventType(event->GetType())) {
if (event->GetType() == blink::WebInputEvent::kTouchStart &&
!embedder->GetView()->HasFocus()) {
embedder->GetView()->Focus();
}
ui::LatencyInfo latency_info(ui::SourceEventType::TOUCH);
host()->ForwardTouchEventWithLatencyInfo(
*static_cast<const blink::WebTouchEvent*>(event), latency_info);
return;
}
if (blink::WebInputEvent::IsGestureEventType(event->GetType())) {
const blink::WebGestureEvent& gesture_event =
*static_cast<const blink::WebGestureEvent*>(event);
// We don't forward inertial GestureScrollUpdates to the guest anymore
// since it now receives GestureFlingStart and will have its own fling
// curve generating GestureScrollUpdate events for it.
// TODO(wjmaclean): Should we try to avoid creating a fling curve in the
// embedder renderer in this case? BrowserPlugin can return 'true' for
// handleInputEvent() on a GestureFlingStart, and we could use this as
// a signal to let the guest handle the fling, though we'd need to be
// sure other plugins would behave appropriately (i.e. return 'false').
if (gesture_event.GetType() == blink::WebInputEvent::kGestureScrollUpdate &&
gesture_event.data.scroll_update.inertial_phase ==
blink::WebGestureEvent::kMomentumPhase) {
return;
}
host()->ForwardGestureEvent(gesture_event);
return;
}
}
#if defined(USE_AURA)
void RenderWidgetHostViewGuest::OnGotEmbedToken(
const base::UnguessableToken& token) {
if (!guest_)
return;
guest_->SendMessageToEmbedder(
std::make_unique<BrowserPluginMsg_SetMusEmbedToken>(
guest_->browser_plugin_instance_id(), token));
}
#endif
} // namespace content