blob: 39bb0898fc0ff63e29e61ca4613adb95af20edf5 [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/message_loop/message_loop.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/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
#include "cc/resources/texture_mailbox.h"
#include "cc/trees/layer_tree_settings.h"
#include "components/display_compositor/gl_helper.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/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/compositor_resize_lock_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/content_switches_internal.h"
#include "content/common/input_messages.h"
#include "content/common/site_isolation_policy.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/browser/render_widget_host_view_frame_subscriber.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/content_switches.h"
#include "gpu/ipc/common/gpu_messages.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "third_party/WebKit/public/web/WebInputEvent.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/window_parenting_client.h"
#include "ui/aura/env.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_types.h"
#include "ui/compositor/compositor_vsync_manager.h"
#include "ui/compositor/dip_util.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/blink/web_input_event.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/gestures/gesture_recognizer.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/public/activation_client.h"
#include "ui/wm/public/scoped_tooltip_disabler.h"
#include "ui/wm/public/tooltip_client.h"
#include "ui/wm/public/transient_window_client.h"
#include "ui/wm/public/window_types.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/win/hidden_window.h"
#include "ui/base/win/osk_display_manager.h"
#include "ui/base/win/osk_display_observer.h"
#include "ui/display/win/screen_win.h"
#include "ui/gfx/gdi_util.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
using gfx::RectToSkIRect;
using gfx::SkIRectToRect;
using blink::WebInputEvent;
using blink::WebGestureEvent;
using blink::WebTouchEvent;
namespace content {
namespace {
// When accelerated compositing is enabled and a widget resize is pending,
// we delay further resizes of the UI. The following constant is the maximum
// length of time that we should delay further UI resizes while waiting for a
// resized frame from a renderer.
const int kResizeLockTimeoutMs = 67;
#if defined(OS_WIN)
// This class implements the ui::OnScreenKeyboardObserver 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::OnScreenKeyboardObserver {
public:
WinScreenKeyboardObserver(RenderWidgetHostImpl* host,
const gfx::Point& location_in_screen,
float scale_factor,
aura::Window* window)
: host_(host),
location_in_screen_(location_in_screen),
device_scale_factor_(scale_factor),
window_(window) {
host_->GetView()->SetInsets(gfx::Insets());
}
// base::win::OnScreenKeyboardObserver overrides.
void OnKeyboardVisible(const gfx::Rect& keyboard_rect_pixels) override {
gfx::Point location_in_pixels =
gfx::ConvertPointToPixel(device_scale_factor_, location_in_screen_);
// Restore the viewport.
host_->GetView()->SetInsets(gfx::Insets());
if (keyboard_rect_pixels.Contains(location_in_pixels)) {
aura::client::ScreenPositionClient* screen_position_client =
aura::client::GetScreenPositionClient(window_->GetRootWindow());
if (!screen_position_client)
return;
DVLOG(1) << "OSK covering focus point.";
gfx::Rect keyboard_rect =
gfx::ConvertRectToDIP(device_scale_factor_, keyboard_rect_pixels);
gfx::Rect bounds_in_screen = window_->GetBoundsInScreen();
DCHECK(bounds_in_screen.bottom() > keyboard_rect.y());
// Set the viewport of the window to be just above the on screen
// keyboard.
int viewport_bottom = bounds_in_screen.bottom() - keyboard_rect.y();
// If the viewport is bigger than the view, then we cannot handle it
// with the current approach. Moving the window above the OSK is one way.
// That for a later patchset.
if (viewport_bottom > bounds_in_screen.height())
return;
host_->GetView()->SetInsets(gfx::Insets(0, 0, viewport_bottom, 0));
gfx::Point origin(location_in_screen_);
screen_position_client->ConvertPointFromScreen(window_, &origin);
// We want to scroll the node into a rectangle which originates from
// the touch point and a small offset (10) in either direction.
gfx::Rect node_rect(origin.x(), origin.y(), 10, 10);
host_->ScrollFocusedEditableNodeIntoRect(node_rect);
}
}
void OnKeyboardHidden(const gfx::Rect& keyboard_rect_pixels) override {
// Restore the viewport.
host_->GetView()->SetInsets(gfx::Insets());
}
private:
RenderWidgetHostImpl* host_;
// The location in DIPs where the touch occurred.
gfx::Point location_in_screen_;
// The current device scale factor.
float device_scale_factor_;
// The content Window.
aura::Window* window_;
DISALLOW_COPY_AND_ASSIGN(WinScreenKeyboardObserver);
};
#endif // defined(OS_WIN)
} // namespace
// We need to watch for mouse events outside a Web Popup or its parent
// and dismiss the popup for certain events.
class RenderWidgetHostViewAura::EventFilterForPopupExit
: public ui::EventHandler {
public:
explicit EventFilterForPopupExit(RenderWidgetHostViewAura* rwhva)
: rwhva_(rwhva) {
DCHECK(rwhva_);
aura::Env::GetInstance()->AddPreTargetHandler(this);
}
~EventFilterForPopupExit() override {
aura::Env::GetInstance()->RemovePreTargetHandler(this);
}
// Overridden from ui::EventHandler
void OnMouseEvent(ui::MouseEvent* event) override {
rwhva_->ApplyEventFilterForPopupExit(event);
}
void OnTouchEvent(ui::TouchEvent* event) override {
rwhva_->ApplyEventFilterForPopupExit(event);
}
private:
RenderWidgetHostViewAura* rwhva_;
DISALLOW_COPY_AND_ASSIGN(EventFilterForPopupExit);
};
void RenderWidgetHostViewAura::ApplyEventFilterForPopupExit(
ui::LocatedEvent* event) {
if (in_shutdown_ || is_fullscreen_ || !event->target())
return;
if (event->type() != ui::ET_MOUSE_PRESSED &&
event->type() != ui::ET_TOUCH_PRESSED) {
return;
}
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();
}
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) 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* host,
bool is_guest_view_hack)
: host_(RenderWidgetHostImpl::From(host)),
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),
begin_frame_source_(nullptr),
needs_begin_frames_(false),
needs_flush_input_(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),
last_active_widget_process_id_(ChildProcessHost::kInvalidUniqueID),
last_active_widget_routing_id_(MSG_ROUTING_NONE),
event_handler_(new RenderWidgetHostViewEventHandler(host_, this, this)),
weak_ptr_factory_(this) {
// GuestViews have two RenderWidgetHostViews and so we need to make sure
// we don't have FrameSinkId collisions.
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
cc::FrameSinkId frame_sink_id =
is_guest_view_hack_
? factory->GetContextFactory()->AllocateFrameSinkId()
: cc::FrameSinkId(
base::checked_cast<uint32_t>(host_->GetProcess()->GetID()),
base::checked_cast<uint32_t>(host_->GetRoutingID()));
delegated_frame_host_ =
base::MakeUnique<DelegatedFrameHost>(frame_sink_id, this);
if (!is_guest_view_hack_)
host_->SetView(this);
// 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);
}
// We should start observing the TextInputManager for IME-related events as
// well as monitoring its lifetime.
if (GetTextInputManager())
GetTextInputManager()->AddObserver(this);
bool overscroll_enabled = base::CommandLine::ForCurrentProcess()->
GetSwitchValueASCII(switches::kOverscrollHistoryNavigation) != "0";
SetOverscrollControllerEnabled(overscroll_enabled);
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 layout tests.
ignore_result(rvh->GetWebkitPreferences());
}
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, RenderWidgetHostView implementation:
void RenderWidgetHostViewAura::InitAsChild(
gfx::NativeView parent_view) {
CreateAuraWindow();
window_->SetType(ui::wm::WINDOW_TYPE_CONTROL);
window_->Init(ui::LAYER_SOLID_COLOR);
window_->SetName("RenderWidgetHostViewAura");
window_->layer()->SetColor(background_color_);
if (parent_view)
parent_view->AddChild(GetNativeView());
const display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
device_scale_factor_ = display.device_scale_factor();
}
void RenderWidgetHostViewAura::InitAsPopup(
RenderWidgetHostView* parent_host_view,
const gfx::Rect& bounds_in_screen) {
CreateAuraWindow();
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_ = NULL;
}
popup_parent_host_view_->SetPopupChild(this);
window_->SetType(ui::wm::WINDOW_TYPE_MENU);
window_->Init(ui::LAYER_SOLID_COLOR);
window_->SetName("RenderWidgetHostViewAura");
window_->layer()->SetColor(background_color_);
// 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_filter_for_popup_exit_.reset(new EventFilterForPopupExit(this));
const display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
device_scale_factor_ = display.device_scale_factor();
}
void RenderWidgetHostViewAura::InitAsFullscreen(
RenderWidgetHostView* reference_host_view) {
CreateAuraWindow();
is_fullscreen_ = true;
window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
window_->Init(ui::LAYER_SOLID_COLOR);
window_->SetName("RenderWidgetHostViewAura");
window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
window_->layer()->SetColor(background_color_);
aura::Window* parent = NULL;
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();
const display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
device_scale_factor_ = display.device_scale_factor();
}
RenderWidgetHost* RenderWidgetHostViewAura::GetRenderWidgetHost() const {
return host_;
}
void RenderWidgetHostViewAura::Show() {
window_->Show();
if (!host_->is_hidden())
return;
bool has_saved_frame = delegated_frame_host_->HasSavedFrame();
ui::LatencyInfo renderer_latency_info, browser_latency_info;
if (has_saved_frame) {
browser_latency_info.AddLatencyNumber(
ui::TAB_SHOW_COMPONENT, host_->GetLatencyComponentId(), 0);
} else {
renderer_latency_info.AddLatencyNumber(
ui::TAB_SHOW_COMPONENT, host_->GetLatencyComponentId(), 0);
}
host_->WasShown(renderer_latency_info);
aura::Window* root = window_->GetRootWindow();
if (root) {
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(root);
if (cursor_client)
NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible());
}
delegated_frame_host_->WasShown(browser_latency_info);
#if defined(OS_WIN)
UpdateLegacyWin();
#endif
}
void RenderWidgetHostViewAura::Hide() {
window_->Hide();
// TODO(wjmaclean): can host_ ever be null?
if (host_ && !host_->is_hidden()) {
host_->WasHidden();
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
}
void RenderWidgetHostViewAura::SetSize(const gfx::Size& size) {
// 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) {
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::Vector2dF RenderWidgetHostViewAura::GetLastScrollOffset() const {
return last_scroll_offset_;
}
gfx::NativeView RenderWidgetHostViewAura::GetNativeView() const {
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* host = window_->GetHost();
if (!host)
return static_cast<gfx::NativeViewAccessible>(NULL);
BrowserAccessibilityManager* manager =
host_->GetOrCreateRootBrowserAccessibilityManager();
if (manager)
return ToBrowserAccessibilityWin(manager->GetRoot());
#endif
NOTIMPLEMENTED();
return static_cast<gfx::NativeViewAccessible>(NULL);
}
ui::TextInputClient* RenderWidgetHostViewAura::GetTextInputClient() {
return this;
}
void RenderWidgetHostViewAura::SetNeedsBeginFrames(bool needs_begin_frames) {
needs_begin_frames_ = needs_begin_frames;
UpdateNeedsBeginFramesInternal();
}
void RenderWidgetHostViewAura::OnSetNeedsFlushInput() {
needs_flush_input_ = true;
UpdateNeedsBeginFramesInternal();
}
void RenderWidgetHostViewAura::UpdateNeedsBeginFramesInternal() {
if (!begin_frame_source_)
return;
bool needs_frame = needs_begin_frames_ || needs_flush_input_;
if (needs_frame == added_frame_observer_)
return;
added_frame_observer_ = needs_frame;
if (needs_frame)
begin_frame_source_->AddObserver(this);
else
begin_frame_source_->RemoveObserver(this);
}
void RenderWidgetHostViewAura::OnBeginFrame(
const cc::BeginFrameArgs& args) {
needs_flush_input_ = false;
host_->FlushInput();
UpdateNeedsBeginFramesInternal();
host_->Send(new ViewMsg_BeginFrame(host_->GetRoutingID(), args));
last_begin_frame_args_ = args;
}
const cc::BeginFrameArgs& RenderWidgetHostViewAura::LastUsedBeginFrameArgs()
const {
return last_begin_frame_args_;
}
void RenderWidgetHostViewAura::OnBeginFrameSourcePausedChanged(bool paused) {
// Only used on Android WebView.
}
RenderFrameHostImpl* RenderWidgetHostViewAura::GetFocusedFrame() {
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 {
return delegated_frame_host_->CanCopyToBitmap();
}
bool RenderWidgetHostViewAura::IsShowing() {
return window_->IsVisible();
}
gfx::Rect RenderWidgetHostViewAura::GetViewBounds() const {
return window_->GetBoundsInScreen();
}
void RenderWidgetHostViewAura::SetBackgroundColor(SkColor color) {
RenderWidgetHostViewBase::SetBackgroundColor(color);
bool opaque = GetBackgroundOpaque();
host_->SetBackgroundOpaque(opaque);
window_->layer()->SetFillsBoundsOpaquely(opaque);
window_->layer()->SetColor(color);
}
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_->WasResized();
}
}
void RenderWidgetHostViewAura::FocusedNodeTouched(
const gfx::Point& location_dips_screen,
bool editable) {
#if defined(OS_WIN)
RenderViewHost* rvh = RenderViewHost::From(host_);
if (rvh && rvh->GetDelegate())
rvh->GetDelegate()->SetIsVirtualKeyboardRequested(editable);
ui::OnScreenKeyboardDisplayManager* osk_display_manager =
ui::OnScreenKeyboardDisplayManager::GetInstance();
DCHECK(osk_display_manager);
if (editable && host_ && host_->GetView()) {
keyboard_observer_.reset(new WinScreenKeyboardObserver(
host_, location_dips_screen, device_scale_factor_, window_));
virtual_keyboard_requested_ =
osk_display_manager->DisplayVirtualKeyboard(keyboard_observer_.get());
} else {
virtual_keyboard_requested_ = false;
osk_display_manager->DismissVirtualKeyboard();
}
#endif
}
void RenderWidgetHostViewAura::UpdateCursor(const WebCursor& cursor) {
current_cursor_ = cursor;
const display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
current_cursor_.SetDisplayInfo(display);
UpdateCursorIfOverSelf();
}
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) {
tooltip_ = tooltip_text;
aura::Window* root_window = window_->GetRootWindow();
aura::client::TooltipClient* tooltip_client =
aura::client::GetTooltipClient(root_window);
if (tooltip_client) {
tooltip_client->UpdateTooltip(window_);
// Content tooltips should be visible indefinitely.
tooltip_client->SetTooltipShownTimeout(window_, 0);
}
}
gfx::Size RenderWidgetHostViewAura::GetRequestedRendererSize() const {
return delegated_frame_host_->GetRequestedRendererSize();
}
void RenderWidgetHostViewAura::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const ReadbackRequestCallback& callback,
const SkColorType preferred_color_type) {
delegated_frame_host_->CopyFromCompositingSurface(
src_subrect, dst_size, callback, preferred_color_type);
}
void RenderWidgetHostViewAura::CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
const base::Callback<void(const gfx::Rect&, bool)>& callback) {
delegated_frame_host_->CopyFromCompositingSurfaceToVideoFrame(
src_subrect, target, callback);
}
bool RenderWidgetHostViewAura::CanCopyToVideoFrame() const {
return delegated_frame_host_->CanCopyToVideoFrame();
}
void RenderWidgetHostViewAura::BeginFrameSubscription(
std::unique_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) {
delegated_frame_host_->BeginFrameSubscription(std::move(subscriber));
}
void RenderWidgetHostViewAura::EndFrameSubscription() {
delegated_frame_host_->EndFrameSubscription();
}
#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_ = NULL;
legacy_window_destroyed_ = true;
}
#endif
void RenderWidgetHostViewAura::OnSwapCompositorFrame(
uint32_t compositor_frame_sink_id,
cc::CompositorFrame frame) {
TRACE_EVENT0("content", "RenderWidgetHostViewAura::OnSwapCompositorFrame");
last_scroll_offset_ = frame.metadata.root_scroll_offset;
if (!frame.delegated_frame_data)
return;
cc::Selection<gfx::SelectionBound> selection = frame.metadata.selection;
if (IsUseZoomForDSFEnabled()) {
float viewportToDIPScale = 1.0f / current_device_scale_factor_;
gfx::PointF start_edge_top = selection.start.edge_top();
gfx::PointF start_edge_bottom = selection.start.edge_bottom();
gfx::PointF end_edge_top = selection.end.edge_top();
gfx::PointF end_edge_bottom = selection.end.edge_bottom();
start_edge_top.Scale(viewportToDIPScale);
start_edge_bottom.Scale(viewportToDIPScale);
end_edge_top.Scale(viewportToDIPScale);
end_edge_bottom.Scale(viewportToDIPScale);
selection.start.SetEdge(start_edge_top, start_edge_bottom);
selection.end.SetEdge(end_edge_top, end_edge_bottom);
}
delegated_frame_host_->SwapDelegatedFrame(compositor_frame_sink_id,
std::move(frame));
SelectionUpdated(selection.is_editable, selection.is_empty_text_form_control,
selection.start, selection.end);
}
void RenderWidgetHostViewAura::ClearCompositorFrame() {
delegated_frame_host_->ClearDelegatedFrame();
}
void RenderWidgetHostViewAura::DidStopFlinging() {
selection_controller_client_->OnScrollCompleted();
}
bool RenderWidgetHostViewAura::HasAcceleratedSurface(
const gfx::Size& desired_size) {
// Aura doesn't use GetBackingStore for accelerated pages, so it doesn't
// matter what is returned here as GetBackingStore is the only caller of this
// method. TODO(jbates) implement this if other Aura code needs it.
return false;
}
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));
}
}
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::GestureEventAck(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
if (overscroll_controller_) {
overscroll_controller_->ReceivedEventACK(
event, (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result));
}
}
void RenderWidgetHostViewAura::ProcessAckedTouchEvent(
const TouchEventWithLatencyInfo& touch,
InputEventAckState ack_result) {
ScopedVector<ui::TouchEvent> events;
aura::WindowTreeHost* host = window_->GetHost();
// |host| is NULL during tests.
if (!host)
return;
// The TouchScrollStarted event is generated & consumed downstream from the
// TouchEventQueue. So we don't expect an ACK up here.
DCHECK(touch.event.type != blink::WebInputEvent::TouchScrollStarted);
ui::EventResult result = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
? ui::ER_HANDLED
: ui::ER_UNHANDLED;
blink::WebTouchPoint::State required_state;
switch (touch.event.type) {
case blink::WebInputEvent::TouchStart:
required_state = blink::WebTouchPoint::StatePressed;
break;
case blink::WebInputEvent::TouchEnd:
required_state = blink::WebTouchPoint::StateReleased;
break;
case blink::WebInputEvent::TouchMove:
required_state = blink::WebTouchPoint::StateMoved;
break;
case blink::WebInputEvent::TouchCancel:
required_state = blink::WebTouchPoint::StateCancelled;
break;
default:
required_state = blink::WebTouchPoint::StateUndefined;
NOTREACHED();
break;
}
// Only send acks for one changed touch point.
bool sent_ack = false;
for (size_t i = 0; i < touch.event.touchesLength; ++i) {
if (touch.event.touches[i].state == required_state) {
DCHECK(!sent_ack);
host->dispatcher()->ProcessedTouchEvent(touch.event.uniqueTouchEventId,
window_, result);
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.type == WebInputEvent::GestureFlingStart) {
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::WebGestureDeviceTouchpad &&
!gesture_event.data.flingStart.velocityX &&
!gesture_event.data.flingStart.velocityY) {
consumed = true;
}
}
if (overscroll_controller_)
consumed |= overscroll_controller_->WillHandleEvent(input_event);
// Touch events should always propagate to the renderer.
if (WebTouchEvent::isTouchEventType(input_event.type))
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
if (consumed && input_event.type == blink::WebInputEvent::GestureFlingStart) {
// 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;
}
BrowserAccessibilityManager*
RenderWidgetHostViewAura::CreateBrowserAccessibilityManager(
BrowserAccessibilityDelegate* delegate, bool for_root_frame) {
BrowserAccessibilityManager* manager = NULL;
#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 NULL;
}
bool RenderWidgetHostViewAura::LockMouse() {
return event_handler_->LockMouse();
}
void RenderWidgetHostViewAura::UnlockMouse() {
event_handler_->UnlockMouse();
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, ui::TextInputClient implementation:
void RenderWidgetHostViewAura::SetCompositionText(
const ui::CompositionText& composition) {
if (!text_input_manager_ || !text_input_manager_->GetActiveWidget())
return;
// TODO(suzhe): convert both renderer_host and renderer to use
// ui::CompositionText.
std::vector<blink::WebCompositionUnderline> underlines;
underlines.reserve(composition.underlines.size());
for (std::vector<ui::CompositionUnderline>::const_iterator it =
composition.underlines.begin();
it != composition.underlines.end(); ++it) {
underlines.push_back(
blink::WebCompositionUnderline(static_cast<unsigned>(it->start_offset),
static_cast<unsigned>(it->end_offset),
it->color,
it->thick,
it->background_color));
}
// 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, underlines, 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, 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
// TODO(wjmaclean): can host_ ever be null?
if (host_ && (event_handler_->accept_return_character() ||
event.GetCharacter() != ui::VKEY_RETURN)) {
// Send a blink::WebInputEvent::Char event to |host_|.
ForwardKeyboardEvent(NativeWebKeyboardEvent(event, event.GetCharacter()));
}
}
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();
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::Point origin = rect.origin();
gfx::Point end = gfx::Point(rect.right(), rect.bottom());
aura::Window* root_window = window_->GetRootWindow();
if (root_window) {
aura::client::ScreenPositionClient* screen_position_client =
aura::client::GetScreenPositionClient(root_window);
screen_position_client->ConvertPointFromScreen(window_, &origin);
screen_position_client->ConvertPointFromScreen(window_, &end);
return gfx::Rect(origin.x(),
origin.y(),
end.x() - origin.x(),
end.y() - origin.y());
}
return rect;
}
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_;
}
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();
return false;
}
bool RenderWidgetHostViewAura::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;
}
bool RenderWidgetHostViewAura::SetSelectionRange(const gfx::Range& range) {
// TODO(suzhe): implement this method when fixing http://crbug.com/55130.
NOTIMPLEMENTED();
return false;
}
bool RenderWidgetHostViewAura::DeleteRange(const gfx::Range& range) {
// TODO(suzhe): implement this method when fixing http://crbug.com/55130.
NOTIMPLEMENTED();
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(wjmaclean): can host_ ever be null?
if (!host_)
return;
// 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::WebTextDirectionRightToLeft
: blink::WebTextDirectionLeftToRight);
GetTextInputManager()->GetActiveWidget()->NotifyTextDirection();
return true;
}
void RenderWidgetHostViewAura::ExtendSelectionAndDelete(
size_t before, size_t after) {
RenderFrameHostImpl* rfh = GetFocusedFrame();
if (rfh)
rfh->ExtendSelectionAndDelete(before, after);
}
void RenderWidgetHostViewAura::EnsureCaretInRect(const gfx::Rect& rect) {
gfx::Rect intersected_rect(
gfx::IntersectRects(rect, window_->GetBoundsInScreen()));
if (intersected_rect.IsEmpty())
return;
host_->ScrollFocusedEditableNodeIntoRect(
ConvertRectFromScreen(intersected_rect));
}
bool RenderWidgetHostViewAura::IsTextEditCommandEnabled(
ui::TextEditCommand command) const {
return false;
}
void RenderWidgetHostViewAura::SetTextEditCommandForNextKeyEvent(
ui::TextEditCommand command) {}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, display::DisplayObserver implementation:
void RenderWidgetHostViewAura::OnDisplayAdded(
const display::Display& new_display) {}
void RenderWidgetHostViewAura::OnDisplayRemoved(
const display::Display& old_display) {}
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 (mouse_locked_)
return ui::kCursorNone;
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 popup_type_ == blink::WebPopupTypeNone;
}
void RenderWidgetHostViewAura::OnCaptureLost() {
host_->LostCapture();
}
void RenderWidgetHostViewAura::OnPaint(const ui::PaintContext& context) {
NOTREACHED();
}
void RenderWidgetHostViewAura::OnDeviceScaleFactorChanged(
float device_scale_factor) {
if (!window_->GetRootWindow())
return;
RenderWidgetHostImpl* host =
RenderWidgetHostImpl::From(GetRenderWidgetHost());
if (host && host->delegate())
host->delegate()->UpdateDeviceScaleFactor(device_scale_factor);
device_scale_factor_ = device_scale_factor;
const display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
DCHECK_EQ(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_->set_host(NULL);
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 {
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, ui::EventHandler implementation:
void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) {
event_handler_->OnKeyEvent(event);
}
void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
event_handler_->OnMouseEvent(event);
}
cc::FrameSinkId RenderWidgetHostViewAura::FrameSinkIdAtPoint(
cc::SurfaceHittestDelegate* delegate,
const gfx::Point& point,
gfx::Point* transformed_point) {
DCHECK(device_scale_factor_ != 0.0f);
// The surface hittest happens in device pixels, so we need to convert the
// |point| from DIPs to pixels before hittesting.
gfx::Point point_in_pixels =
gfx::ConvertPointToPixel(device_scale_factor_, point);
cc::SurfaceId id = delegated_frame_host_->SurfaceIdAtPoint(
delegate, point_in_pixels, transformed_point);
*transformed_point =
gfx::ConvertPointToDIP(device_scale_factor_, *transformed_point);
// It is possible that the renderer has not yet produced a surface, in which
// case we return our current namespace.
if (id.is_null())
return GetFrameSinkId();
return id.frame_sink_id();
}
void RenderWidgetHostViewAura::ProcessMouseEvent(
const blink::WebMouseEvent& event,
const ui::LatencyInfo& latency) {
host_->ForwardMouseEventWithLatencyInfo(event, latency);
}
void RenderWidgetHostViewAura::ProcessMouseWheelEvent(
const blink::WebMouseWheelEvent& event,
const ui::LatencyInfo& latency) {
host_->ForwardWheelEventWithLatencyInfo(event, latency);
}
void RenderWidgetHostViewAura::ProcessTouchEvent(
const blink::WebTouchEvent& event,
const ui::LatencyInfo& latency) {
host_->ForwardTouchEventWithLatencyInfo(event, latency);
}
void RenderWidgetHostViewAura::ProcessGestureEvent(
const blink::WebGestureEvent& event,
const ui::LatencyInfo& latency) {
host_->ForwardGestureEventWithLatencyInfo(event, latency);
}
bool RenderWidgetHostViewAura::TransformPointToLocalCoordSpace(
const gfx::Point& point,
const cc::SurfaceId& original_surface,
gfx::Point* transformed_point) {
// Transformations use physical pixels rather than DIP, so conversion
// is necessary.
gfx::Point point_in_pixels =
gfx::ConvertPointToPixel(device_scale_factor_, point);
if (!delegated_frame_host_->TransformPointToLocalCoordSpace(
point_in_pixels, original_surface, transformed_point))
return false;
*transformed_point =
gfx::ConvertPointToDIP(device_scale_factor_, *transformed_point);
return true;
}
bool RenderWidgetHostViewAura::TransformPointToCoordSpaceForView(
const gfx::Point& point,
RenderWidgetHostViewBase* target_view,
gfx::Point* transformed_point) {
// 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 delegated_frame_host_->TransformPointToCoordSpaceForView(
point, target_view, transformed_point);
}
void RenderWidgetHostViewAura::FocusedNodeChanged(
bool editable,
const gfx::Rect& node_bounds_in_screen) {
#if defined(OS_WIN)
if (!editable && virtual_keyboard_requested_) {
virtual_keyboard_requested_ = false;
RenderViewHost* rvh = RenderViewHost::From(host_);
if (rvh && rvh->GetDelegate())
rvh->GetDelegate()->SetIsVirtualKeyboardRequested(false);
DCHECK(ui::OnScreenKeyboardDisplayManager::GetInstance());
ui::OnScreenKeyboardDisplayManager::GetInstance()->DismissVirtualKeyboard();
}
#endif
}
void RenderWidgetHostViewAura::OnScrollEvent(ui::ScrollEvent* event) {
event_handler_->OnScrollEvent(event);
}
void RenderWidgetHostViewAura::OnTouchEvent(ui::TouchEvent* event) {
event_handler_->OnTouchEvent(event);
}
void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event) {
event_handler_->OnGestureEvent(event);
}
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, aura::client::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_->ignore_input_events())
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);
// Often the application can set focus to the view in response to a key
// down. However the following char event shouldn't be sent to the web
// page.
host_->SuppressNextCharEvents();
}
BrowserAccessibilityManager* manager =
host_->GetRootBrowserAccessibilityManager();
if (manager)
manager->OnWindowFocused();
} else if (window_ == lost_focus) {
host_->SetActive(false);
host_->Blur();
DetachFromInputMethod();
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::OnHostMoved(const aura::WindowTreeHost* host,
const gfx::Point& new_origin) {
TRACE_EVENT1("ui", "RenderWidgetHostViewAura::OnHostMoved",
"new_origin", new_origin.ToString());
UpdateScreenInfo(window_);
}
////////////////////////////////////////////////////////////////////////////////
// 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();
delegated_frame_host_.reset();
window_observer_.reset();
if (window_) {
if (window_->GetHost())
window_->GetHost()->RemoveObserver(this);
UnlockMouse();
aura::client::SetTooltipText(window_, NULL);
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_ == NULL ||
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_ == NULL ||
popup_child_host_view_->popup_parent_host_view_ == this);
popup_child_host_view_->popup_parent_host_view_ = NULL;
}
event_filter_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_);
if (virtual_keyboard_requested_) {
DCHECK(keyboard_observer_.get());
ui::OnScreenKeyboardDisplayManager* osk_display_manager =
ui::OnScreenKeyboardDisplayManager::GetInstance();
DCHECK(osk_display_manager);
osk_display_manager->RemoveObserver(keyboard_observer_.get());
}
#endif
if (text_input_manager_)
text_input_manager_->RemoveObserver(this);
}
void RenderWidgetHostViewAura::CreateAuraWindow() {
DCHECK(!window_);
window_ = new aura::Window(this);
event_handler_->set_window(window_);
window_observer_.reset(new WindowObserver(this));
aura::client::SetTooltipText(window_, &tooltip_);
aura::client::SetActivationDelegate(window_, this);
aura::client::SetFocusChangeObserver(window_, this);
window_->set_layer_owner_delegate(delegated_frame_host_.get());
display::Screen::GetScreen()->AddObserver(this);
}
void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() {
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::kCursorNone)
cursor = ui::kCursorPointer;
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(root_window);
if (cursor_client) {
cursor_client->SetCursor(cursor);
}
}
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();
}
void RenderWidgetHostViewAura::Shutdown() {
if (!in_shutdown_) {
in_shutdown_ = true;
host_->ShutdownAndDestroyWidget(true);
}
}
bool RenderWidgetHostViewAura::NeedsInputGrab() {
return popup_type_ == blink::WebPopupTypePage;
}
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 aura::client::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::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.
#if defined(OS_CHROMEOS)
aura::Window* snapped = window_->GetToplevelWindow();
#else
aura::Window* snapped = window_->GetRootWindow();
#endif
if (snapped && snapped != window_)
ui::SnapLayerToPhysicalPixelBoundary(snapped->layer(), window_->layer());
has_snapped_to_boundary_ = true;
}
bool RenderWidgetHostViewAura::OnShowContextMenu(
const ContextMenuParams& params) {
#if defined(OS_WIN)
event_handler_->SetContextMenuParams(params);
return params.source_type != ui::MENU_SOURCE_LONG_PRESS;
#else
return true;
#endif // defined(OS_WIN)
}
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);
host_->WasResized();
delegated_frame_host_->WasResized();
#if defined(OS_WIN)
UpdateLegacyWin();
if (mouse_locked_)
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
delegated_frame_host_->SetCompositor(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);
delegated_frame_host_->ResetCompositor();
#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);
}
void RenderWidgetHostViewAura::ForwardKeyboardEvent(
const NativeWebKeyboardEvent& 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->Send(new InputMsg_SetEditCommandsForNextKeyEvent(
target_host->GetRoutingID(), edit_commands));
target_host->ForwardKeyboardEvent(event);
return;
}
#endif
target_host->ForwardKeyboardEvent(event);
}
void RenderWidgetHostViewAura::SelectionUpdated(
bool is_editable,
bool is_empty_text_form_control,
const gfx::SelectionBound& start,
const gfx::SelectionBound& end) {
selection_controller_->OnSelectionEditable(is_editable);
selection_controller_->OnSelectionEmpty(is_empty_text_form_control);
selection_controller_->OnSelectionBoundsChanged(start, end);
}
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));
}
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost, public:
ui::Layer* RenderWidgetHostViewAura::DelegatedFrameHostGetLayer() const {
return window_->layer();
}
bool RenderWidgetHostViewAura::DelegatedFrameHostIsVisible() const {
return !host_->is_hidden();
}
SkColor RenderWidgetHostViewAura::DelegatedFrameHostGetGutterColor(
SkColor color) const {
// When making an element on the page fullscreen the element's background
// may not match the page's, so use black as the gutter color to avoid
// flashes of brighter colors during the transition.
if (host_->delegate() && host_->delegate()->IsFullscreenForCurrentTab())
return SK_ColorBLACK;
return color;
}
gfx::Size RenderWidgetHostViewAura::DelegatedFrameHostDesiredSizeInDIP() const {
return window_->bounds().size();
}
bool RenderWidgetHostViewAura::DelegatedFrameCanCreateResizeLock() const {
#if !defined(OS_CHROMEOS)
// On Windows and Linux, holding pointer moves will not help throttling
// resizes.
// TODO(piman): on Windows we need to block (nested message loop?) the
// WM_SIZE event. On Linux we need to throttle at the WM level using
// _NET_WM_SYNC_REQUEST.
return false;
#else
if (host_->auto_resize_enabled())
return false;
return true;
#endif
}
std::unique_ptr<ResizeLock>
RenderWidgetHostViewAura::DelegatedFrameHostCreateResizeLock(
bool defer_compositor_lock) {
gfx::Size desired_size = window_->bounds().size();
return std::unique_ptr<ResizeLock>(new CompositorResizeLock(
window_->GetHost(), desired_size, defer_compositor_lock,
base::TimeDelta::FromMilliseconds(kResizeLockTimeoutMs)));
}
void RenderWidgetHostViewAura::DelegatedFrameHostResizeLockWasReleased() {
host_->WasResized();
}
void RenderWidgetHostViewAura::DelegatedFrameHostSendReclaimCompositorResources(
int compositor_frame_sink_id,
bool is_swap_ack,
const cc::ReturnedResourceArray& resources) {
host_->Send(new ViewMsg_ReclaimCompositorResources(
host_->GetRoutingID(), compositor_frame_sink_id, is_swap_ack, resources));
}
void RenderWidgetHostViewAura::SetBeginFrameSource(
cc::BeginFrameSource* source) {
if (begin_frame_source_ && added_frame_observer_) {
begin_frame_source_->RemoveObserver(this);
added_frame_observer_ = false;
}
begin_frame_source_ = source;
UpdateNeedsBeginFramesInternal();
}
bool RenderWidgetHostViewAura::IsAutoResizeEnabled() const {
return host_->auto_resize_enabled();
}
void RenderWidgetHostViewAura::OnDidNavigateMainFrameToNewPage() {
ui::GestureRecognizer::Get()->CancelActiveTouches(window_);
}
void RenderWidgetHostViewAura::LockCompositingSurface() {
NOTIMPLEMENTED();
}
void RenderWidgetHostViewAura::UnlockCompositingSurface() {
NOTIMPLEMENTED();
}
cc::FrameSinkId RenderWidgetHostViewAura::GetFrameSinkId() {
return delegated_frame_host_->GetFrameSinkId();
}
cc::SurfaceId RenderWidgetHostViewAura::SurfaceIdForTesting() const {
return delegated_frame_host_->SurfaceIdForTesting();
}
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->show_ime_if_needed)
GetInputMethod()->ShowImeIfNeeded();
if (state && state->type != ui::TEXT_INPUT_TYPE_NONE) {
// Start monitoring the composition information if the focused node is
// editable.
RenderWidgetHostImpl* last_active_widget =
text_input_manager_->GetActiveWidget();
last_active_widget_routing_id_ = last_active_widget->GetRoutingID();
last_active_widget_process_id_ = last_active_widget->GetProcess()->GetID();
last_active_widget->Send(new InputMsg_RequestCompositionUpdate(
last_active_widget->GetRoutingID(), false /* immediate request */,
true /* monitor request */));
} else {
// Stop monitoring the composition information if the focused node is not
// editable.
RenderWidgetHostImpl* last_active_widget = RenderWidgetHostImpl::FromID(
last_active_widget_process_id_, last_active_widget_routing_id_);
if (last_active_widget) {
last_active_widget->Send(new InputMsg_RequestCompositionUpdate(
last_active_widget->GetRoutingID(), false /* immediate request */,
false /* monitor request */));
}
last_active_widget_routing_id_ = MSG_ROUTING_NONE;
last_active_widget_process_id_ = ChildProcessHost::kInvalidUniqueID;
}
}
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) {
if (GetInputMethod())
GetInputMethod()->OnCaretBoundsChanged(this);
}
void RenderWidgetHostViewAura::OnTextSelectionChanged(
TextInputManager* text_input_manager,
RenderWidgetHostViewBase* updated_view) {
#if defined(USE_X11) && !defined(OS_CHROMEOS)
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;
base::string16 selected_text;
if (GetTextInputManager()
->GetTextSelection(focused_view)
->GetSelectedText(&selected_text)) {
// Set the CLIPBOARD_TYPE_SELECTION to the ui::Clipboard.
ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_SELECTION);
clipboard_writer.WriteText(selected_text);
}
#endif // defined(USE_X11) && !defined(OS_CHROMEOS)
}
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);
}
} // namespace content