blob: 08f42d361b527725e30863ceeb60369b63e74f2f [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/renderer_host/render_widget_host_view_child_frame.h"
#include <algorithm>
#include <utility>
#include <vector>
#include "base/debug/dump_without_crashing.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.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_manager.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/browser_plugin/browser_plugin_guest.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/frame_connector_delegate.h"
#include "content/browser/renderer_host/input/touch_selection_controller_client_child_frame.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_impl.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/browser/renderer_host/render_widget_host_view_event_handler.h"
#include "content/browser/renderer_host/text_input_manager.h"
#include "content/common/text_input_state.h"
#include "content/common/view_messages.h"
#include "content/public/browser/guest_mode.h"
#include "content/public/browser/render_process_host.h"
#include "gpu/ipc/common/gpu_messages.h"
#include "services/service_manager/runner/common/client_util.h"
#include "third_party/WebKit/public/platform/WebTouchEvent.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/touch_selection/touch_selection_controller.h"
#if defined(USE_AURA)
#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "ui/aura/env.h"
#endif
namespace content {
// static
RenderWidgetHostViewChildFrame* RenderWidgetHostViewChildFrame::Create(
RenderWidgetHost* widget) {
RenderWidgetHostViewChildFrame* view =
new RenderWidgetHostViewChildFrame(widget);
view->Init();
return view;
}
RenderWidgetHostViewChildFrame::RenderWidgetHostViewChildFrame(
RenderWidgetHost* widget_host)
: host_(RenderWidgetHostImpl::From(widget_host)),
frame_sink_id_(
base::checked_cast<uint32_t>(widget_host->GetProcess()->GetID()),
base::checked_cast<uint32_t>(widget_host->GetRoutingID())),
next_surface_sequence_(1u),
current_surface_scale_factor_(1.f),
frame_connector_(nullptr),
background_color_(SK_ColorWHITE),
scroll_bubbling_state_(NO_ACTIVE_GESTURE_SCROLL),
weak_factory_(this) {
if (!IsUsingMus()) {
GetHostFrameSinkManager()->RegisterFrameSinkId(frame_sink_id_, this);
#if DCHECK_IS_ON()
GetHostFrameSinkManager()->SetFrameSinkDebugLabel(
frame_sink_id_, "RenderWidgetHostViewChildFrame");
#endif
CreateCompositorFrameSinkSupport();
}
}
RenderWidgetHostViewChildFrame::~RenderWidgetHostViewChildFrame() {
// TODO(wjmaclean): The next two lines are a speculative fix for
// https://crbug.com/760074, based on the theory that perhaps something is
// destructing the class without calling Destroy() first.
if (frame_connector_)
DetachFromTouchSelectionClientManagerIfNecessary();
if (!IsUsingMus()) {
ResetCompositorFrameSinkSupport();
if (GetHostFrameSinkManager())
GetHostFrameSinkManager()->InvalidateFrameSinkId(frame_sink_id_);
}
}
void RenderWidgetHostViewChildFrame::Init() {
RegisterFrameSinkId();
host_->SetView(this);
GetTextInputManager();
}
void RenderWidgetHostViewChildFrame::
DetachFromTouchSelectionClientManagerIfNecessary() {
if (!selection_controller_client_)
return;
auto* root_view = frame_connector_->GetRootRenderWidgetHostView();
if (root_view) {
auto* manager = root_view->GetTouchSelectionControllerClientManager();
if (manager)
manager->RemoveObserver(this);
} else {
// We should never get here, but maybe we are? Test this out with a
// diagnostic we can track. If we do get here, it would explain
// https://crbug.com/760074.
base::debug::DumpWithoutCrashing();
}
selection_controller_client_.reset();
}
void RenderWidgetHostViewChildFrame::SetFrameConnectorDelegate(
FrameConnectorDelegate* frame_connector) {
if (frame_connector_ == frame_connector)
return;
if (frame_connector_) {
SetParentFrameSinkId(viz::FrameSinkId());
last_received_local_surface_id_ = viz::LocalSurfaceId();
// Unlocks the mouse if this RenderWidgetHostView holds the lock.
UnlockMouse();
DetachFromTouchSelectionClientManagerIfNecessary();
}
frame_connector_ = frame_connector;
if (!frame_connector_)
return;
RenderWidgetHostViewBase* parent_view =
frame_connector_->GetParentRenderWidgetHostView();
if (parent_view) {
DCHECK(parent_view->GetFrameSinkId().is_valid() || IsUsingMus());
SetParentFrameSinkId(parent_view->GetFrameSinkId());
}
current_device_scale_factor_ =
frame_connector_->screen_info().device_scale_factor;
auto* root_view = frame_connector_->GetRootRenderWidgetHostView();
if (root_view) {
auto* manager = root_view->GetTouchSelectionControllerClientManager();
if (manager) {
// We have managers in Aura and Android, as well as outside of content/.
// There is no manager for Mac OS.
selection_controller_client_ =
std::make_unique<TouchSelectionControllerClientChildFrame>(this,
manager);
manager->AddObserver(this);
}
}
#if defined(USE_AURA)
if (IsUsingMus()) {
frame_connector_->EmbedRendererWindowTreeClientInParent(
GetWindowTreeClientFromRenderer());
}
#endif
}
void RenderWidgetHostViewChildFrame::OnManagerWillDestroy(
TouchSelectionControllerClientManager* manager) {
// We get the manager via the observer callback instead of through the
// frame_connector_ since our connection to the root_view may disappear by
// the time this function is called, but before frame_connector_ is reset.
manager->RemoveObserver(this);
selection_controller_client_.reset();
}
void RenderWidgetHostViewChildFrame::InitAsChild(gfx::NativeView parent_view) {
NOTREACHED();
}
RenderWidgetHost* RenderWidgetHostViewChildFrame::GetRenderWidgetHost() const {
return host_;
}
void RenderWidgetHostViewChildFrame::SetSize(const gfx::Size& size) {
host_->WasResized();
}
void RenderWidgetHostViewChildFrame::SetBounds(const gfx::Rect& rect) {
SetSize(rect.size());
if (rect != last_screen_rect_) {
last_screen_rect_ = rect;
host_->SendScreenRects();
}
}
void RenderWidgetHostViewChildFrame::Focus() {}
bool RenderWidgetHostViewChildFrame::HasFocus() const {
if (frame_connector_)
return frame_connector_->HasFocus();
return false;
}
bool RenderWidgetHostViewChildFrame::IsSurfaceAvailableForCopy() const {
return has_frame_;
}
void RenderWidgetHostViewChildFrame::Show() {
if (!host_->is_hidden())
return;
if (!CanBecomeVisible())
return;
host_->WasShown(ui::LatencyInfo());
if (frame_connector_)
frame_connector_->SetVisibilityForChildViews(true);
}
void RenderWidgetHostViewChildFrame::Hide() {
if (host_->is_hidden())
return;
host_->WasHidden();
if (frame_connector_)
frame_connector_->SetVisibilityForChildViews(false);
}
bool RenderWidgetHostViewChildFrame::IsShowing() {
return !host_->is_hidden();
}
gfx::Rect RenderWidgetHostViewChildFrame::GetViewBounds() const {
gfx::Rect rect;
if (frame_connector_) {
rect = frame_connector_->ChildFrameRect();
RenderWidgetHostView* parent_view =
frame_connector_->GetParentRenderWidgetHostView();
// The parent_view can be null in tests when using a TestWebContents.
if (parent_view) {
// Translate frame_rect by the parent's RenderWidgetHostView offset.
rect.Offset(parent_view->GetViewBounds().OffsetFromOrigin());
}
}
return rect;
}
gfx::Size RenderWidgetHostViewChildFrame::GetVisibleViewportSize() const {
// For subframes, the visual viewport corresponds to the main frame size, so
// this bubbles up to the parent until it hits the main frame's
// RenderWidgetHostView.
//
// Currently this excludes webview guests, since they expect the visual
// viewport to return the guest's size rather than the page's; one reason why
// is that Blink ends up using the visual viewport to calculate things like
// window.innerWidth/innerHeight for main frames, and a guest is considered
// to be a main frame. This should be cleaned up eventually.
bool is_guest = BrowserPluginGuest::IsGuest(RenderViewHostImpl::From(host_));
if (frame_connector_ && !is_guest) {
// An auto-resize set by the top-level frame overrides what would be
// reported by embedding RenderWidgetHostViews.
if (host_->delegate() && !host_->delegate()->GetAutoResizeSize().IsEmpty())
return host_->delegate()->GetAutoResizeSize();
RenderWidgetHostView* parent_view =
frame_connector_->GetParentRenderWidgetHostView();
// The parent_view can be null in unit tests when using a TestWebContents.
if (parent_view)
return parent_view->GetVisibleViewportSize();
}
return GetViewBounds().size();
}
gfx::Vector2dF RenderWidgetHostViewChildFrame::GetLastScrollOffset() const {
return last_scroll_offset_;
}
gfx::NativeView RenderWidgetHostViewChildFrame::GetNativeView() const {
// TODO(ekaramad): To accomodate MimeHandlerViewGuest while embedded inside
// OOPIF-webview, we need to return the native view to be used by
// RenderWidgetHostViewGuest. Remove this once https://crbug.com/642826 is
// fixed.
if (frame_connector_)
return frame_connector_->GetParentRenderWidgetHostView()->GetNativeView();
return nullptr;
}
gfx::NativeViewAccessible
RenderWidgetHostViewChildFrame::GetNativeViewAccessible() {
NOTREACHED();
return nullptr;
}
void RenderWidgetHostViewChildFrame::SetBackgroundColor(SkColor color) {
background_color_ = color;
DCHECK(SkColorGetA(color) == SK_AlphaOPAQUE ||
SkColorGetA(color) == SK_AlphaTRANSPARENT);
host_->SetBackgroundOpaque(SkColorGetA(color) == SK_AlphaOPAQUE);
}
SkColor RenderWidgetHostViewChildFrame::background_color() const {
return background_color_;
}
gfx::Size RenderWidgetHostViewChildFrame::GetPhysicalBackingSize() const {
gfx::Size size;
if (frame_connector_) {
size = gfx::ScaleToCeiledSize(
frame_connector_->ChildFrameRect().size(),
frame_connector_->screen_info().device_scale_factor);
}
return size;
}
void RenderWidgetHostViewChildFrame::InitAsPopup(
RenderWidgetHostView* parent_host_view,
const gfx::Rect& bounds) {
NOTREACHED();
}
void RenderWidgetHostViewChildFrame::InitAsFullscreen(
RenderWidgetHostView* reference_host_view) {
NOTREACHED();
}
void RenderWidgetHostViewChildFrame::UpdateCursor(const WebCursor& cursor) {
if (frame_connector_)
frame_connector_->UpdateCursor(cursor);
}
void RenderWidgetHostViewChildFrame::SetIsLoading(bool is_loading) {
// It is valid for an inner WebContents's SetIsLoading() to end up here.
// This is because an inner WebContents's main frame's RenderWidgetHostView
// is a RenderWidgetHostViewChildFrame. In contrast, when there is no
// inner/outer WebContents, only subframe's RenderWidgetHostView can be a
// RenderWidgetHostViewChildFrame which do not get a SetIsLoading() call.
if (GuestMode::IsCrossProcessFrameGuest(
WebContents::FromRenderViewHost(RenderViewHost::From(host_))))
return;
NOTREACHED();
}
void RenderWidgetHostViewChildFrame::RenderProcessGone(
base::TerminationStatus status,
int error_code) {
if (frame_connector_)
frame_connector_->RenderProcessGone();
Destroy();
}
void RenderWidgetHostViewChildFrame::Destroy() {
// FrameSinkIds registered with RenderWidgetHostInputEventRouter
// have already been cleared when RenderWidgetHostViewBase notified its
// observers of our impending destruction.
if (frame_connector_) {
frame_connector_->SetView(nullptr);
SetFrameConnectorDelegate(nullptr);
}
// We notify our observers about shutdown here since we are about to release
// host_ and do not want any event calls coming from
// RenderWidgetHostInputEventRouter afterwards.
NotifyObserversAboutShutdown();
host_->SetView(nullptr);
host_ = nullptr;
delete this;
}
void RenderWidgetHostViewChildFrame::SetTooltipText(
const base::string16& tooltip_text) {
frame_connector_->GetRootRenderWidgetHostView()->SetTooltipText(tooltip_text);
}
RenderWidgetHostViewBase* RenderWidgetHostViewChildFrame::GetParentView() {
if (!frame_connector_)
return nullptr;
return frame_connector_->GetParentRenderWidgetHostView();
}
void RenderWidgetHostViewChildFrame::RegisterFrameSinkId() {
// If Destroy() has been called before we get here, host_ may be null.
if (host_ && host_->delegate() && host_->delegate()->GetInputEventRouter()) {
RenderWidgetHostInputEventRouter* router =
host_->delegate()->GetInputEventRouter();
if (!router->is_registered(frame_sink_id_))
router->AddFrameSinkIdOwner(frame_sink_id_, this);
}
}
void RenderWidgetHostViewChildFrame::UnregisterFrameSinkId() {
DCHECK(host_);
if (host_->delegate() && host_->delegate()->GetInputEventRouter()) {
host_->delegate()->GetInputEventRouter()->RemoveFrameSinkIdOwner(
frame_sink_id_);
DetachFromTouchSelectionClientManagerIfNecessary();
}
}
void RenderWidgetHostViewChildFrame::UpdateViewportIntersection(
const gfx::Rect& viewport_intersection) {
if (host_)
host_->Send(new ViewMsg_SetViewportIntersection(host_->GetRoutingID(),
viewport_intersection));
}
void RenderWidgetHostViewChildFrame::SetIsInert() {
if (host_ && frame_connector_) {
host_->Send(new ViewMsg_SetIsInert(host_->GetRoutingID(),
frame_connector_->IsInert()));
}
}
void RenderWidgetHostViewChildFrame::GestureEventAck(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
bool should_bubble =
ack_result == INPUT_EVENT_ACK_STATE_NOT_CONSUMED ||
ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS ||
ack_result == INPUT_EVENT_ACK_STATE_CONSUMED_SHOULD_BUBBLE;
if (!frame_connector_)
return;
if (wheel_scroll_latching_enabled()) {
// GestureScrollBegin is a blocking event; It is forwarded for bubbling if
// its ack is not consumed. For the rest of the scroll events
// (GestureScrollUpdate, GestureScrollEnd, GestureFlingStart) the
// frame_connector_ decides to forward them for bubbling if the
// GestureScrollBegin event is forwarded.
if ((event.GetType() == blink::WebInputEvent::kGestureScrollBegin &&
should_bubble) ||
event.GetType() == blink::WebInputEvent::kGestureScrollUpdate ||
event.GetType() == blink::WebInputEvent::kGestureScrollEnd ||
event.GetType() == blink::WebInputEvent::kGestureFlingStart) {
frame_connector_->BubbleScrollEvent(event);
}
} else {
// Consumption of the first GestureScrollUpdate determines whether to
// bubble the sequence of GestureScrollUpdates.
// If the child consumed some scroll, then stopped consuming once it could
// no longer scroll, we don't want to bubble those unconsumed GSUs as we
// want the user to start a new gesture in order to scroll the parent.
// Unfortunately, this is only effective for touch scrolling as wheel
// scrolling wraps GSUs in GSB/GSE pairs.
if (event.GetType() == blink::WebInputEvent::kGestureScrollBegin) {
DCHECK_EQ(NO_ACTIVE_GESTURE_SCROLL, scroll_bubbling_state_);
scroll_bubbling_state_ = AWAITING_FIRST_UPDATE;
} else if (scroll_bubbling_state_ == AWAITING_FIRST_UPDATE &&
event.GetType() == blink::WebInputEvent::kGestureScrollUpdate) {
scroll_bubbling_state_ = (should_bubble ? BUBBLE : SCROLL_CHILD);
} else if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd ||
event.GetType() == blink::WebInputEvent::kGestureFlingStart) {
scroll_bubbling_state_ = NO_ACTIVE_GESTURE_SCROLL;
}
// GestureScrollBegin is consumed by the target frame and not forwarded,
// because we don't know whether we will need to bubble scroll until we
// receive a GestureScrollUpdate ACK. GestureScrollUpdates are forwarded
// for bubbling if the first GSU has unused scroll extent,
// while GestureScrollEnd is always forwarded and handled according to
// current scroll state in the RenderWidgetHostInputEventRouter.
if ((event.GetType() == blink::WebInputEvent::kGestureScrollUpdate &&
scroll_bubbling_state_ == BUBBLE) ||
event.GetType() == blink::WebInputEvent::kGestureScrollEnd ||
event.GetType() == blink::WebInputEvent::kGestureFlingStart) {
frame_connector_->BubbleScrollEvent(event);
}
}
}
void RenderWidgetHostViewChildFrame::DidReceiveCompositorFrameAck(
const std::vector<viz::ReturnedResource>& resources) {
if (renderer_compositor_frame_sink_)
renderer_compositor_frame_sink_->DidReceiveCompositorFrameAck(resources);
}
void RenderWidgetHostViewChildFrame::DidPresentCompositorFrame(
uint32_t presentation_token,
base::TimeTicks time,
base::TimeDelta refresh,
uint32_t flags) {
NOTIMPLEMENTED();
}
void RenderWidgetHostViewChildFrame::DidDiscardCompositorFrame(
uint32_t presentation_token) {
NOTIMPLEMENTED();
}
void RenderWidgetHostViewChildFrame::DidCreateNewRendererCompositorFrameSink(
viz::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink) {
ResetCompositorFrameSinkSupport();
renderer_compositor_frame_sink_ = renderer_compositor_frame_sink;
CreateCompositorFrameSinkSupport();
has_frame_ = false;
}
void RenderWidgetHostViewChildFrame::SetParentFrameSinkId(
const viz::FrameSinkId& parent_frame_sink_id) {
if (parent_frame_sink_id_ == parent_frame_sink_id || IsUsingMus())
return;
auto* host_frame_sink_manager = GetHostFrameSinkManager();
// Unregister hierarchy for the current parent, only if set.
if (parent_frame_sink_id_.is_valid()) {
host_frame_sink_manager->UnregisterFrameSinkHierarchy(parent_frame_sink_id_,
frame_sink_id_);
}
parent_frame_sink_id_ = parent_frame_sink_id;
// Register hierarchy for the new parent, only if set.
if (parent_frame_sink_id_.is_valid()) {
host_frame_sink_manager->RegisterFrameSinkHierarchy(parent_frame_sink_id_,
frame_sink_id_);
}
}
void RenderWidgetHostViewChildFrame::ProcessCompositorFrame(
const viz::LocalSurfaceId& local_surface_id,
viz::CompositorFrame frame) {
current_surface_size_ = frame.size_in_pixels();
current_surface_scale_factor_ = frame.device_scale_factor();
// TODO(kenrb): Supply HitTestRegionList data here as described in
// crbug.com/750755.
bool result = support_->SubmitCompositorFrame(local_surface_id,
std::move(frame), nullptr);
DCHECK(result);
has_frame_ = true;
if (last_received_local_surface_id_ != local_surface_id ||
HasEmbedderChanged()) {
last_received_local_surface_id_ = local_surface_id;
SendSurfaceInfoToEmbedder();
}
if (selection_controller_client_) {
selection_controller_client_->UpdateSelectionBoundsIfNeeded(
frame.metadata.selection, current_device_scale_factor_);
}
ProcessFrameSwappedCallbacks();
}
void RenderWidgetHostViewChildFrame::SendSurfaceInfoToEmbedder() {
if (IsUsingMus())
return;
// TODO(kylechar): Remove sequence generation and only send surface info.
// See https://crbug.com/676384.
viz::SurfaceSequence sequence =
viz::SurfaceSequence(frame_sink_id_, next_surface_sequence_++);
viz::SurfaceManager* manager = GetFrameSinkManager()->surface_manager();
viz::SurfaceId surface_id(frame_sink_id_, last_received_local_surface_id_);
// The renderer process will satisfy this dependency when it creates a
// SurfaceLayer.
if (!manager->using_surface_references())
manager->RequireSequence(surface_id, sequence);
viz::SurfaceInfo surface_info(surface_id, current_surface_scale_factor_,
current_surface_size_);
SendSurfaceInfoToEmbedderImpl(surface_info, sequence);
}
void RenderWidgetHostViewChildFrame::SendSurfaceInfoToEmbedderImpl(
const viz::SurfaceInfo& surface_info,
const viz::SurfaceSequence& sequence) {
frame_connector_->SetChildFrameSurface(surface_info, sequence);
}
void RenderWidgetHostViewChildFrame::SubmitCompositorFrame(
const viz::LocalSurfaceId& local_surface_id,
viz::CompositorFrame frame) {
TRACE_EVENT0("content",
"RenderWidgetHostViewChildFrame::OnSwapCompositorFrame");
last_scroll_offset_ = frame.metadata.root_scroll_offset;
if (!frame_connector_)
return;
ProcessCompositorFrame(local_surface_id, std::move(frame));
}
void RenderWidgetHostViewChildFrame::OnDidNotProduceFrame(
const viz::BeginFrameAck& ack) {
support_->DidNotProduceFrame(ack);
}
void RenderWidgetHostViewChildFrame::ProcessFrameSwappedCallbacks() {
// We only use callbacks once, therefore we make a new list for registration
// before we start, and discard the old list entries when we are done.
FrameSwappedCallbackList process_callbacks;
process_callbacks.swap(frame_swapped_callbacks_);
for (std::unique_ptr<base::Closure>& callback : process_callbacks)
callback->Run();
}
gfx::Rect RenderWidgetHostViewChildFrame::GetBoundsInRootWindow() {
gfx::Rect rect;
if (frame_connector_) {
RenderWidgetHostViewBase* root_view =
frame_connector_->GetRootRenderWidgetHostView();
// The root_view can be null in tests when using a TestWebContents.
if (root_view)
rect = root_view->GetBoundsInRootWindow();
}
return rect;
}
void RenderWidgetHostViewChildFrame::ProcessAckedTouchEvent(
const TouchEventWithLatencyInfo& touch,
InputEventAckState ack_result) {
if (!frame_connector_)
return;
frame_connector_->ForwardProcessAckedTouchEvent(touch, ack_result);
}
void RenderWidgetHostViewChildFrame::DidStopFlinging() {
if (selection_controller_client_)
selection_controller_client_->DidStopFlinging();
}
bool RenderWidgetHostViewChildFrame::LockMouse() {
if (frame_connector_)
return frame_connector_->LockMouse();
return false;
}
void RenderWidgetHostViewChildFrame::UnlockMouse() {
if (host_->delegate() && host_->delegate()->HasMouseLock(host_) &&
frame_connector_)
frame_connector_->UnlockMouse();
}
bool RenderWidgetHostViewChildFrame::IsMouseLocked() {
if (!host_->delegate())
return false;
return host_->delegate()->HasMouseLock(host_);
}
viz::FrameSinkId RenderWidgetHostViewChildFrame::GetFrameSinkId() {
return frame_sink_id_;
}
viz::LocalSurfaceId RenderWidgetHostViewChildFrame::GetLocalSurfaceId() const {
if (frame_connector_)
return frame_connector_->local_surface_id();
return viz::LocalSurfaceId();
}
void RenderWidgetHostViewChildFrame::ProcessKeyboardEvent(
const NativeWebKeyboardEvent& event,
const ui::LatencyInfo& latency) {
host_->ForwardKeyboardEventWithLatencyInfo(event, latency);
}
void RenderWidgetHostViewChildFrame::ProcessMouseEvent(
const blink::WebMouseEvent& event,
const ui::LatencyInfo& latency) {
host_->ForwardMouseEventWithLatencyInfo(event, latency);
}
void RenderWidgetHostViewChildFrame::ProcessMouseWheelEvent(
const blink::WebMouseWheelEvent& event,
const ui::LatencyInfo& latency) {
if (event.delta_x != 0 || event.delta_y != 0 ||
event.phase == blink::WebMouseWheelEvent::kPhaseEnded ||
event.phase == blink::WebMouseWheelEvent::kPhaseCancelled ||
event.momentum_phase == blink::WebMouseWheelEvent::kPhaseEnded ||
event.momentum_phase == blink::WebMouseWheelEvent::kPhaseCancelled)
host_->ForwardWheelEventWithLatencyInfo(event, latency);
}
void RenderWidgetHostViewChildFrame::ProcessTouchEvent(
const blink::WebTouchEvent& event,
const ui::LatencyInfo& latency) {
if (event.GetType() == blink::WebInputEvent::kTouchStart &&
frame_connector_ && !frame_connector_->HasFocus()) {
frame_connector_->FocusRootView();
}
host_->ForwardTouchEventWithLatencyInfo(event, latency);
}
void RenderWidgetHostViewChildFrame::ProcessGestureEvent(
const blink::WebGestureEvent& event,
const ui::LatencyInfo& latency) {
host_->ForwardGestureEventWithLatencyInfo(event, latency);
}
gfx::PointF RenderWidgetHostViewChildFrame::TransformPointToRootCoordSpaceF(
const gfx::PointF& point) {
if (!frame_connector_ || !last_received_local_surface_id_.is_valid())
return point;
return frame_connector_->TransformPointToRootCoordSpace(
point, viz::SurfaceId(frame_sink_id_, last_received_local_surface_id_));
}
bool RenderWidgetHostViewChildFrame::TransformPointToLocalCoordSpace(
const gfx::PointF& point,
const viz::SurfaceId& original_surface,
gfx::PointF* transformed_point) {
*transformed_point = point;
if (!frame_connector_ || !last_received_local_surface_id_.is_valid())
return false;
return frame_connector_->TransformPointToLocalCoordSpace(
point, original_surface,
viz::SurfaceId(frame_sink_id_, last_received_local_surface_id_),
transformed_point);
}
bool RenderWidgetHostViewChildFrame::TransformPointToCoordSpaceForView(
const gfx::PointF& point,
RenderWidgetHostViewBase* target_view,
gfx::PointF* transformed_point) {
if (!frame_connector_ || !last_received_local_surface_id_.is_valid())
return false;
if (target_view == this) {
*transformed_point = point;
return true;
}
return frame_connector_->TransformPointToCoordSpaceForView(
point, target_view,
viz::SurfaceId(frame_sink_id_, last_received_local_surface_id_),
transformed_point);
}
bool RenderWidgetHostViewChildFrame::IsRenderWidgetHostViewChildFrame() {
return true;
}
void RenderWidgetHostViewChildFrame::WillSendScreenRects() {
// TODO(kenrb): These represent post-initialization state updates that are
// needed by the renderer. During normal OOPIF setup these are unnecessary,
// as the parent renderer will send the information and it will be
// immediately propagated to the OOPIF. However when an OOPIF navigates from
// one process to another, the parent doesn't know that, and certain
// browser-side state needs to be sent again. There is probably a less
// spammy way to do this, but triggering on SendScreenRects() is reasonable
// until somebody figures that out. RWHVCF::Init() is too early.
if (frame_connector_) {
UpdateViewportIntersection(frame_connector_->ViewportIntersection());
SetIsInert();
}
}
#if defined(OS_MACOSX)
ui::AcceleratedWidgetMac*
RenderWidgetHostViewChildFrame::GetAcceleratedWidgetMac() const {
return nullptr;
}
void RenderWidgetHostViewChildFrame::SetActive(bool active) {}
void RenderWidgetHostViewChildFrame::ShowDefinitionForSelection() {
if (frame_connector_) {
frame_connector_->GetRootRenderWidgetHostView()
->ShowDefinitionForSelection();
}
}
bool RenderWidgetHostViewChildFrame::SupportsSpeech() const {
return false;
}
void RenderWidgetHostViewChildFrame::SpeakSelection() {}
bool RenderWidgetHostViewChildFrame::IsSpeaking() const {
return false;
}
void RenderWidgetHostViewChildFrame::StopSpeaking() {}
#endif // defined(OS_MACOSX)
void RenderWidgetHostViewChildFrame::RegisterFrameSwappedCallback(
std::unique_ptr<base::Closure> callback) {
frame_swapped_callbacks_.push_back(std::move(callback));
}
void RenderWidgetHostViewChildFrame::CopyFromSurface(
const gfx::Rect& src_rect,
const gfx::Size& output_size,
const ReadbackRequestCallback& callback,
const SkColorType preferred_color_type) {
if (!IsSurfaceAvailableForCopy()) {
// Defer submitting the copy request until after a frame is drawn, at which
// point we should be guaranteed that the surface is available.
RegisterFrameSwappedCallback(std::make_unique<base::Closure>(base::Bind(
&RenderWidgetHostViewChildFrame::SubmitSurfaceCopyRequest, AsWeakPtr(),
src_rect, output_size, callback, preferred_color_type)));
return;
}
SubmitSurfaceCopyRequest(src_rect, output_size, callback,
preferred_color_type);
}
void RenderWidgetHostViewChildFrame::SubmitSurfaceCopyRequest(
const gfx::Rect& src_subrect,
const gfx::Size& output_size,
const ReadbackRequestCallback& callback,
const SkColorType preferred_color_type) {
DCHECK(IsSurfaceAvailableForCopy());
DCHECK(support_);
std::unique_ptr<viz::CopyOutputRequest> request =
std::make_unique<viz::CopyOutputRequest>(
viz::CopyOutputRequest::ResultFormat::RGBA_TEXTURE,
base::BindOnce(&CopyFromCompositingSurfaceHasResult, output_size,
preferred_color_type, callback));
if (!src_subrect.IsEmpty())
request->set_area(src_subrect);
support_->RequestCopyOfSurface(std::move(request));
}
bool RenderWidgetHostViewChildFrame::HasAcceleratedSurface(
const gfx::Size& desired_size) {
return false;
}
void RenderWidgetHostViewChildFrame::ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) {
if (renderer_compositor_frame_sink_)
renderer_compositor_frame_sink_->ReclaimResources(resources);
}
void RenderWidgetHostViewChildFrame::OnBeginFrame(
const viz::BeginFrameArgs& args) {
if (renderer_compositor_frame_sink_)
renderer_compositor_frame_sink_->OnBeginFrame(args);
}
void RenderWidgetHostViewChildFrame::OnBeginFramePausedChanged(bool paused) {
if (renderer_compositor_frame_sink_)
renderer_compositor_frame_sink_->OnBeginFramePausedChanged(paused);
}
void RenderWidgetHostViewChildFrame::OnFirstSurfaceActivation(
const viz::SurfaceInfo& surface_info) {
viz::SurfaceSequence sequence(frame_sink_id_, next_surface_sequence_++);
SendSurfaceInfoToEmbedderImpl(surface_info, sequence);
}
void RenderWidgetHostViewChildFrame::SetNeedsBeginFrames(
bool needs_begin_frames) {
if (support_)
support_->SetNeedsBeginFrame(needs_begin_frames);
}
InputEventAckState RenderWidgetHostViewChildFrame::FilterInputEvent(
const blink::WebInputEvent& input_event) {
if (input_event.GetType() == blink::WebInputEvent::kGestureFlingStart) {
const blink::WebGestureEvent& gesture_event =
static_cast<const blink::WebGestureEvent&>(input_event);
// Zero-velocity touchpad flings are an Aura-specific signal that the
// touchpad scroll has ended, and should not be forwarded to the renderer.
if (gesture_event.source_device == blink::kWebGestureDeviceTouchpad &&
!gesture_event.data.fling_start.velocity_x &&
!gesture_event.data.fling_start.velocity_y) {
// Here we indicate that there was no consumer for this event, as
// otherwise the fling animation system will try to run an animation
// and will also expect a notification when the fling ends. Since
// CrOS just uses the GestureFlingStart with zero-velocity as a means
// of indicating that touchpad scroll has ended, we don't actually want
// a fling animation.
// Note: this event handling is modeled on similar code in
// TenderWidgetHostViewAura::FilterInputEvent().
return INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
}
}
// Allow the root RWHV a chance to consume the child's GestureScrollUpdates
// in case the root needs to prevent the child from scrolling. For example,
// if the root has started an overscroll gesture, it needs to process the
// scroll events that would normally be processed by the child.
// TODO(mcnee): With scroll-latching enabled, the child would not scroll
// in this case. Remove this once scroll-latching lands. crbug.com/751782
if (!wheel_scroll_latching_enabled() && frame_connector_ &&
input_event.GetType() == blink::WebInputEvent::kGestureScrollUpdate) {
const blink::WebGestureEvent& gesture_event =
static_cast<const blink::WebGestureEvent&>(input_event);
return frame_connector_->GetRootRenderWidgetHostView()
->FilterChildGestureEvent(gesture_event);
}
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
InputEventAckState RenderWidgetHostViewChildFrame::FilterChildGestureEvent(
const blink::WebGestureEvent& gesture_event) {
// We may be the owner of a RenderWidgetHostViewGuest,
// so we talk to the root RWHV on its behalf.
// TODO(mcnee): Remove once MimeHandlerViewGuest is based on OOPIF.
// See crbug.com/659750
if (frame_connector_)
return frame_connector_->GetRootRenderWidgetHostView()
->FilterChildGestureEvent(gesture_event);
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
BrowserAccessibilityManager*
RenderWidgetHostViewChildFrame::CreateBrowserAccessibilityManager(
BrowserAccessibilityDelegate* delegate,
bool for_root_frame) {
return BrowserAccessibilityManager::Create(
BrowserAccessibilityManager::GetEmptyDocument(), delegate);
}
void RenderWidgetHostViewChildFrame::GetScreenInfo(ScreenInfo* screen_info) {
if (frame_connector_)
*screen_info = frame_connector_->screen_info();
}
void RenderWidgetHostViewChildFrame::ResizeDueToAutoResize(
const gfx::Size& new_size,
uint64_t sequence_number) {
if (frame_connector_)
frame_connector_->ResizeDueToAutoResize(new_size, sequence_number);
}
void RenderWidgetHostViewChildFrame::ClearCompositorSurfaceIfNecessary() {
if (!support_)
return;
support_->EvictCurrentSurface();
has_frame_ = false;
}
bool RenderWidgetHostViewChildFrame::IsChildFrameForTesting() const {
return true;
}
viz::SurfaceId RenderWidgetHostViewChildFrame::SurfaceIdForTesting() const {
return viz::SurfaceId(frame_sink_id_, last_received_local_surface_id_);
}
void RenderWidgetHostViewChildFrame::CreateCompositorFrameSinkSupport() {
if (IsUsingMus())
return;
DCHECK(!support_);
constexpr bool is_root = false;
constexpr bool needs_sync_points = true;
support_ = GetHostFrameSinkManager()->CreateCompositorFrameSinkSupport(
this, frame_sink_id_, is_root, needs_sync_points);
if (parent_frame_sink_id_.is_valid()) {
GetHostFrameSinkManager()->RegisterFrameSinkHierarchy(parent_frame_sink_id_,
frame_sink_id_);
}
if (host_->needs_begin_frames())
support_->SetNeedsBeginFrame(true);
}
void RenderWidgetHostViewChildFrame::ResetCompositorFrameSinkSupport() {
if (!support_)
return;
if (parent_frame_sink_id_.is_valid()) {
GetHostFrameSinkManager()->UnregisterFrameSinkHierarchy(
parent_frame_sink_id_, frame_sink_id_);
}
support_.reset();
}
bool RenderWidgetHostViewChildFrame::HasEmbedderChanged() {
return false;
}
bool RenderWidgetHostViewChildFrame::GetSelectionRange(
gfx::Range* range) const {
if (!text_input_manager_ || !GetFocusedWidget())
return false;
const TextInputManager::TextSelection* selection =
text_input_manager_->GetTextSelection(GetFocusedWidget()->GetView());
if (!selection)
return false;
range->set_start(selection->range().start());
range->set_end(selection->range().end());
return true;
}
ui::TextInputType RenderWidgetHostViewChildFrame::GetTextInputType() const {
if (!text_input_manager_)
return ui::TEXT_INPUT_TYPE_NONE;
if (text_input_manager_->GetTextInputState())
return text_input_manager_->GetTextInputState()->type;
return ui::TEXT_INPUT_TYPE_NONE;
}
gfx::Point RenderWidgetHostViewChildFrame::GetViewOriginInRoot() const {
if (frame_connector_) {
auto origin = GetViewBounds().origin() -
frame_connector_->GetRootRenderWidgetHostView()
->GetViewBounds()
.origin();
return gfx::Point(origin.x(), origin.y());
}
return gfx::Point();
}
RenderWidgetHostViewBase*
RenderWidgetHostViewChildFrame::GetRootRenderWidgetHostView() const {
return frame_connector_ ? frame_connector_->GetRootRenderWidgetHostView()
: nullptr;
}
bool RenderWidgetHostViewChildFrame::CanBecomeVisible() {
if (!frame_connector_)
return true;
if (frame_connector_->IsHidden())
return false;
RenderWidgetHostViewBase* parent_view = GetParentView();
if (!parent_view || !parent_view->IsRenderWidgetHostViewChildFrame()) {
// Root frame does not have a CSS visibility property.
return true;
}
return static_cast<RenderWidgetHostViewChildFrame*>(parent_view)
->CanBecomeVisible();
}
// static
bool RenderWidgetHostViewChildFrame::IsUsingMus() {
#if defined(USE_AURA)
return aura::Env::GetInstance()->mode() == aura::Env::Mode::MUS;
#else
return false;
#endif
}
} // namespace content