blob: 642e95614d6c873cec67bba7abe50dc81e72f860 [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_aura.h"
#include <set>
#include <utility>
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "cc/layers/layer.h"
#include "cc/trees/layer_tree_settings.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/common/surfaces/local_surface_id_allocation.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include "content/browser/bad_message.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/cursor_manager.h"
#include "content/browser/renderer_host/delegated_frame_host_client_aura.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target_aura.h"
#include "content/browser/renderer_host/input/touch_selection_controller_client_aura.h"
#include "content/browser/renderer_host/overscroll_controller.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_view_host_delegate_view.h"
#include "content/browser/renderer_host/render_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/ui_events_helper.h"
#include "content/common/input_messages.h"
#include "content/common/render_widget_window_tree_client_factory.mojom.h"
#include "content/common/text_input_state.h"
#include "content/common/view_messages.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/overscroll_configuration.h"
#include "content/public/browser/render_view_host.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 "services/service_manager/public/cpp/interface_provider.h"
#include "services/ws/common/switches.h"
#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "third_party/blink/public/platform/web_input_event.h"
#include "third_party/blink/public/web/web_ime_text_span.h"
#include "ui/accessibility/platform/aura_window_properties.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/cursor_client_observer.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/client/transient_window_client.h"
#include "ui/aura/client/window_parenting_client.h"
#include "ui/aura/env.h"
#include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/hit_test.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/base/ui_base_switches_util.h"
#include "ui/base/ui_base_types.h"
#include "ui/compositor/compositor_vsync_manager.h"
#include "ui/compositor/dip_util.h"
#include "ui/display/screen.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/blink/did_overscroll_params.h"
#include "ui/events/blink/web_input_event.h"
#include "ui/events/event.h"
#include "ui/events/event_observer.h"
#include "ui/events/event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/gestures/gesture_recognizer.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/skia_util.h"
#include "ui/touch_selection/touch_selection_controller.h"
#include "ui/wm/core/coordinate_conversion.h"
#include "ui/wm/core/window_util.h"
#include "ui/wm/public/activation_client.h"
#include "ui/wm/public/scoped_tooltip_disabler.h"
#include "ui/wm/public/tooltip_client.h"
#if defined(OS_WIN)
#include "base/time/time.h"
#include "content/browser/accessibility/browser_accessibility_manager_win.h"
#include "content/browser/accessibility/browser_accessibility_win.h"
#include "content/browser/renderer_host/legacy_render_widget_host_win.h"
#include "ui/base/ime/input_method_keyboard_controller.h"
#include "ui/base/ime/input_method_keyboard_controller_observer.h"
#include "ui/base/win/hidden_window.h"
#include "ui/display/win/screen_win.h"
#include "ui/gfx/gdi_util.h"
#endif
#if defined(USE_X11)
#include "content/browser/accessibility/browser_accessibility_auralinux.h"
#endif
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
#include "ui/base/ime/linux/text_edit_command_auralinux.h"
#include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h"
#endif
#if defined(OS_CHROMEOS)
#include "ui/wm/core/ime_util_chromeos.h"
#endif
#if defined(OS_FUCHSIA)
#include "ui/base/ime/input_method_keyboard_controller.h"
#endif
using gfx::RectToSkIRect;
using gfx::SkIRectToRect;
using blink::WebInputEvent;
using blink::WebGestureEvent;
using blink::WebTouchEvent;
namespace content {
namespace {
// Callback from embedding the renderer.
void EmbedCallback(bool result) {
if (!result)
DVLOG(1) << "embed failed";
}
} // namespace
#if defined(OS_WIN)
// This class implements the ui::InputMethodKeyboardControllerObserver interface
// which provides notifications about the on screen keyboard on Windows getting
// displayed or hidden in response to taps on editable fields.
// It provides functionality to request blink to scroll the input field if it
// is obscured by the on screen keyboard.
class WinScreenKeyboardObserver
: public ui::InputMethodKeyboardControllerObserver {
public:
WinScreenKeyboardObserver(RenderWidgetHostViewAura* host_view)
: host_view_(host_view) {
host_view_->SetInsets(gfx::Insets());
if (auto* input_method = host_view_->GetInputMethod())
input_method->GetInputMethodKeyboardController()->AddObserver(this);
}
~WinScreenKeyboardObserver() override {
if (auto* input_method = host_view_->GetInputMethod())
input_method->GetInputMethodKeyboardController()->RemoveObserver(this);
}
// InputMethodKeyboardControllerObserver overrides.
void OnKeyboardVisible(const gfx::Rect& keyboard_rect) override {
host_view_->SetInsets(gfx::Insets(
0, 0, keyboard_rect.IsEmpty() ? 0 : keyboard_rect.height(), 0));
}
void OnKeyboardHidden() override {
// Restore the viewport.
host_view_->SetInsets(gfx::Insets());
}
private:
RenderWidgetHostViewAura* host_view_;
DISALLOW_COPY_AND_ASSIGN(WinScreenKeyboardObserver);
};
#endif // defined(OS_WIN)
// We need to watch for mouse events outside a Web Popup or its parent
// and dismiss the popup for certain events.
class RenderWidgetHostViewAura::EventObserverForPopupExit
: public ui::EventObserver {
public:
explicit EventObserverForPopupExit(RenderWidgetHostViewAura* rwhva)
: rwhva_(rwhva) {
aura::Env* env = aura::Env::GetInstance();
env->AddEventObserver(this, env,
{ui::ET_MOUSE_PRESSED, ui::ET_TOUCH_PRESSED});
}
~EventObserverForPopupExit() override {
aura::Env::GetInstance()->RemoveEventObserver(this);
}
// ui::EventObserver:
void OnEvent(const ui::Event& event) override {
rwhva_->ApplyEventObserverForPopupExit(*event.AsLocatedEvent());
}
private:
RenderWidgetHostViewAura* rwhva_;
DISALLOW_COPY_AND_ASSIGN(EventObserverForPopupExit);
};
void RenderWidgetHostViewAura::ApplyEventObserverForPopupExit(
const ui::LocatedEvent& event) {
DCHECK(event.type() == ui::ET_MOUSE_PRESSED ||
event.type() == ui::ET_TOUCH_PRESSED);
if (in_shutdown_ || is_fullscreen_)
return;
// |target| may be null.
aura::Window* target = static_cast<aura::Window*>(event.target());
if (target != window_ &&
(!popup_parent_host_view_ ||
target != popup_parent_host_view_->window_)) {
// If we enter this code path it means that we did not receive any focus
// lost notifications for the popup window. Ensure that blink is aware
// of the fact that focus was lost for the host window by sending a Blur
// notification. We also set a flag in the view indicating that we need
// to force a Focus notification on the next mouse down.
if (popup_parent_host_view_ && popup_parent_host_view_->host()) {
popup_parent_host_view_->event_handler()
->set_focus_on_mouse_down_or_key_event(true);
popup_parent_host_view_->host()->Blur();
}
// Note: popup_parent_host_view_ may be NULL when there are multiple
// popup children per view. See: RenderWidgetHostViewAura::InitAsPopup().
Shutdown();
}
}
// We have to implement the WindowObserver interface on a separate object
// because clang doesn't like implementing multiple interfaces that have
// methods with the same name. This object is owned by the
// RenderWidgetHostViewAura.
class RenderWidgetHostViewAura::WindowObserver : public aura::WindowObserver {
public:
explicit WindowObserver(RenderWidgetHostViewAura* view)
: view_(view) {
view_->window_->AddObserver(this);
}
~WindowObserver() override { view_->window_->RemoveObserver(this); }
// Overridden from aura::WindowObserver:
void OnWindowAddedToRootWindow(aura::Window* window) override {
if (window == view_->window_)
view_->AddedToRootWindow();
}
void OnWindowRemovingFromRootWindow(aura::Window* window,
aura::Window* new_root) override {
if (window == view_->window_)
view_->RemovingFromRootWindow();
}
void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override {
view_->ParentHierarchyChanged();
}
void OnWindowTitleChanged(aura::Window* window) override {
if (window == view_->window_)
view_->WindowTitleChanged();
}
private:
RenderWidgetHostViewAura* view_;
DISALLOW_COPY_AND_ASSIGN(WindowObserver);
};
// This class provides functionality to observe the ancestors of the RWHVA for
// bounds changes. This is done to snap the RWHVA window to a pixel boundary,
// which could change when the bounds relative to the root changes.
// An example where this happens is below:-
// The fast resize code path for bookmarks where in the parent of RWHVA which
// is WCV has its bounds changed before the bookmark is hidden. This results in
// the traditional bounds change notification for the WCV reporting the old
// bounds as the bookmark is still around. Observing all the ancestors of the
// RWHVA window enables us to know when the bounds of the window relative to
// root changes and allows us to snap accordingly.
class RenderWidgetHostViewAura::WindowAncestorObserver
: public aura::WindowObserver {
public:
explicit WindowAncestorObserver(RenderWidgetHostViewAura* view)
: view_(view) {
aura::Window* parent = view_->window_->parent();
while (parent) {
parent->AddObserver(this);
ancestors_.insert(parent);
parent = parent->parent();
}
}
~WindowAncestorObserver() override {
RemoveAncestorObservers();
}
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override {
DCHECK(ancestors_.find(window) != ancestors_.end());
if (new_bounds.origin() != old_bounds.origin())
view_->HandleParentBoundsChanged();
}
private:
void RemoveAncestorObservers() {
for (auto* ancestor : ancestors_)
ancestor->RemoveObserver(this);
ancestors_.clear();
}
RenderWidgetHostViewAura* view_;
std::set<aura::Window*> ancestors_;
DISALLOW_COPY_AND_ASSIGN(WindowAncestorObserver);
};
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, public:
RenderWidgetHostViewAura::RenderWidgetHostViewAura(
RenderWidgetHost* widget_host,
bool is_guest_view_hack,
bool is_mus_browser_plugin_guest)
: RenderWidgetHostViewBase(widget_host),
is_mus_browser_plugin_guest_(is_mus_browser_plugin_guest),
window_(nullptr),
in_shutdown_(false),
in_bounds_changed_(false),
popup_parent_host_view_(nullptr),
popup_child_host_view_(nullptr),
is_loading_(false),
has_composition_text_(false),
needs_begin_frames_(false),
added_frame_observer_(false),
cursor_visibility_state_in_renderer_(UNKNOWN),
#if defined(OS_WIN)
legacy_render_widget_host_HWND_(nullptr),
legacy_window_destroyed_(false),
virtual_keyboard_requested_(false),
#endif
has_snapped_to_boundary_(false),
is_guest_view_hack_(is_guest_view_hack),
device_scale_factor_(0.0f),
event_handler_(new RenderWidgetHostViewEventHandler(host(), this, this)),
frame_sink_id_(features::IsMultiProcessMash()
? viz::FrameSinkId()
: is_guest_view_hack_
? AllocateFrameSinkIdForGuestViewHack()
: host()->GetFrameSinkId()),
weak_ptr_factory_(this) {
if (!is_mus_browser_plugin_guest_)
CreateDelegatedFrameHostClient();
if (!is_guest_view_hack_)
host()->SetView(this);
// We should start observing the TextInputManager for IME-related events as
// well as monitoring its lifetime.
if (GetTextInputManager())
GetTextInputManager()->AddObserver(this);
cursor_manager_.reset(new CursorManager(this));
SetOverscrollControllerEnabled(
OverscrollConfig::GetHistoryNavigationMode() !=
OverscrollConfig::HistoryNavigationMode::kDisabled);
selection_controller_client_.reset(
new TouchSelectionControllerClientAura(this));
CreateSelectionController();
RenderViewHost* rvh = RenderViewHost::From(host());
if (rvh) {
// TODO(mostynb): actually use prefs. Landing this as a separate CL
// first to rebaseline some unreliable web tests.
ignore_result(rvh->GetWebkitPreferences());
}
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, RenderWidgetHostView implementation:
void RenderWidgetHostViewAura::InitAsChild(gfx::NativeView parent_view) {
DCHECK_EQ(widget_type_, WidgetType::kFrame);
if (is_mus_browser_plugin_guest_)
return;
CreateAuraWindow(aura::client::WINDOW_TYPE_CONTROL);
if (parent_view)
parent_view->AddChild(GetNativeView());
device_scale_factor_ = GetDeviceScaleFactor();
}
void RenderWidgetHostViewAura::InitAsPopup(
RenderWidgetHostView* parent_host_view,
const gfx::Rect& bounds_in_screen) {
DCHECK_EQ(widget_type_, WidgetType::kPopup);
// Popups never have |is_mus_browser_plugin_guest_| set to true.
DCHECK(!is_mus_browser_plugin_guest_);
popup_parent_host_view_ =
static_cast<RenderWidgetHostViewAura*>(parent_host_view);
// TransientWindowClient may be NULL during tests.
aura::client::TransientWindowClient* transient_window_client =
aura::client::GetTransientWindowClient();
RenderWidgetHostViewAura* old_child =
popup_parent_host_view_->popup_child_host_view_;
if (old_child) {
// TODO(jhorwich): Allow multiple popup_child_host_view_ per view, or
// similar mechanism to ensure a second popup doesn't cause the first one
// to never get a chance to filter events. See crbug.com/160589.
DCHECK(old_child->popup_parent_host_view_ == popup_parent_host_view_);
if (transient_window_client) {
transient_window_client->RemoveTransientChild(
popup_parent_host_view_->window_, old_child->window_);
}
old_child->popup_parent_host_view_ = nullptr;
}
popup_parent_host_view_->SetPopupChild(this);
CreateAuraWindow(aura::client::WINDOW_TYPE_MENU);
// Setting the transient child allows for the popup to get mouse events when
// in a system modal dialog. Do this before calling ParentWindowWithContext
// below so that the transient parent is visible to WindowTreeClient.
// This fixes crbug.com/328593.
if (transient_window_client) {
transient_window_client->AddTransientChild(
popup_parent_host_view_->window_, window_);
}
aura::Window* root = popup_parent_host_view_->window_->GetRootWindow();
aura::client::ParentWindowWithContext(window_, root, bounds_in_screen);
SetBounds(bounds_in_screen);
Show();
if (NeedsMouseCapture())
window_->SetCapture();
event_observer_for_popup_exit_ =
std::make_unique<EventObserverForPopupExit>(this);
device_scale_factor_ = GetDeviceScaleFactor();
}
void RenderWidgetHostViewAura::InitAsFullscreen(
RenderWidgetHostView* reference_host_view) {
DCHECK_EQ(widget_type_, WidgetType::kFrame);
// Webview Fullscreen doesn't go through InitAsFullscreen(), so
// |is_mus_browser_plugin_guest_| is always false.
DCHECK(!is_mus_browser_plugin_guest_);
is_fullscreen_ = true;
CreateAuraWindow(aura::client::WINDOW_TYPE_NORMAL);
window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
aura::Window* parent = nullptr;
gfx::Rect bounds;
if (reference_host_view) {
aura::Window* reference_window =
static_cast<RenderWidgetHostViewAura*>(reference_host_view)->window_;
event_handler_->TrackHost(reference_window);
display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(reference_window);
parent = reference_window->GetRootWindow();
bounds = display.bounds();
}
aura::client::ParentWindowWithContext(window_, parent, bounds);
Show();
Focus();
device_scale_factor_ = GetDeviceScaleFactor();
}
void RenderWidgetHostViewAura::Show() {
if (is_mus_browser_plugin_guest_)
return;
// If the viz::LocalSurfaceIdAllocation is invalid, we may have been evicted,
// and no other visual properties have since been changed. Allocate a new id
// and start synchronizing.
if (!window_->GetLocalSurfaceIdAllocation().IsValid()) {
window_->AllocateLocalSurfaceId();
SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
window_->GetLocalSurfaceIdAllocation());
}
window_->Show();
WasUnOccluded();
}
void RenderWidgetHostViewAura::Hide() {
if (is_mus_browser_plugin_guest_)
return;
window_->Hide();
WasOccluded();
}
void RenderWidgetHostViewAura::SetSize(const gfx::Size& size) {
DCHECK(!is_mus_browser_plugin_guest_);
// For a SetSize operation, we don't care what coordinate system the origin
// of the window is in, it's only important to make sure that the origin
// remains constant after the operation.
InternalSetBounds(gfx::Rect(window_->bounds().origin(), size));
}
void RenderWidgetHostViewAura::SetBounds(const gfx::Rect& rect) {
DCHECK(!is_mus_browser_plugin_guest_);
gfx::Point relative_origin(rect.origin());
// RenderWidgetHostViewAura::SetBounds() takes screen coordinates, but
// Window::SetBounds() takes parent coordinates, so do the conversion here.
aura::Window* root = window_->GetRootWindow();
if (root) {
aura::client::ScreenPositionClient* screen_position_client =
aura::client::GetScreenPositionClient(root);
if (screen_position_client) {
screen_position_client->ConvertPointFromScreen(window_->parent(),
&relative_origin);
}
}
InternalSetBounds(gfx::Rect(relative_origin, rect.size()));
}
gfx::NativeView RenderWidgetHostViewAura::GetNativeView() const {
DCHECK(!is_mus_browser_plugin_guest_);
return window_;
}
#if defined(OS_WIN)
HWND RenderWidgetHostViewAura::GetHostWindowHWND() const {
aura::WindowTreeHost* host = window_->GetHost();
return host ? host->GetAcceleratedWidget() : nullptr;
}
#endif
gfx::NativeViewAccessible RenderWidgetHostViewAura::GetNativeViewAccessible() {
#if defined(OS_WIN)
aura::WindowTreeHost* window_host = window_->GetHost();
if (!window_host)
return static_cast<gfx::NativeViewAccessible>(NULL);
BrowserAccessibilityManager* manager =
host()->GetOrCreateRootBrowserAccessibilityManager();
if (manager)
return ToBrowserAccessibilityWin(manager->GetRoot())->GetCOM();
#elif defined(USE_X11)
BrowserAccessibilityManager* manager =
host()->GetOrCreateRootBrowserAccessibilityManager();
if (manager && manager->GetRoot())
return manager->GetRoot()->GetNativeViewAccessible();
#endif
NOTIMPLEMENTED_LOG_ONCE();
return static_cast<gfx::NativeViewAccessible>(nullptr);
}
ui::TextInputClient* RenderWidgetHostViewAura::GetTextInputClient() {
return this;
}
void RenderWidgetHostViewAura::SetNeedsBeginFrames(bool needs_begin_frames) {
needs_begin_frames_ = needs_begin_frames;
UpdateNeedsBeginFramesInternal();
}
void RenderWidgetHostViewAura::SetWantsAnimateOnlyBeginFrames() {
if (delegated_frame_host_)
delegated_frame_host_->SetWantsAnimateOnlyBeginFrames();
}
void RenderWidgetHostViewAura::OnBeginFrame(base::TimeTicks frame_time) {
host()->ProgressFlingIfNeeded(frame_time);
UpdateNeedsBeginFramesInternal();
}
RenderFrameHostImpl* RenderWidgetHostViewAura::GetFocusedFrame() const {
RenderViewHost* rvh = RenderViewHost::From(host());
if (!rvh)
return nullptr;
FrameTreeNode* focused_frame =
rvh->GetDelegate()->GetFrameTree()->GetFocusedFrame();
if (!focused_frame)
return nullptr;
return focused_frame->current_frame_host();
}
void RenderWidgetHostViewAura::HandleParentBoundsChanged() {
SnapToPhysicalPixelBoundary();
#if defined(OS_WIN)
if (legacy_render_widget_host_HWND_) {
legacy_render_widget_host_HWND_->SetBounds(
window_->GetBoundsInRootWindow());
}
#endif
if (!in_shutdown_) {
// Send screen rects through the delegate if there is one. Not every
// RenderWidgetHost has a delegate (for example, drop-down widgets).
if (host_->delegate())
host_->delegate()->SendScreenRects();
else
host_->SendScreenRects();
}
}
void RenderWidgetHostViewAura::ParentHierarchyChanged() {
ancestor_window_observer_.reset(new WindowAncestorObserver(this));
// Snap when we receive a hierarchy changed. http://crbug.com/388908.
HandleParentBoundsChanged();
}
void RenderWidgetHostViewAura::Focus() {
// Make sure we have a FocusClient before attempting to Focus(). In some
// situations we may not yet be in a valid Window hierarchy (such as reloading
// after out of memory discarded the tab).
aura::client::FocusClient* client = aura::client::GetFocusClient(window_);
if (client)
window_->Focus();
}
bool RenderWidgetHostViewAura::HasFocus() const {
return window_->HasFocus();
}
bool RenderWidgetHostViewAura::IsSurfaceAvailableForCopy() const {
if (!delegated_frame_host_)
return false;
return delegated_frame_host_->CanCopyFromCompositingSurface();
}
void RenderWidgetHostViewAura::EnsureSurfaceSynchronizedForWebTest() {
++latest_capture_sequence_number_;
SynchronizeVisualProperties(cc::DeadlinePolicy::UseInfiniteDeadline(),
base::nullopt);
}
bool RenderWidgetHostViewAura::IsShowing() {
return window_->IsVisible();
}
void RenderWidgetHostViewAura::WasUnOccluded() {
if (!host_->is_hidden())
return;
bool has_saved_frame =
delegated_frame_host_ ? delegated_frame_host_->HasSavedFrame() : false;
const bool renderer_should_record_presentation_time = !has_saved_frame;
host()->WasShown(renderer_should_record_presentation_time);
aura::Window* root = window_->GetRootWindow();
if (root) {
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(root);
if (cursor_client)
NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible());
}
if (delegated_frame_host_) {
// If the frame for the renderer is already available, then the
// tab-switching time is the presentation time for the browser-compositor.
const bool record_presentation_time = has_saved_frame;
delegated_frame_host_->WasShown(
GetLocalSurfaceIdAllocation().local_surface_id(),
window_->bounds().size(), record_presentation_time);
}
#if defined(OS_WIN)
UpdateLegacyWin();
#endif
}
void RenderWidgetHostViewAura::WasOccluded() {
if (!host()->is_hidden()) {
host()->WasHidden();
if (delegated_frame_host_)
delegated_frame_host_->WasHidden();
#if defined(OS_WIN)
aura::WindowTreeHost* host = window_->GetHost();
if (host) {
// We reparent the legacy Chrome_RenderWidgetHostHWND window to the global
// hidden window on the same lines as Windowed plugin windows.
if (legacy_render_widget_host_HWND_)
legacy_render_widget_host_HWND_->UpdateParent(ui::GetHiddenWindow());
}
#endif
}
#if defined(OS_WIN)
if (legacy_render_widget_host_HWND_)
legacy_render_widget_host_HWND_->Hide();
#endif
}
gfx::Rect RenderWidgetHostViewAura::GetViewBounds() const {
return window_->GetBoundsInScreen();
}
void RenderWidgetHostViewAura::UpdateBackgroundColor() {
DCHECK(GetBackgroundColor());
SkColor color = *GetBackgroundColor();
bool opaque = SkColorGetA(color) == SK_AlphaOPAQUE;
window_->layer()->SetFillsBoundsOpaquely(opaque);
window_->layer()->SetColor(color);
}
void RenderWidgetHostViewAura::WindowTitleChanged() {
if (delegated_frame_host_) {
delegated_frame_host_->WindowTitleChanged(
base::UTF16ToUTF8(window_->GetTitle()));
}
}
bool RenderWidgetHostViewAura::IsMouseLocked() {
return event_handler_->mouse_locked();
}
gfx::Size RenderWidgetHostViewAura::GetVisibleViewportSize() const {
gfx::Rect requested_rect(GetRequestedRendererSize());
requested_rect.Inset(insets_);
return requested_rect.size();
}
void RenderWidgetHostViewAura::SetInsets(const gfx::Insets& insets) {
if (insets != insets_) {
insets_ = insets;
host()->SynchronizeVisualProperties(!insets_.IsEmpty());
}
}
void RenderWidgetHostViewAura::FocusedNodeTouched(bool editable) {
#if defined(OS_WIN)
auto* input_method = GetInputMethod();
if (!input_method || !input_method->GetInputMethodKeyboardController())
return;
auto* controller = input_method->GetInputMethodKeyboardController();
if (editable && host()->GetView() && host()->delegate()) {
if (last_pointer_type_ == ui::EventPointerType::POINTER_TYPE_TOUCH) {
keyboard_observer_.reset(new WinScreenKeyboardObserver(this));
if (!controller->DisplayVirtualKeyboard())
keyboard_observer_.reset(nullptr);
} else {
keyboard_observer_.reset(nullptr);
}
virtual_keyboard_requested_ = keyboard_observer_.get();
} else {
virtual_keyboard_requested_ = false;
controller->DismissVirtualKeyboard();
}
#endif
}
void RenderWidgetHostViewAura::UpdateCursor(const WebCursor& cursor) {
GetCursorManager()->UpdateCursor(this, cursor);
}
void RenderWidgetHostViewAura::DisplayCursor(const WebCursor& cursor) {
current_cursor_ = cursor;
const display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
current_cursor_.SetDisplayInfo(display);
UpdateCursorIfOverSelf();
}
CursorManager* RenderWidgetHostViewAura::GetCursorManager() {
return cursor_manager_.get();
}
void RenderWidgetHostViewAura::SetIsLoading(bool is_loading) {
is_loading_ = is_loading;
UpdateCursorIfOverSelf();
}
void RenderWidgetHostViewAura::RenderProcessGone(base::TerminationStatus status,
int error_code) {
UpdateCursorIfOverSelf();
Destroy();
}
void RenderWidgetHostViewAura::Destroy() {
// Beware, this function is not called on all destruction paths. If |window_|
// has been created, then it will implicitly end up calling
// ~RenderWidgetHostViewAura when |window_| is destroyed. Otherwise, The
// destructor is invoked directly from here. So all destruction/cleanup code
// should happen there, not here.
in_shutdown_ = true;
if (window_)
delete window_;
else
delete this;
}
void RenderWidgetHostViewAura::SetTooltipText(
const base::string16& tooltip_text) {
GetCursorManager()->SetTooltipTextForView(this, tooltip_text);
}
void RenderWidgetHostViewAura::DisplayTooltipText(
const base::string16& tooltip_text) {
tooltip_ = tooltip_text;
aura::Window* root_window = window_->GetRootWindow();
wm::TooltipClient* tooltip_client = wm::GetTooltipClient(root_window);
if (tooltip_client) {
tooltip_client->UpdateTooltip(window_);
// Content tooltips should be visible indefinitely.
tooltip_client->SetTooltipShownTimeout(window_, 0);
}
}
uint32_t RenderWidgetHostViewAura::GetCaptureSequenceNumber() const {
return latest_capture_sequence_number_;
}
bool RenderWidgetHostViewAura::DoBrowserControlsShrinkRendererSize() const {
return host()->delegate() &&
host()->delegate()->DoBrowserControlsShrinkRendererSize();
}
float RenderWidgetHostViewAura::GetTopControlsHeight() const {
return host()->delegate() ? host()->delegate()->GetTopControlsHeight() : 0;
}
void RenderWidgetHostViewAura::CopyFromSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
base::OnceCallback<void(const SkBitmap&)> callback) {
base::WeakPtr<RenderWidgetHostImpl> popup_host;
base::WeakPtr<DelegatedFrameHost> popup_frame_host;
if (popup_child_host_view_) {
popup_host = popup_child_host_view_->host()->GetWeakPtr();
popup_frame_host =
popup_child_host_view_->GetDelegatedFrameHost()->GetWeakPtr();
}
RenderWidgetHostViewBase::CopyMainAndPopupFromSurface(
host()->GetWeakPtr(), delegated_frame_host_->GetWeakPtr(), popup_host,
popup_frame_host, src_subrect, dst_size, device_scale_factor_,
std::move(callback));
}
#if defined(OS_WIN)
bool RenderWidgetHostViewAura::UsesNativeWindowFrame() const {
return (legacy_render_widget_host_HWND_ != NULL);
}
void RenderWidgetHostViewAura::UpdateMouseLockRegion() {
RECT window_rect =
display::Screen::GetScreen()
->DIPToScreenRectInWindow(window_, window_->GetBoundsInScreen())
.ToRECT();
::ClipCursor(&window_rect);
}
void RenderWidgetHostViewAura::OnLegacyWindowDestroyed() {
legacy_render_widget_host_HWND_ = nullptr;
legacy_window_destroyed_ = true;
}
#endif
void RenderWidgetHostViewAura::DidCreateNewRendererCompositorFrameSink(
viz::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink) {
renderer_compositor_frame_sink_ = renderer_compositor_frame_sink;
if (delegated_frame_host_) {
delegated_frame_host_->DidCreateNewRendererCompositorFrameSink(
renderer_compositor_frame_sink_);
}
}
void RenderWidgetHostViewAura::SubmitCompositorFrame(
const viz::LocalSurfaceId& local_surface_id,
viz::CompositorFrame frame,
base::Optional<viz::HitTestRegionList> hit_test_region_list) {
DCHECK(delegated_frame_host_);
TRACE_EVENT0("content", "RenderWidgetHostViewAura::OnSwapCompositorFrame");
delegated_frame_host_->SubmitCompositorFrame(
local_surface_id, std::move(frame), std::move(hit_test_region_list));
}
void RenderWidgetHostViewAura::OnDidNotProduceFrame(
const viz::BeginFrameAck& ack) {
if (delegated_frame_host_)
delegated_frame_host_->DidNotProduceFrame(ack);
}
void RenderWidgetHostViewAura::ClearCompositorFrame() {
// This method is only used for content rendering timeout when surface sync is
// off. However, surface sync is always on on Aura platforms.
NOTREACHED();
}
void RenderWidgetHostViewAura::ResetFallbackToFirstNavigationSurface() {
if (delegated_frame_host_)
delegated_frame_host_->ResetFallbackToFirstNavigationSurface();
}
bool RenderWidgetHostViewAura::RequestRepaintForTesting() {
return SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
base::nullopt);
}
void RenderWidgetHostViewAura::DidStopFlinging() {
selection_controller_client_->OnScrollCompleted();
}
void RenderWidgetHostViewAura::TransformPointToRootSurface(gfx::PointF* point) {
aura::Window* root = window_->GetRootWindow();
aura::Window::ConvertPointToTarget(window_, root, point);
root->GetRootWindow()->transform().TransformPoint(point);
// On ChromeOS, the root surface is the whole desktop. When using the
// window-service converting to screen coordinates gives us that.
#if defined(OS_CHROMEOS)
if (features::IsUsingWindowService()) {
aura::client::ScreenPositionClient* screen_client =
aura::client::GetScreenPositionClient(root);
if (screen_client) {
gfx::Point rounded_point(point->x(), point->y());
screen_client->ConvertPointToScreen(root, &rounded_point);
*point = gfx::PointF(rounded_point);
}
}
#endif
}
gfx::Rect RenderWidgetHostViewAura::GetBoundsInRootWindow() {
aura::Window* top_level = window_->GetToplevelWindow();
gfx::Rect bounds(top_level->GetBoundsInScreen());
#if defined(OS_WIN)
// TODO(zturner,iyengar): This will break when we remove support for NPAPI and
// remove the legacy hwnd, so a better fix will need to be decided when that
// happens.
if (UsesNativeWindowFrame()) {
// aura::Window doesn't take into account non-client area of native windows
// (e.g. HWNDs), so for that case ask Windows directly what the bounds are.
aura::WindowTreeHost* host = top_level->GetHost();
if (!host)
return top_level->GetBoundsInScreen();
RECT window_rect = {0};
HWND hwnd = host->GetAcceleratedWidget();
::GetWindowRect(hwnd, &window_rect);
bounds = gfx::Rect(window_rect);
// Maximized windows are outdented from the work area by the frame thickness
// even though this "frame" is not painted. This confuses code (and people)
// that think of a maximized window as corresponding exactly to the work
// area. Correct for this by subtracting the frame thickness back off.
if (::IsZoomed(hwnd)) {
bounds.Inset(GetSystemMetrics(SM_CXSIZEFRAME),
GetSystemMetrics(SM_CYSIZEFRAME));
bounds.Inset(GetSystemMetrics(SM_CXPADDEDBORDER),
GetSystemMetrics(SM_CXPADDEDBORDER));
}
// Pixels come back from GetWindowHost, so we need to convert those back to
// DIPs here.
bounds = display::Screen::GetScreen()->ScreenToDIPRectInWindow(top_level,
bounds);
}
#endif
return bounds;
}
void RenderWidgetHostViewAura::WheelEventAck(
const blink::WebMouseWheelEvent& event,
InputEventAckState ack_result) {
if (overscroll_controller_) {
overscroll_controller_->ReceivedEventACK(
event, (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result));
}
}
void RenderWidgetHostViewAura::DidOverscroll(
const ui::DidOverscrollParams& params) {
if (overscroll_controller_)
overscroll_controller_->OnDidOverscroll(params);
}
void RenderWidgetHostViewAura::GestureEventAck(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
const blink::WebInputEvent::Type event_type = event.GetType();
if (event_type == blink::WebGestureEvent::kGestureScrollBegin ||
event_type == blink::WebGestureEvent::kGestureScrollEnd) {
if (host()->delegate()) {
host()->delegate()->SetTopControlsGestureScrollInProgress(
event_type == blink::WebGestureEvent::kGestureScrollBegin);
}
}
if (overscroll_controller_) {
overscroll_controller_->ReceivedEventACK(
event, (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result));
// Terminate an active fling when the ACK for a GSU generated from the fling
// progress (GSU with inertial state) is consumed and the overscrolling mode
// is not |OVERSCROLL_NONE|. The early fling termination generates a GSE
// which completes the overscroll action. Without this change the overscroll
// action would complete at the end of the active fling progress which
// causes noticeable delay in cases that the fling velocity is large.
// https://crbug.com/797855
if (event_type == blink::WebInputEvent::kGestureScrollUpdate &&
event.data.scroll_update.inertial_phase ==
blink::WebGestureEvent::kMomentumPhase &&
overscroll_controller_->overscroll_mode() != OVERSCROLL_NONE) {
StopFling();
}
}
// Stop flinging if a GSU event with momentum phase is sent to the renderer
// but not consumed.
StopFlingingIfNecessary(event, ack_result);
event_handler_->GestureEventAck(event, ack_result);
ForwardTouchpadZoomEventIfNecessary(event, ack_result);
}
void RenderWidgetHostViewAura::ProcessAckedTouchEvent(
const TouchEventWithLatencyInfo& touch,
InputEventAckState ack_result) {
aura::WindowTreeHost* window_host = window_->GetHost();
// |host| is NULL during tests.
if (!window_host)
return;
// The TouchScrollStarted event is generated & consumed downstream from the
// TouchEventQueue. So we don't expect an ACK up here.
DCHECK(touch.event.GetType() != blink::WebInputEvent::kTouchScrollStarted);
ui::EventResult result = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
? ui::ER_HANDLED
: ui::ER_UNHANDLED;
blink::WebTouchPoint::State required_state;
switch (touch.event.GetType()) {
case blink::WebInputEvent::kTouchStart:
required_state = blink::WebTouchPoint::kStatePressed;
break;
case blink::WebInputEvent::kTouchEnd:
required_state = blink::WebTouchPoint::kStateReleased;
break;
case blink::WebInputEvent::kTouchMove:
required_state = blink::WebTouchPoint::kStateMoved;
break;
case blink::WebInputEvent::kTouchCancel:
required_state = blink::WebTouchPoint::kStateCancelled;
break;
default:
required_state = blink::WebTouchPoint::kStateUndefined;
NOTREACHED();
break;
}
// Only send acks for one changed touch point.
bool sent_ack = false;
for (size_t i = 0; i < touch.event.touches_length; ++i) {
if (touch.event.touches[i].state == required_state) {
DCHECK(!sent_ack);
window_host->dispatcher()->ProcessedTouchEvent(
touch.event.unique_touch_event_id, window_, result,
InputEventAckStateIsSetNonBlocking(ack_result));
if (touch.event.touch_start_or_first_touch_move &&
result == ui::ER_HANDLED && host()->delegate() &&
host()->delegate()->GetInputEventRouter()) {
host()
->delegate()
->GetInputEventRouter()
->OnHandledTouchStartOrFirstTouchMove(
touch.event.unique_touch_event_id);
}
sent_ack = true;
}
}
}
std::unique_ptr<SyntheticGestureTarget>
RenderWidgetHostViewAura::CreateSyntheticGestureTarget() {
return std::unique_ptr<SyntheticGestureTarget>(
new SyntheticGestureTargetAura(host()));
}
InputEventAckState RenderWidgetHostViewAura::FilterInputEvent(
const blink::WebInputEvent& input_event) {
bool consumed = false;
if (input_event.GetType() == WebInputEvent::kGestureFlingStart) {
const WebGestureEvent& gesture_event =
static_cast<const 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.SourceDevice() == blink::kWebGestureDeviceTouchpad &&
!gesture_event.data.fling_start.velocity_x &&
!gesture_event.data.fling_start.velocity_y) {
consumed = true;
}
}
if (overscroll_controller_)
consumed |= overscroll_controller_->WillHandleEvent(input_event);
// Touch events should always propagate to the renderer.
if (WebTouchEvent::IsTouchEventType(input_event.GetType()))
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
if (consumed &&
input_event.GetType() == blink::WebInputEvent::kGestureFlingStart) {
// 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: Similar code exists in
// RenderWidgetHostViewChildFrame::FilterInputEvent()
return INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
}
return consumed ? INPUT_EVENT_ACK_STATE_CONSUMED
: INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
InputEventAckState RenderWidgetHostViewAura::FilterChildGestureEvent(
const blink::WebGestureEvent& gesture_event) {
if (overscroll_controller_ &&
overscroll_controller_->WillHandleEvent(gesture_event))
return INPUT_EVENT_ACK_STATE_CONSUMED;
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
BrowserAccessibilityManager*
RenderWidgetHostViewAura::CreateBrowserAccessibilityManager(
BrowserAccessibilityDelegate* delegate, bool for_root_frame) {
BrowserAccessibilityManager* manager = nullptr;
#if defined(OS_WIN)
manager = new BrowserAccessibilityManagerWin(
BrowserAccessibilityManagerWin::GetEmptyDocument(), delegate);
#else
manager = BrowserAccessibilityManager::Create(
BrowserAccessibilityManager::GetEmptyDocument(), delegate);
#endif
return manager;
}
gfx::AcceleratedWidget
RenderWidgetHostViewAura::AccessibilityGetAcceleratedWidget() {
#if defined(OS_WIN)
if (legacy_render_widget_host_HWND_)
return legacy_render_widget_host_HWND_->hwnd();
#endif
return gfx::kNullAcceleratedWidget;
}
gfx::NativeViewAccessible
RenderWidgetHostViewAura::AccessibilityGetNativeViewAccessible() {
#if defined(OS_WIN)
if (legacy_render_widget_host_HWND_)
return legacy_render_widget_host_HWND_->window_accessible();
#endif
return nullptr;
}
void RenderWidgetHostViewAura::SetMainFrameAXTreeID(ui::AXTreeID id) {
window_->SetProperty(ui::kChildAXTreeID, new std::string(id.ToString()));
}
bool RenderWidgetHostViewAura::LockMouse() {
return event_handler_->LockMouse();
}
void RenderWidgetHostViewAura::UnlockMouse() {
event_handler_->UnlockMouse();
}
bool RenderWidgetHostViewAura::LockKeyboard(
base::Optional<base::flat_set<ui::DomCode>> codes) {
return event_handler_->LockKeyboard(std::move(codes));
}
void RenderWidgetHostViewAura::UnlockKeyboard() {
event_handler_->UnlockKeyboard();
}
bool RenderWidgetHostViewAura::IsKeyboardLocked() {
return event_handler_->IsKeyboardLocked();
}
base::flat_map<std::string, std::string>
RenderWidgetHostViewAura::GetKeyboardLayoutMap() {
aura::WindowTreeHost* host = window_->GetHost();
if (host)
return host->GetKeyboardLayoutMap();
return {};
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, ui::TextInputClient implementation:
void RenderWidgetHostViewAura::SetCompositionText(
const ui::CompositionText& composition) {
if (!text_input_manager_ || !text_input_manager_->GetActiveWidget())
return;
// TODO(suzhe): due to a bug of webkit, we can't use selection range with
// composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788
text_input_manager_->GetActiveWidget()->ImeSetComposition(
composition.text, composition.ime_text_spans, gfx::Range::InvalidRange(),
composition.selection.end(), composition.selection.end());
has_composition_text_ = !composition.text.empty();
}
void RenderWidgetHostViewAura::ConfirmCompositionText() {
if (text_input_manager_ && text_input_manager_->GetActiveWidget() &&
has_composition_text_) {
text_input_manager_->GetActiveWidget()->ImeFinishComposingText(false);
}
has_composition_text_ = false;
}
void RenderWidgetHostViewAura::ClearCompositionText() {
if (text_input_manager_ && text_input_manager_->GetActiveWidget() &&
has_composition_text_)
text_input_manager_->GetActiveWidget()->ImeCancelComposition();
has_composition_text_ = false;
}
void RenderWidgetHostViewAura::InsertText(const base::string16& text) {
DCHECK_NE(GetTextInputType(), ui::TEXT_INPUT_TYPE_NONE);
if (text_input_manager_ && text_input_manager_->GetActiveWidget()) {
if (text.length())
text_input_manager_->GetActiveWidget()->ImeCommitText(
text, std::vector<ui::ImeTextSpan>(), gfx::Range::InvalidRange(), 0);
else if (has_composition_text_)
text_input_manager_->GetActiveWidget()->ImeFinishComposingText(false);
}
has_composition_text_ = false;
}
void RenderWidgetHostViewAura::InsertChar(const ui::KeyEvent& event) {
if (popup_child_host_view_ && popup_child_host_view_->NeedsInputGrab()) {
popup_child_host_view_->InsertChar(event);
return;
}
// Ignore character messages for VKEY_RETURN sent on CTRL+M. crbug.com/315547
if (event_handler_->accept_return_character() ||
event.GetCharacter() != ui::VKEY_RETURN) {
// Send a blink::WebInputEvent::Char event to |host_|.
ForwardKeyboardEventWithLatencyInfo(
NativeWebKeyboardEvent(event, event.GetCharacter()), *event.latency(),
nullptr, nullptr);
}
}
ui::TextInputType RenderWidgetHostViewAura::GetTextInputType() const {
if (text_input_manager_ && text_input_manager_->GetTextInputState())
return text_input_manager_->GetTextInputState()->type;
return ui::TEXT_INPUT_TYPE_NONE;
}
ui::TextInputMode RenderWidgetHostViewAura::GetTextInputMode() const {
if (text_input_manager_ && text_input_manager_->GetTextInputState())
return text_input_manager_->GetTextInputState()->mode;
return ui::TEXT_INPUT_MODE_DEFAULT;
}
base::i18n::TextDirection RenderWidgetHostViewAura::GetTextDirection() const {
NOTIMPLEMENTED_LOG_ONCE();
return base::i18n::UNKNOWN_DIRECTION;
}
int RenderWidgetHostViewAura::GetTextInputFlags() const {
if (text_input_manager_ && text_input_manager_->GetTextInputState())
return text_input_manager_->GetTextInputState()->flags;
return 0;
}
bool RenderWidgetHostViewAura::CanComposeInline() const {
if (text_input_manager_ && text_input_manager_->GetTextInputState())
return text_input_manager_->GetTextInputState()->can_compose_inline;
return true;
}
gfx::Rect RenderWidgetHostViewAura::ConvertRectToScreen(
const gfx::Rect& rect) const {
gfx::Point origin = rect.origin();
gfx::Point end = gfx::Point(rect.right(), rect.bottom());
aura::Window* root_window = window_->GetRootWindow();
if (!root_window)
return rect;
aura::client::ScreenPositionClient* screen_position_client =
aura::client::GetScreenPositionClient(root_window);
if (!screen_position_client)
return rect;
screen_position_client->ConvertPointToScreen(window_, &origin);
screen_position_client->ConvertPointToScreen(window_, &end);
return gfx::Rect(origin.x(),
origin.y(),
end.x() - origin.x(),
end.y() - origin.y());
}
gfx::Rect RenderWidgetHostViewAura::ConvertRectFromScreen(
const gfx::Rect& rect) const {
gfx::Rect result = rect;
if (window_->GetRootWindow() &&
aura::client::GetScreenPositionClient(window_->GetRootWindow()))
wm::ConvertRectFromScreen(window_, &result);
return result;
}
gfx::Rect RenderWidgetHostViewAura::GetCaretBounds() const {
if (!text_input_manager_ || !text_input_manager_->GetActiveWidget())
return gfx::Rect();
const TextInputManager::SelectionRegion* region =
text_input_manager_->GetSelectionRegion();
return ConvertRectToScreen(
gfx::RectBetweenSelectionBounds(region->anchor, region->focus));
}
bool RenderWidgetHostViewAura::GetCompositionCharacterBounds(
uint32_t index,
gfx::Rect* rect) const {
DCHECK(rect);
if (!text_input_manager_ || !text_input_manager_->GetActiveWidget())
return false;
const TextInputManager::CompositionRangeInfo* composition_range_info =
text_input_manager_->GetCompositionRangeInfo();
if (index >= composition_range_info->character_bounds.size())
return false;
*rect = ConvertRectToScreen(composition_range_info->character_bounds[index]);
return true;
}
bool RenderWidgetHostViewAura::HasCompositionText() const {
return has_composition_text_;
}
ui::TextInputClient::FocusReason RenderWidgetHostViewAura::GetFocusReason()
const {
if (!HasFocus())
return ui::TextInputClient::FOCUS_REASON_NONE;
switch (last_pointer_type_before_focus_) {
case ui::EventPointerType::POINTER_TYPE_MOUSE:
return ui::TextInputClient::FOCUS_REASON_MOUSE;
case ui::EventPointerType::POINTER_TYPE_PEN:
return ui::TextInputClient::FOCUS_REASON_PEN;
case ui::EventPointerType::POINTER_TYPE_TOUCH:
return ui::TextInputClient::FOCUS_REASON_TOUCH;
default:
return ui::TextInputClient::FOCUS_REASON_OTHER;
}
}
bool RenderWidgetHostViewAura::GetTextRange(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->offset());
range->set_end(selection->offset() + selection->text().length());
return true;
}
bool RenderWidgetHostViewAura::GetCompositionTextRange(
gfx::Range* range) const {
// TODO(suzhe): implement this method when fixing http://crbug.com/55130.
NOTIMPLEMENTED_LOG_ONCE();
return false;
}
bool RenderWidgetHostViewAura::GetEditableSelectionRange(
gfx::Range* range) const {
// TODO(yhanada, crbug.com/908762): Return only selections in a text field.
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;
}
bool RenderWidgetHostViewAura::SetEditableSelectionRange(
const gfx::Range& range) {
// TODO(suzhe): implement this method when fixing http://crbug.com/55130.
NOTIMPLEMENTED_LOG_ONCE();
return false;
}
bool RenderWidgetHostViewAura::DeleteRange(const gfx::Range& range) {
// TODO(suzhe): implement this method when fixing http://crbug.com/55130.
NOTIMPLEMENTED_LOG_ONCE();
return false;
}
bool RenderWidgetHostViewAura::GetTextFromRange(
const gfx::Range& range,
base::string16* text) const {
if (!text_input_manager_ || !GetFocusedWidget())
return false;
const TextInputManager::TextSelection* selection =
text_input_manager_->GetTextSelection(GetFocusedWidget()->GetView());
if (!selection)
return false;
gfx::Range selection_text_range(
selection->offset(), selection->offset() + selection->text().length());
if (!selection_text_range.Contains(range)) {
text->clear();
return false;
}
if (selection_text_range.EqualsIgnoringDirection(range)) {
// Avoid calling substr whose performance is low.
*text = selection->text();
} else {
*text = selection->text().substr(range.GetMin() - selection->offset(),
range.length());
}
return true;
}
void RenderWidgetHostViewAura::OnInputMethodChanged() {
// TODO(suzhe): implement the newly added "locale" property of HTML DOM
// TextEvent.
}
bool RenderWidgetHostViewAura::ChangeTextDirectionAndLayoutAlignment(
base::i18n::TextDirection direction) {
if (!GetTextInputManager() && !GetTextInputManager()->GetActiveWidget())
return false;
GetTextInputManager()->GetActiveWidget()->UpdateTextDirection(
direction == base::i18n::RIGHT_TO_LEFT
? blink::kWebTextDirectionRightToLeft
: blink::kWebTextDirectionLeftToRight);
GetTextInputManager()->GetActiveWidget()->NotifyTextDirection();
return true;
}
void RenderWidgetHostViewAura::ExtendSelectionAndDelete(
size_t before, size_t after) {
RenderFrameHostImpl* rfh = GetFocusedFrame();
if (rfh)
rfh->GetFrameInputHandler()->ExtendSelectionAndDelete(before, after);
}
void RenderWidgetHostViewAura::EnsureCaretNotInRect(
const gfx::Rect& rect_in_screen) {
aura::Window* top_level_window = window_->GetToplevelWindow();
#if defined(OS_CHROMEOS)
wm::EnsureWindowNotInRect(top_level_window, rect_in_screen);
#endif
// Perform overscroll if the caret is still hidden by the keyboard.
const gfx::Rect hidden_window_bounds_in_screen = gfx::IntersectRects(
rect_in_screen, top_level_window->GetBoundsInScreen());
if (hidden_window_bounds_in_screen.IsEmpty())
return;
gfx::Rect visible_area_in_local_space = gfx::SubtractRects(
window_->GetBoundsInScreen(), hidden_window_bounds_in_screen);
visible_area_in_local_space =
ConvertRectFromScreen(visible_area_in_local_space);
ScrollFocusedEditableNodeIntoRect(visible_area_in_local_space);
}
bool RenderWidgetHostViewAura::IsTextEditCommandEnabled(
ui::TextEditCommand command) const {
return false;
}
void RenderWidgetHostViewAura::SetTextEditCommandForNextKeyEvent(
ui::TextEditCommand command) {}
ukm::SourceId RenderWidgetHostViewAura::GetClientSourceForMetrics() const {
RenderFrameHostImpl* frame = GetFocusedFrame();
if (frame) {
frame->GetRenderWidgetHost()
->delegate()
->GetUkmSourceIdForLastCommittedSource();
}
return ukm::SourceId();
}
bool RenderWidgetHostViewAura::ShouldDoLearning() {
return GetTextInputManager() && GetTextInputManager()->should_do_learning();
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, display::DisplayObserver implementation:
void RenderWidgetHostViewAura::OnDisplayMetricsChanged(
const display::Display& display,
uint32_t metrics) {
// The screen info should be updated regardless of the metric change.
display::Screen* screen = display::Screen::GetScreen();
if (display.id() == screen->GetDisplayNearestWindow(window_).id()) {
UpdateScreenInfo(window_);
current_cursor_.SetDisplayInfo(display);
UpdateCursorIfOverSelf();
}
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, aura::WindowDelegate implementation:
gfx::Size RenderWidgetHostViewAura::GetMinimumSize() const {
return gfx::Size();
}
gfx::Size RenderWidgetHostViewAura::GetMaximumSize() const {
return gfx::Size();
}
void RenderWidgetHostViewAura::OnBoundsChanged(const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
base::AutoReset<bool> in_bounds_changed(&in_bounds_changed_, true);
// We care about this whenever RenderWidgetHostViewAura is not owned by a
// WebContentsViewAura since changes to the Window's bounds need to be
// messaged to the renderer. WebContentsViewAura invokes SetSize() or
// SetBounds() itself. No matter how we got here, any redundant calls are
// harmless.
SetSize(new_bounds.size());
if (GetInputMethod())
GetInputMethod()->OnCaretBoundsChanged(this);
}
gfx::NativeCursor RenderWidgetHostViewAura::GetCursor(const gfx::Point& point) {
if (IsMouseLocked())
return ui::CursorType::kNone;
return current_cursor_.GetNativeCursor();
}
int RenderWidgetHostViewAura::GetNonClientComponent(
const gfx::Point& point) const {
return HTCLIENT;
}
bool RenderWidgetHostViewAura::ShouldDescendIntoChildForEventHandling(
aura::Window* child,
const gfx::Point& location) {
return true;
}
bool RenderWidgetHostViewAura::CanFocus() {
return widget_type_ == WidgetType::kFrame;
}
void RenderWidgetHostViewAura::OnCaptureLost() {
host()->LostCapture();
}
void RenderWidgetHostViewAura::OnPaint(const ui::PaintContext& context) {
NOTREACHED();
}
void RenderWidgetHostViewAura::OnDeviceScaleFactorChanged(
float old_device_scale_factor,
float new_device_scale_factor) {
if (!window_->GetRootWindow())
return;
SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
window_->GetLocalSurfaceIdAllocation());
device_scale_factor_ = new_device_scale_factor;
const display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
DCHECK_EQ(new_device_scale_factor, display.device_scale_factor());
current_cursor_.SetDisplayInfo(display);
SnapToPhysicalPixelBoundary();
}
void RenderWidgetHostViewAura::OnWindowDestroying(aura::Window* window) {
#if defined(OS_WIN)
// The LegacyRenderWidgetHostHWND instance is destroyed when its window is
// destroyed. Normally we control when that happens via the Destroy call
// in the dtor. However there may be cases where the window is destroyed
// by Windows, i.e. the parent window is destroyed before the
// RenderWidgetHostViewAura instance goes away etc. To avoid that we
// destroy the LegacyRenderWidgetHostHWND instance here.
if (legacy_render_widget_host_HWND_) {
legacy_render_widget_host_HWND_->Destroy();
// The Destroy call above will delete the LegacyRenderWidgetHostHWND
// instance.
legacy_render_widget_host_HWND_ = NULL;
}
#endif
// Make sure that the input method no longer references to this object before
// this object is removed from the root window (i.e. this object loses access
// to the input method).
DetachFromInputMethod();
if (overscroll_controller_)
overscroll_controller_->Reset();
}
void RenderWidgetHostViewAura::OnWindowDestroyed(aura::Window* window) {
// This is not called on all destruction paths (e.g. if this view was never
// inialized properly to create the window). So the destruction/cleanup code
// that do not depend on |window_| should happen in the destructor, not here.
delete this;
}
void RenderWidgetHostViewAura::OnWindowTargetVisibilityChanged(bool visible) {
}
bool RenderWidgetHostViewAura::HasHitTestMask() const {
return false;
}
void RenderWidgetHostViewAura::GetHitTestMask(gfx::Path* mask) const {
}
bool RenderWidgetHostViewAura::RequiresDoubleTapGestureEvents() const {
RenderViewHost* rvh = RenderViewHost::From(host());
return rvh && rvh->GetWebkitPreferences().double_tap_to_zoom_enabled;
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, ui::EventHandler implementation:
void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) {
last_pointer_type_ = ui::EventPointerType::POINTER_TYPE_UNKNOWN;
event_handler_->OnKeyEvent(event);
}
void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
#if defined(OS_WIN)
if (event->type() == ui::ET_MOUSE_MOVED) {
if (event->location() == last_mouse_move_location_) {
event->SetHandled();
return;
}
last_mouse_move_location_ = event->location();
}
#endif
last_pointer_type_ = ui::EventPointerType::POINTER_TYPE_MOUSE;
event_handler_->OnMouseEvent(event);
}
bool RenderWidgetHostViewAura::TransformPointToLocalCoordSpaceLegacy(
const gfx::PointF& point,
const viz::SurfaceId& original_surface,
gfx::PointF* transformed_point) {
// Transformations use physical pixels rather than DIP, so conversion
// is necessary.
gfx::PointF point_in_pixels =
gfx::ConvertPointToPixel(device_scale_factor_, point);
// TODO: this shouldn't be used with aura-mus, so that the null check so
// go away and become a DCHECK.
if (delegated_frame_host_ &&
!delegated_frame_host_->TransformPointToLocalCoordSpaceLegacy(
point_in_pixels, original_surface, transformed_point))
return false;
*transformed_point =
gfx::ConvertPointToDIP(device_scale_factor_, *transformed_point);
return true;
}
bool RenderWidgetHostViewAura::HasFallbackSurface() const {
return delegated_frame_host_ && delegated_frame_host_->HasFallbackSurface();
}
bool RenderWidgetHostViewAura::TransformPointToCoordSpaceForView(
const gfx::PointF& point,
RenderWidgetHostViewBase* target_view,
gfx::PointF* transformed_point,
viz::EventSource source) {
if (target_view == this || !delegated_frame_host_) {
*transformed_point = point;
return true;
}
// In TransformPointToLocalCoordSpace() there is a Point-to-Pixel conversion,
// but it is not necessary here because the final target view is responsible
// for converting before computing the final transform.
return target_view->TransformPointToLocalCoordSpace(
point, GetCurrentSurfaceId(), transformed_point, source);
}
viz::FrameSinkId RenderWidgetHostViewAura::GetRootFrameSinkId() {
if (!window_ || !window_->GetHost() || !window_->GetHost()->compositor())
return viz::FrameSinkId();
// In single-process mash the root is provided by Ash. Have
// HostFrameSinkManager walk the tree to find the right root.
if (features::IsSingleProcessMash()) {
base::Optional<viz::FrameSinkId> root =
GetHostFrameSinkManager()->FindRootFrameSinkId(frame_sink_id_);
return root ? *root : viz::FrameSinkId();
}
return window_->GetHost()->compositor()->frame_sink_id();
}
viz::SurfaceId RenderWidgetHostViewAura::GetCurrentSurfaceId() const {
return delegated_frame_host_ ? delegated_frame_host_->GetCurrentSurfaceId()
: viz::SurfaceId();
}
void RenderWidgetHostViewAura::FocusedNodeChanged(
bool editable,
const gfx::Rect& node_bounds_in_screen) {
// The last gesture most likely caused the focus change. The focus reason will
// be incorrect if the focus was triggered without a user gesture.
// TODO(https://crbug.com/824604): Get the focus reason from the renderer
// process instead to get the true focus reason.
last_pointer_type_before_focus_ = last_pointer_type_;
auto* input_method = GetInputMethod();
if (input_method)
input_method->CancelComposition(this);
has_composition_text_ = false;
#if defined(OS_WIN)
if (!editable && virtual_keyboard_requested_ && window_) {
virtual_keyboard_requested_ = false;
if (input_method && input_method->GetInputMethodKeyboardController()) {
input_method->GetInputMethodKeyboardController()
->DismissVirtualKeyboard();
}
}
#elif defined(OS_FUCHSIA)
if (!editable && window_) {
if (input_method) {
input_method->GetInputMethodKeyboardController()
->DismissVirtualKeyboard();
}
}
#endif
}
void RenderWidgetHostViewAura::ScheduleEmbed(
ws::mojom::WindowTreeClientPtr client,
base::OnceCallback<void(const base::UnguessableToken&)> callback) {
DCHECK(features::IsMultiProcessMash());
aura::Env::GetInstance()->ScheduleEmbed(std::move(client),
std::move(callback));
}
void RenderWidgetHostViewAura::OnScrollEvent(ui::ScrollEvent* event) {
event_handler_->OnScrollEvent(event);
}
void RenderWidgetHostViewAura::OnTouchEvent(ui::TouchEvent* event) {
last_pointer_type_ = event->pointer_details().pointer_type;
event_handler_->OnTouchEvent(event);
}
void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event) {
last_pointer_type_ = event->details().primary_pointer_type();
event_handler_->OnGestureEvent(event);
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, wm::ActivationDelegate implementation:
bool RenderWidgetHostViewAura::ShouldActivate() const {
aura::WindowTreeHost* host = window_->GetHost();
if (!host)
return true;
const ui::Event* event = host->dispatcher()->current_event();
if (!event)
return true;
return is_fullscreen_;
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, aura::client::CursorClientObserver implementation:
void RenderWidgetHostViewAura::OnCursorVisibilityChanged(bool is_visible) {
NotifyRendererOfCursorVisibilityState(is_visible);
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, aura::client::FocusChangeObserver implementation:
void RenderWidgetHostViewAura::OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) {
DCHECK(window_ == gained_focus || window_ == lost_focus);
if (window_ == gained_focus) {
// We need to honor input bypass if the associated tab is does not want
// input. This gives the current focused window a chance to be the text
// input client and handle events.
if (host()->IsIgnoringInputEvents())
return;
host()->GotFocus();
host()->SetActive(true);
ui::InputMethod* input_method = GetInputMethod();
if (input_method) {
// Ask the system-wide IME to send all TextInputClient messages to |this|
// object.
input_method->SetFocusedTextInputClient(this);
}
BrowserAccessibilityManager* manager =
host()->GetRootBrowserAccessibilityManager();
if (manager)
manager->OnWindowFocused();
} else if (window_ == lost_focus) {
host()->SetActive(false);
host()->LostFocus();
DetachFromInputMethod();
// TODO(wjmaclean): Do we need to let TouchSelectionControllerClientAura
// handle this, just in case it stomps on a new highlight in another view
// that has just become focused? So far it doesn't appear to be a problem,
// but we should keep an eye on it.
selection_controller_->HideAndDisallowShowingAutomatically();
if (overscroll_controller_)
overscroll_controller_->Cancel();
BrowserAccessibilityManager* manager =
host()->GetRootBrowserAccessibilityManager();
if (manager)
manager->OnWindowBlurred();
// If we lose the focus while fullscreen, close the window; Pepper Flash
// won't do it for us (unlike NPAPI Flash). However, we do not close the
// window if we lose the focus to a window on another display.
display::Screen* screen = display::Screen::GetScreen();
bool focusing_other_display =
gained_focus && screen->GetNumDisplays() > 1 &&
(screen->GetDisplayNearestWindow(window_).id() !=
screen->GetDisplayNearestWindow(gained_focus).id());
if (is_fullscreen_ && !in_shutdown_ && !focusing_other_display) {
#if defined(OS_WIN)
// On Windows, if we are switching to a non Aura Window on a different
// screen we should not close the fullscreen window.
if (!gained_focus) {
POINT point = {0};
::GetCursorPos(&point);
if (screen->GetDisplayNearestWindow(window_).id() !=
screen->GetDisplayNearestPoint(gfx::Point(point)).id())
return;
}
#endif
Shutdown();
return;
}
// Close the child popup window if we lose focus (e.g. due to a JS alert or
// system modal dialog). This is particularly important if
// |popup_child_host_view_| has mouse capture.
if (popup_child_host_view_)
popup_child_host_view_->Shutdown();
}
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, aura::WindowTreeHostObserver implementation:
void RenderWidgetHostViewAura::OnHostMovedInPixels(
aura::WindowTreeHost* host,
const gfx::Point& new_origin_in_pixels) {
TRACE_EVENT1("ui", "RenderWidgetHostViewAura::OnHostMovedInPixels",
"new_origin_in_pixels", new_origin_in_pixels.ToString());
UpdateScreenInfo(window_);
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, RenderFrameMetadataProvider::Observer
// implementation:
void RenderWidgetHostViewAura::OnRenderFrameMetadataChangedAfterActivation() {
RenderWidgetHostViewBase::OnRenderFrameMetadataChangedAfterActivation();
const cc::RenderFrameMetadata& metadata =
host()->render_frame_metadata_provider()->LastRenderFrameMetadata();
SetContentBackgroundColor(metadata.root_background_color);
if (metadata.selection.start != selection_start_ ||
metadata.selection.end != selection_end_) {
selection_start_ = metadata.selection.start;
selection_end_ = metadata.selection.end;
selection_controller_client_->UpdateClientSelectionBounds(selection_start_,
selection_end_);
}
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, private:
RenderWidgetHostViewAura::~RenderWidgetHostViewAura() {
// Ask the RWH to drop reference to us.
if (!is_guest_view_hack_)
host()->ViewDestroyed();
selection_controller_.reset();
selection_controller_client_.reset();
GetCursorManager()->ViewBeingDestroyed(this);
delegated_frame_host_.reset();
window_observer_.reset();
if (window_) {
if (window_->GetHost())
window_->GetHost()->RemoveObserver(this);
UnlockMouse();
wm::SetTooltipText(window_, nullptr);
display::Screen::GetScreen()->RemoveObserver(this);
// This call is usually no-op since |this| object is already removed from
// the Aura root window and we don't have a way to get an input method
// object associated with the window, but just in case.
DetachFromInputMethod();
}
if (popup_parent_host_view_) {
DCHECK(!popup_parent_host_view_->popup_child_host_view_ ||
popup_parent_host_view_->popup_child_host_view_ == this);
popup_parent_host_view_->SetPopupChild(nullptr);
}
if (popup_child_host_view_) {
DCHECK(!popup_child_host_view_->popup_parent_host_view_ ||
popup_child_host_view_->popup_parent_host_view_ == this);
popup_child_host_view_->popup_parent_host_view_ = nullptr;
}
event_observer_for_popup_exit_.reset();
#if defined(OS_WIN)
// The LegacyRenderWidgetHostHWND window should have been destroyed in
// RenderWidgetHostViewAura::OnWindowDestroying and the pointer should
// be set to NULL.
DCHECK(!legacy_render_widget_host_HWND_);
#endif
if (text_input_manager_)
text_input_manager_->RemoveObserver(this);
}
void RenderWidgetHostViewAura::CreateAuraWindow(aura::client::WindowType type) {
DCHECK(!window_);
DCHECK(!is_mus_browser_plugin_guest_);
window_ = new aura::Window(this);
window_->SetName("RenderWidgetHostViewAura");
event_handler_->set_window(window_);
window_observer_.reset(new WindowObserver(this));
wm::SetTooltipText(window_, &tooltip_);
wm::SetActivationDelegate(window_, this);
aura::client::SetFocusChangeObserver(window_, this);
display::Screen::GetScreen()->AddObserver(this);
window_->SetType(type);
window_->Init(ui::LAYER_SOLID_COLOR);
window_->layer()->SetColor(GetBackgroundColor() ? *GetBackgroundColor()
: SK_ColorWHITE);
// This needs to happen only after |window_| has been initialized using
// Init(), because it needs to have the layer.
if (frame_sink_id_.is_valid())
window_->SetEmbedFrameSinkId(frame_sink_id_);
if (!features::IsMultiProcessMash())
return;
// Embed the renderer into the Window.
// Use kEmbedFlagEmbedderControlsVisibility so that the renderer can't change
// the visibility of |window_|.
aura::WindowPortMus::Get(window_)->Embed(
GetWindowTreeClientFromRenderer(),
ws::mojom::kEmbedFlagEmbedderInterceptsEvents |
ws::mojom::kEmbedFlagEmbedderControlsVisibility,
base::BindOnce(&EmbedCallback));
}
void RenderWidgetHostViewAura::CreateDelegatedFrameHostClient() {
if (!frame_sink_id_.is_valid())
return;
delegated_frame_host_client_ =
std::make_unique<DelegatedFrameHostClientAura>(this);
delegated_frame_host_ = std::make_unique<DelegatedFrameHost>(
frame_sink_id_, delegated_frame_host_client_.get(),
false /* should_register_frame_sink_id */);
// Let the page-level input event router know about our surface ID
// namespace for surface-based hit testing.
if (host()->delegate() && host()->delegate()->GetInputEventRouter()) {
host()->delegate()->GetInputEventRouter()->AddFrameSinkIdOwner(
GetFrameSinkId(), this);
}
}
void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() {
if (is_mus_browser_plugin_guest_)
return;
if (host()->GetProcess()->FastShutdownStarted())
return;
aura::Window* root_window = window_->GetRootWindow();
if (!root_window)
return;
display::Screen* screen = display::Screen::GetScreen();
DCHECK(screen);
gfx::Point cursor_screen_point = screen->GetCursorScreenPoint();
#if !defined(OS_CHROMEOS)
// Ignore cursor update messages if the window under the cursor is not us.
aura::Window* window_at_screen_point = screen->GetWindowAtScreenPoint(
cursor_screen_point);
#if defined(OS_WIN)
// On Windows we may fail to retrieve the aura Window at the current cursor
// position. This is because the WindowFromPoint API may return the legacy
// window which is not associated with an aura Window. In this case we need
// to get the aura window for the parent of the legacy window.
if (!window_at_screen_point && legacy_render_widget_host_HWND_) {
HWND hwnd_at_point = ::WindowFromPoint(cursor_screen_point.ToPOINT());
if (hwnd_at_point == legacy_render_widget_host_HWND_->hwnd())
hwnd_at_point = legacy_render_widget_host_HWND_->GetParent();
display::win::ScreenWin* screen_win =
static_cast<display::win::ScreenWin*>(screen);
window_at_screen_point = screen_win->GetNativeWindowFromHWND(
hwnd_at_point);
}
#endif // defined(OS_WIN)
if (!window_at_screen_point ||
(window_at_screen_point->GetRootWindow() != root_window)) {
return;
}
#endif // !defined(OS_CHROMEOS)
gfx::Point root_window_point = cursor_screen_point;
aura::client::ScreenPositionClient* screen_position_client =
aura::client::GetScreenPositionClient(root_window);
if (screen_position_client) {
screen_position_client->ConvertPointFromScreen(
root_window, &root_window_point);
}
if (root_window->GetEventHandlerForPoint(root_window_point) != window_)
return;
gfx::NativeCursor cursor = current_cursor_.GetNativeCursor();
// Do not show loading cursor when the cursor is currently hidden.
if (is_loading_ && cursor != ui::CursorType::kNone)
cursor = ui::Cursor(ui::CursorType::kPointer);
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(root_window);
if (cursor_client) {
cursor_client->SetCursor(cursor);
}
}
bool RenderWidgetHostViewAura::SynchronizeVisualProperties(
const cc::DeadlinePolicy& deadline_policy,
const base::Optional<viz::LocalSurfaceIdAllocation>&
child_local_surface_id_allocation) {
DCHECK(window_);
window_->UpdateLocalSurfaceIdFromEmbeddedClient(
child_local_surface_id_allocation);
// If the viz::LocalSurfaceIdAllocation is invalid, we may have been evicted,
// allocate a new one to establish bounds.
if (!GetLocalSurfaceIdAllocation().IsValid())
window_->AllocateLocalSurfaceId();
if (delegated_frame_host_) {
delegated_frame_host_->EmbedSurface(
GetLocalSurfaceIdAllocation().local_surface_id(),
window_->bounds().size(), deadline_policy);
}
return host()->SynchronizeVisualProperties();
}
void RenderWidgetHostViewAura::OnDidUpdateVisualPropertiesComplete(
const cc::RenderFrameMetadata& metadata) {
DCHECK(window_);
if (host()->delegate()) {
host()->delegate()->SetTopControlsShownRatio(
host(), metadata.top_controls_shown_ratio);
}
SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
metadata.local_surface_id_allocation);
}
ui::InputMethod* RenderWidgetHostViewAura::GetInputMethod() const {
if (!window_)
return nullptr;
aura::Window* root_window = window_->GetRootWindow();
if (!root_window)
return nullptr;
return root_window->GetHost()->GetInputMethod();
}
RenderWidgetHostViewBase*
RenderWidgetHostViewAura::GetFocusedViewForTextSelection() {
// We obtain the TextSelection from focused RWH which is obtained from the
// frame tree. BrowserPlugin-based guests' RWH is not part of the frame tree
// and the focused RWH will be that of the embedder which is incorrect. In
// this case we should use TextSelection for |this| since RWHV for guest
// forwards text selection information to its platform view.
return is_guest_view_hack_
? this
: GetFocusedWidget() ? GetFocusedWidget()->GetView() : nullptr;
}
void RenderWidgetHostViewAura::Shutdown() {
if (!in_shutdown_) {
in_shutdown_ = true;
host()->ShutdownAndDestroyWidget(true);
}
}
TouchSelectionControllerClientManager*
RenderWidgetHostViewAura::GetTouchSelectionControllerClientManager() {
return selection_controller_client_.get();
}
bool RenderWidgetHostViewAura::NeedsInputGrab() {
return widget_type_ == WidgetType::kPopup;
}
bool RenderWidgetHostViewAura::NeedsMouseCapture() {
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
return NeedsInputGrab();
#endif
return false;
}
void RenderWidgetHostViewAura::SetTooltipsEnabled(bool enable) {
if (enable) {
tooltip_disabler_.reset();
} else {
tooltip_disabler_.reset(
new wm::ScopedTooltipDisabler(window_->GetRootWindow()));
}
}
void RenderWidgetHostViewAura::ShowContextMenu(
const ContextMenuParams& params) {
// Use RenderViewHostDelegate to get to the WebContentsViewAura, which will
// actually show the disambiguation popup.
RenderViewHost* rvh = RenderViewHost::From(host());
if (!rvh)
return;
RenderViewHostDelegate* delegate = rvh->GetDelegate();
if (!delegate)
return;
RenderViewHostDelegateView* delegate_view = delegate->GetDelegateView();
if (!delegate_view)
return;
delegate_view->ShowContextMenu(GetFocusedFrame(), params);
}
void RenderWidgetHostViewAura::NotifyRendererOfCursorVisibilityState(
bool is_visible) {
if (host()->is_hidden() ||
(cursor_visibility_state_in_renderer_ == VISIBLE && is_visible) ||
(cursor_visibility_state_in_renderer_ == NOT_VISIBLE && !is_visible))
return;
cursor_visibility_state_in_renderer_ = is_visible ? VISIBLE : NOT_VISIBLE;
host()->SendCursorVisibilityState(is_visible);
}
void RenderWidgetHostViewAura::SetOverscrollControllerEnabled(bool enabled) {
if (!enabled)
overscroll_controller_.reset();
else if (!overscroll_controller_)
overscroll_controller_.reset(new OverscrollController());
}
void RenderWidgetHostViewAura::SetOverscrollControllerForTesting(
std::unique_ptr<OverscrollController> controller) {
overscroll_controller_ = std::move(controller);
}
void RenderWidgetHostViewAura::SnapToPhysicalPixelBoundary() {
// The top left corner of our view in window coordinates might not land on a
// device pixel boundary if we have a non-integer device scale. In that case,
// to avoid the web contents area looking blurry we translate the web contents
// in the +x, +y direction to land on the nearest pixel boundary. This may
// cause the bottom and right edges to be clipped slightly, but that's ok.
// We want to snap it to the nearest ancestor.
wm::SnapWindowToPixelBoundary(window_);
has_snapped_to_boundary_ = true;
}
void RenderWidgetHostViewAura::SetSelectionControllerClientForTest(
std::unique_ptr<TouchSelectionControllerClientAura> client) {
selection_controller_client_.swap(client);
CreateSelectionController();
}
void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) {
SnapToPhysicalPixelBoundary();
// Don't recursively call SetBounds if this bounds update is the result of
// a Window::SetBoundsInternal call.
if (!in_bounds_changed_)
window_->SetBounds(rect);
// Even if not showing yet, we need to synchronize on size. As the renderer
// needs to begin layout. Waiting until we show to start layout leads to
// significant delays in embedding the first shown surface (500+ ms.)
SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
window_->GetLocalSurfaceIdAllocation());
#if defined(OS_WIN)
UpdateLegacyWin();
if (IsMouseLocked())
UpdateMouseLockRegion();
#endif
}
#if defined(OS_WIN)
void RenderWidgetHostViewAura::UpdateLegacyWin() {
if (legacy_window_destroyed_ || !GetHostWindowHWND())
return;
if (!legacy_render_widget_host_HWND_) {
legacy_render_widget_host_HWND_ =
LegacyRenderWidgetHostHWND::Create(GetHostWindowHWND());
}
if (legacy_render_widget_host_HWND_) {
legacy_render_widget_host_HWND_->set_host(this);
legacy_render_widget_host_HWND_->UpdateParent(GetHostWindowHWND());
legacy_render_widget_host_HWND_->SetBounds(
window_->GetBoundsInRootWindow());
// There are cases where the parent window is created, made visible and
// the associated RenderWidget is also visible before the
// LegacyRenderWidgetHostHWND instace is created. Ensure that it is shown
// here.
if (!host()->is_hidden())
legacy_render_widget_host_HWND_->Show();
}
}
#endif
void RenderWidgetHostViewAura::SchedulePaintIfNotInClip(
const gfx::Rect& rect,
const gfx::Rect& clip) {
if (!clip.IsEmpty()) {
gfx::Rect to_paint = gfx::SubtractRects(rect, clip);
if (!to_paint.IsEmpty())
window_->SchedulePaintInRect(to_paint);
} else {
window_->SchedulePaintInRect(rect);
}
}
void RenderWidgetHostViewAura::AddedToRootWindow() {
window_->GetHost()->AddObserver(this);
UpdateScreenInfo(window_);
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(window_->GetRootWindow());
if (cursor_client) {
cursor_client->AddObserver(this);
NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible());
}
if (HasFocus()) {
ui::InputMethod* input_method = GetInputMethod();
if (input_method)
input_method->SetFocusedTextInputClient(this);
}
#if defined(OS_WIN)
UpdateLegacyWin();
#endif
if (delegated_frame_host_)
delegated_frame_host_->AttachToCompositor(window_->GetHost()->compositor());
}
void RenderWidgetHostViewAura::RemovingFromRootWindow() {
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(window_->GetRootWindow());
if (cursor_client)
cursor_client->RemoveObserver(this);
DetachFromInputMethod();
window_->GetHost()->RemoveObserver(this);
if (delegated_frame_host_)
delegated_frame_host_->DetachFromCompositor();
#if defined(OS_WIN)
// Update the legacy window's parent temporarily to the hidden window. It
// will eventually get reparented to the right root.
if (legacy_render_widget_host_HWND_)
legacy_render_widget_host_HWND_->UpdateParent(ui::GetHiddenWindow());
#endif
}
void RenderWidgetHostViewAura::DetachFromInputMethod() {
ui::InputMethod* input_method = GetInputMethod();
if (input_method) {
input_method->DetachTextInputClient(this);
#if defined(OS_CHROMEOS)
wm::RestoreWindowBoundsOnClientFocusLost(window_->GetToplevelWindow());
#endif // defined(OS_CHROMEOS)
}
#if defined(OS_WIN)
// Reset the keyboard observer because it attaches to the input method.
keyboard_observer_.reset();
#endif // defined(OS_WIN)
}
void RenderWidgetHostViewAura::ForwardKeyboardEventWithLatencyInfo(
const NativeWebKeyboardEvent& event,
const ui::LatencyInfo& latency,
ui::KeyEvent* original_key_event,
bool* update_event) {
RenderWidgetHostImpl* target_host = host();
// If there are multiple widgets on the page (such as when there are
// out-of-process iframes), pick the one that should process this event.
if (host()->delegate())
target_host = host()->delegate()->GetFocusedRenderWidgetHost(host());
if (!target_host)
return;
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
ui::TextEditKeyBindingsDelegateAuraLinux* keybinding_delegate =
ui::GetTextEditKeyBindingsDelegate();
std::vector<ui::TextEditCommandAuraLinux> commands;
if (!event.skip_in_browser &&
keybinding_delegate &&
event.os_event &&
keybinding_delegate->MatchEvent(*event.os_event, &commands)) {
// Transform from ui/ types to content/ types.
EditCommands edit_commands;
for (std::vector<ui::TextEditCommandAuraLinux>::const_iterator it =
commands.begin(); it != commands.end(); ++it) {
edit_commands.push_back(EditCommand(it->GetCommandString(),
it->argument()));
}
target_host->ForwardKeyboardEventWithCommands(
event, latency, &edit_commands, original_key_event, update_event);
return;
}
#endif
target_host->ForwardKeyboardEventWithCommands(
event, latency, nullptr, original_key_event, update_event);
}
void RenderWidgetHostViewAura::CreateSelectionController() {
ui::TouchSelectionController::Config tsc_config;
tsc_config.max_tap_duration = base::TimeDelta::FromMilliseconds(
ui::GestureConfiguration::GetInstance()->long_press_time_in_ms());
tsc_config.tap_slop = ui::GestureConfiguration::GetInstance()
->max_touch_move_in_pixels_for_click();
tsc_config.enable_longpress_drag_selection = false;
selection_controller_.reset(new ui::TouchSelectionController(
selection_controller_client_.get(), tsc_config));
}
void RenderWidgetHostViewAura::OnDidNavigateMainFrameToNewPage() {
window_->env()->gesture_recognizer()->CancelActiveTouches(window_);
}
const viz::FrameSinkId& RenderWidgetHostViewAura::GetFrameSinkId() const {
return frame_sink_id_;
}
const viz::LocalSurfaceIdAllocation&
RenderWidgetHostViewAura::GetLocalSurfaceIdAllocation() const {
return window_->GetLocalSurfaceIdAllocation();
}
void RenderWidgetHostViewAura::OnUpdateTextInputStateCalled(
TextInputManager* text_input_manager,
RenderWidgetHostViewBase* updated_view,
bool did_update_state) {
DCHECK_EQ(text_input_manager_, text_input_manager);
if (!GetInputMethod())
return;
if (did_update_state)
GetInputMethod()->OnTextInputTypeChanged(this);
const TextInputState* state = text_input_manager_->GetTextInputState();
if (state && state->type != ui::TEXT_INPUT_TYPE_NONE &&
state->mode != ui::TEXT_INPUT_MODE_NONE) {
bool show_virtual_keyboard = true;
#if defined(OS_WIN) || defined(OS_FUCHSIA)
show_virtual_keyboard =
last_pointer_type_ == ui::EventPointerType::POINTER_TYPE_TOUCH;
#endif
if (state->show_ime_if_needed &&
GetInputMethod()->GetTextInputClient() == this &&
show_virtual_keyboard) {
GetInputMethod()->ShowVirtualKeyboardIfEnabled();
}
// Ensure that accessibility events are fired when the selection location
// moves from UI back to content.
text_input_manager->NotifySelectionBoundsChanged(updated_view);
}
if (auto* render_widget_host = updated_view->host()) {
// Monitor the composition information if there is a focused editable node.
render_widget_host->RequestCompositionUpdates(
false /* immediate_request */,
state &&
(state->type != ui::TEXT_INPUT_TYPE_NONE) /* monitor_updates */);
}
}
void RenderWidgetHostViewAura::OnImeCancelComposition(
TextInputManager* text_input_manager,
RenderWidgetHostViewBase* view) {
// |view| is not necessarily the one corresponding to
// TextInputManager::GetActiveWidget() as RenderWidgetHostViewAura can call
// this method to finish any ongoing composition in response to a mouse down
// event.
if (GetInputMethod())
GetInputMethod()->CancelComposition(this);
has_composition_text_ = false;
}
void RenderWidgetHostViewAura::OnSelectionBoundsChanged(
TextInputManager* text_input_manager,
RenderWidgetHostViewBase* updated_view) {
// Note: accessibility caret move events are no longer fired directly here,
// because they were redundant with the events fired by the top level window
// by HWNDMessageHandler::OnCaretBoundsChanged().
if (GetInputMethod())
GetInputMethod()->OnCaretBoundsChanged(this);
}
void RenderWidgetHostViewAura::OnTextSelectionChanged(
TextInputManager* text_input_manager,
RenderWidgetHostViewBase* updated_view) {
if (!GetTextInputManager())
return;
// We obtain the TextSelection from focused RWH which is obtained from the
// frame tree. BrowserPlugin-based guests' RWH is not part of the frame tree
// and the focused RWH will be that of the embedder which is incorrect. In
// this case we should use TextSelection for |this| since RWHV for guest
// forwards text selection information to its platform view.
RenderWidgetHostViewBase* focused_view =
is_guest_view_hack_
? this
: GetFocusedWidget() ? GetFocusedWidget()->GetView() : nullptr;
if (!focused_view)
return;
// IMF relies on the |OnCaretBoundsChanged| for the surrounding text changed
// events to IME. Explicitly call |OnCaretBoundsChanged| here so that IMF can
// know about the surrounding text changes when the caret bounds are not
// changed. e.g. When the rendered text is wider than the input field,
// deleting the last character won't change the caret bounds but will change
// the surrounding text.
if (GetInputMethod())
GetInputMethod()->OnCaretBoundsChanged(this);
#if defined(USE_X11)
const TextInputManager::TextSelection* selection =
GetTextInputManager()->GetTextSelection(focused_view);
if (selection->selected_text().length()) {
// Set the CLIPBOARD_TYPE_SELECTION to the ui::Clipboard.
ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_SELECTION);
clipboard_writer.WriteText(selection->selected_text());
}
#endif // defined(USE_X11)
}
void RenderWidgetHostViewAura::SetPopupChild(
RenderWidgetHostViewAura* popup_child_host_view) {
popup_child_host_view_ = popup_child_host_view;
event_handler_->SetPopupChild(
popup_child_host_view,
popup_child_host_view ? popup_child_host_view->event_handler() : nullptr);
}
void RenderWidgetHostViewAura::UpdateNeedsBeginFramesInternal() {
if (!delegated_frame_host_)
return;
delegated_frame_host_->SetNeedsBeginFrames(needs_begin_frames_);
}
void RenderWidgetHostViewAura::ScrollFocusedEditableNodeIntoRect(
const gfx::Rect& node_rect) {
RenderFrameHostImpl* rfh = GetFocusedFrame();
if (rfh) {
rfh->GetFrameInputHandler()->ScrollFocusedEditableNodeIntoRect(node_rect);
}
}
void RenderWidgetHostViewAura::OnSynchronizedDisplayPropertiesChanged() {
SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
base::nullopt);
}
viz::ScopedSurfaceIdAllocator
RenderWidgetHostViewAura::DidUpdateVisualProperties(
const cc::RenderFrameMetadata& metadata) {
base::OnceCallback<void()> allocation_task = base::BindOnce(
&RenderWidgetHostViewAura::OnDidUpdateVisualPropertiesComplete,
weak_ptr_factory_.GetWeakPtr(), metadata);
return window_->GetSurfaceIdAllocator(std::move(allocation_task));
}
void RenderWidgetHostViewAura::DidNavigate() {
if (!IsShowing()) {
// Navigating while hidden should not allocate a new LocalSurfaceID. Once
// sizes are ready, or we begin to Show, we can then allocate the new
// LocalSurfaceId.
window_->InvalidateLocalSurfaceId();
} else {
if (is_first_navigation_) {
// The first navigation does not need a new LocalSurfaceID. The renderer
// can use the ID that was already provided.
SynchronizeVisualProperties(cc::DeadlinePolicy::UseExistingDeadline(),
window_->GetLocalSurfaceIdAllocation());
} else {
SynchronizeVisualProperties(cc::DeadlinePolicy::UseExistingDeadline(),
base::nullopt);
}
}
if (delegated_frame_host_)
delegated_frame_host_->DidNavigate();
is_first_navigation_ = false;
}
// static
viz::FrameSinkId
RenderWidgetHostViewAura::AllocateFrameSinkIdForGuestViewHack() {
return ImageTransportFactory::GetInstance()
->GetContextFactoryPrivate()
->AllocateFrameSinkId();
}
MouseWheelPhaseHandler* RenderWidgetHostViewAura::GetMouseWheelPhaseHandler() {
return &event_handler_->mouse_wheel_phase_handler();
}
void RenderWidgetHostViewAura::TakeFallbackContentFrom(
RenderWidgetHostView* view) {
DCHECK(!static_cast<RenderWidgetHostViewBase*>(view)
->IsRenderWidgetHostViewChildFrame());
DCHECK(!static_cast<RenderWidgetHostViewBase*>(view)
->IsRenderWidgetHostViewGuest());
RenderWidgetHostViewAura* view_aura =
static_cast<RenderWidgetHostViewAura*>(view);
base::Optional<SkColor> color = view_aura->GetBackgroundColor();
if (color)
SetBackgroundColor(*color);
if (delegated_frame_host_ && view_aura->delegated_frame_host_) {
delegated_frame_host_->TakeFallbackContentFrom(
view_aura->delegated_frame_host_.get());
}
host()->GetContentRenderingTimeoutFrom(view_aura->host());
}
void RenderWidgetHostViewAura::InvalidateLocalSurfaceIdOnEviction() {
window_->InvalidateLocalSurfaceId();
}
} // namespace content