| // 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 "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/command_line.h" |
| #include "base/debug/trace_event.h" |
| #include "base/logging.h" |
| #include "base/message_loop.h" |
| #include "base/string_number_conversions.h" |
| #include "content/browser/renderer_host/backing_store_aura.h" |
| #include "content/browser/renderer_host/dip_util.h" |
| #include "content/browser/renderer_host/render_view_host_delegate.h" |
| #include "content/browser/renderer_host/render_widget_host_impl.h" |
| #include "content/browser/renderer_host/web_input_event_aura.h" |
| #include "content/common/gpu/client/gl_helper.h" |
| #include "content/common/gpu/gpu_messages.h" |
| #include "content/common/view_messages.h" |
| #include "content/port/browser/render_widget_host_view_port.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_view_host.h" |
| #include "content/public/browser/user_metrics.h" |
| #include "content/public/common/content_switches.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderline.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/client/cursor_client.h" |
| #include "ui/aura/client/screen_position_client.h" |
| #include "ui/aura/client/stacking_client.h" |
| #include "ui/aura/client/tooltip_client.h" |
| #include "ui/aura/client/window_types.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/root_window.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_observer.h" |
| #include "ui/aura/window_tracker.h" |
| #include "ui/base/clipboard/scoped_clipboard_writer.h" |
| #include "ui/base/events/event.h" |
| #include "ui/base/gestures/gesture_recognizer.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.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/display.h" |
| #include "ui/gfx/screen.h" |
| #include "ui/gfx/skia_util.h" |
| |
| #if defined(OS_WIN) |
| #include "ui/base/win/hidden_window.h" |
| #endif |
| |
| using WebKit::WebScreenInfo; |
| using WebKit::WebTouchEvent; |
| |
| namespace content { |
| namespace { |
| |
| // In mouse lock mode, we need to prevent the (invisible) cursor from hitting |
| // the border of the view, in order to get valid movement information. However, |
| // forcing the cursor back to the center of the view after each mouse move |
| // doesn't work well. It reduces the frequency of useful mouse move messages |
| // significantly. Therefore, we move the cursor to the center of the view only |
| // if it approaches the border. |kMouseLockBorderPercentage| specifies the width |
| // of the border area, in percentage of the corresponding dimension. |
| const int kMouseLockBorderPercentage = 15; |
| |
| // 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) |
| // Used to associate a plugin HWND with its RenderWidgetHostViewAura instance. |
| const wchar_t kWidgetOwnerProperty[] = L"RenderWidgetHostViewAuraOwner"; |
| |
| BOOL CALLBACK WindowDestroyingCallback(HWND window, LPARAM param) { |
| RenderWidgetHostViewAura* widget = |
| reinterpret_cast<RenderWidgetHostViewAura*>(param); |
| if (GetProp(window, kWidgetOwnerProperty) == widget) { |
| // Properties set on HWNDs must be removed to avoid leaks. |
| RemoveProp(window, kWidgetOwnerProperty); |
| RenderWidgetHostViewBase::DetachPluginWindowsCallback(window); |
| } |
| return TRUE; |
| } |
| |
| BOOL CALLBACK HideWindowsCallback(HWND window, LPARAM param) { |
| RenderWidgetHostViewAura* widget = |
| reinterpret_cast<RenderWidgetHostViewAura*>(param); |
| if (GetProp(window, kWidgetOwnerProperty) == widget) |
| SetParent(window, ui::GetHiddenWindow()); |
| return TRUE; |
| } |
| |
| BOOL CALLBACK ShowWindowsCallback(HWND window, LPARAM param) { |
| RenderWidgetHostViewAura* widget = |
| reinterpret_cast<RenderWidgetHostViewAura*>(param); |
| |
| HWND parent = |
| widget->GetNativeView()->GetRootWindow()->GetAcceleratedWidget(); |
| if (GetProp(window, kWidgetOwnerProperty) == widget) |
| SetParent(window, parent); |
| return TRUE; |
| } |
| #endif |
| |
| ui::TouchStatus DecideTouchStatus(const WebKit::WebTouchEvent& event, |
| WebKit::WebTouchPoint* point) { |
| if (event.type == WebKit::WebInputEvent::TouchEnd && |
| event.touchesLength == 0) |
| return ui::TOUCH_STATUS_QUEUED_END; |
| |
| return ui::TOUCH_STATUS_QUEUED; |
| } |
| |
| void UpdateWebTouchEventAfterDispatch(WebKit::WebTouchEvent* event, |
| WebKit::WebTouchPoint* point) { |
| if (point->state != WebKit::WebTouchPoint::StateReleased) |
| return; |
| --event->touchesLength; |
| for (unsigned i = point - event->touches; |
| i < event->touchesLength; |
| ++i) { |
| event->touches[i] = event->touches[i + 1]; |
| } |
| } |
| |
| bool CanRendererHandleEvent(const ui::MouseEvent* event) { |
| if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED) |
| return false; |
| |
| #if defined(OS_WIN) |
| // Renderer cannot handle WM_XBUTTON events. |
| switch (event->native_event().message) { |
| case WM_XBUTTONDOWN: |
| case WM_XBUTTONUP: |
| case WM_XBUTTONDBLCLK: |
| case WM_NCXBUTTONDOWN: |
| case WM_NCXBUTTONUP: |
| case WM_NCXBUTTONDBLCLK: |
| return false; |
| default: |
| break; |
| } |
| #endif |
| return true; |
| } |
| |
| void GetScreenInfoForWindow(WebScreenInfo* results, aura::Window* window) { |
| const gfx::Display display = window ? |
| gfx::Screen::GetDisplayNearestWindow(window) : |
| gfx::Screen::GetPrimaryDisplay(); |
| const gfx::Size size = display.size(); |
| results->rect = WebKit::WebRect(0, 0, size.width(), size.height()); |
| results->availableRect = results->rect; |
| // TODO(derat|oshima): Don't hardcode this. Get this from display object. |
| results->depth = 24; |
| results->depthPerComponent = 8; |
| int default_dpi = display.device_scale_factor() * 160; |
| results->verticalDPI = default_dpi; |
| results->horizontalDPI = default_dpi; |
| } |
| |
| bool ShouldSendPinchGesture() { |
| static bool pinch_allowed = |
| CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableViewport) || |
| CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePinch); |
| return pinch_allowed; |
| } |
| |
| bool ShouldReleaseFrontSurface() { |
| static bool release_front_surface_allowed = |
| CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableUIReleaseFrontSurface); |
| return release_front_surface_allowed; |
| } |
| |
| } // namespace |
| |
| // 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) {} |
| virtual ~WindowObserver() {} |
| |
| // Overridden from aura::WindowObserver: |
| virtual void OnWindowRemovingFromRootWindow(aura::Window* window) OVERRIDE { |
| view_->RemovingFromRootWindow(); |
| } |
| |
| private: |
| RenderWidgetHostViewAura* view_; |
| |
| DISALLOW_COPY_AND_ASSIGN(WindowObserver); |
| }; |
| |
| class RenderWidgetHostViewAura::ResizeLock { |
| public: |
| ResizeLock(aura::RootWindow* root_window, const gfx::Size new_size) |
| : root_window_(root_window), |
| new_size_(new_size), |
| compositor_lock_(root_window_->GetCompositorLock()), |
| weak_ptr_factory_(this) { |
| root_window_->HoldMouseMoves(); |
| |
| BrowserThread::PostDelayedTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&RenderWidgetHostViewAura::ResizeLock::CancelLock, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::TimeDelta::FromMilliseconds(kResizeLockTimeoutMs)); |
| } |
| |
| ~ResizeLock() { |
| CancelLock(); |
| } |
| |
| void UnlockCompositor() { |
| compositor_lock_ = NULL; |
| } |
| |
| void CancelLock() { |
| if (!root_window_) |
| return; |
| UnlockCompositor(); |
| root_window_->ReleaseMouseMoves(); |
| root_window_ = NULL; |
| } |
| |
| const gfx::Size& expected_size() const { |
| return new_size_; |
| } |
| |
| private: |
| aura::RootWindow* root_window_; |
| gfx::Size new_size_; |
| scoped_refptr<aura::CompositorLock> compositor_lock_; |
| base::WeakPtrFactory<ResizeLock> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ResizeLock); |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, public: |
| |
| RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host) |
| : host_(RenderWidgetHostImpl::From(host)), |
| ALLOW_THIS_IN_INITIALIZER_LIST(window_(new aura::Window(this))), |
| in_shutdown_(false), |
| is_fullscreen_(false), |
| popup_parent_host_view_(NULL), |
| popup_child_host_view_(NULL), |
| is_loading_(false), |
| text_input_type_(ui::TEXT_INPUT_TYPE_NONE), |
| can_compose_inline_(true), |
| has_composition_text_(false), |
| device_scale_factor_(1.0f), |
| current_surface_(0), |
| current_surface_is_protected_(true), |
| current_surface_in_use_by_compositor_(true), |
| protection_state_id_(0), |
| surface_route_id_(0), |
| paint_canvas_(NULL), |
| synthetic_move_sent_(false), |
| accelerated_compositing_state_changed_(false) { |
| host_->SetView(this); |
| window_observer_.reset(new WindowObserver(this)); |
| window_->AddObserver(window_observer_.get()); |
| aura::client::SetTooltipText(window_, &tooltip_); |
| aura::client::SetActivationDelegate(window_, this); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, RenderWidgetHostView implementation: |
| |
| void RenderWidgetHostViewAura::InitAsChild( |
| gfx::NativeView parent_view) { |
| window_->Init(ui::LAYER_TEXTURED); |
| window_->SetName("RenderWidgetHostViewAura"); |
| } |
| |
| void RenderWidgetHostViewAura::InitAsPopup( |
| RenderWidgetHostView* parent_host_view, |
| const gfx::Rect& bounds_in_display) { |
| popup_parent_host_view_ = |
| static_cast<RenderWidgetHostViewAura*>(parent_host_view); |
| popup_parent_host_view_->popup_child_host_view_ = this; |
| window_->SetType(aura::client::WINDOW_TYPE_MENU); |
| window_->Init(ui::LAYER_TEXTURED); |
| window_->SetName("RenderWidgetHostViewAura"); |
| |
| aura::Window* parent = NULL; |
| aura::RootWindow* root = popup_parent_host_view_->window_->GetRootWindow(); |
| aura::client::ScreenPositionClient* screen_position_client = |
| aura::client::GetScreenPositionClient(root); |
| if (screen_position_client) { |
| gfx::Point origin_in_screen(bounds_in_display.origin()); |
| screen_position_client->ConvertPointToScreen(root, &origin_in_screen); |
| parent = aura::client::GetStackingClient()->GetDefaultParent( |
| window_, gfx::Rect(origin_in_screen, bounds_in_display.size())); |
| } |
| window_->SetParent(parent); |
| SetBounds(bounds_in_display); |
| Show(); |
| } |
| |
| void RenderWidgetHostViewAura::InitAsFullscreen( |
| RenderWidgetHostView* reference_host_view) { |
| is_fullscreen_ = true; |
| window_->SetType(aura::client::WINDOW_TYPE_NORMAL); |
| window_->Init(ui::LAYER_TEXTURED); |
| window_->SetName("RenderWidgetHostViewAura"); |
| window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); |
| aura::Window* parent = NULL; |
| if (reference_host_view) { |
| aura::Window* reference_window = |
| static_cast<RenderWidgetHostViewAura*>(reference_host_view)->window_; |
| if (reference_window) { |
| host_tracker_.reset(new aura::WindowTracker); |
| host_tracker_->Add(reference_window); |
| } |
| gfx::Display display = |
| gfx::Screen::GetDisplayNearestWindow(reference_window); |
| aura::client::StackingClient* stacking_client = |
| aura::client::GetStackingClient(); |
| if (stacking_client) |
| parent = stacking_client->GetDefaultParent(window_, display.bounds()); |
| } |
| window_->SetParent(parent); |
| Show(); |
| Focus(); |
| } |
| |
| RenderWidgetHost* RenderWidgetHostViewAura::GetRenderWidgetHost() const { |
| return host_; |
| } |
| |
| void RenderWidgetHostViewAura::WasShown() { |
| if (!host_->is_hidden()) |
| return; |
| host_->WasShown(); |
| |
| if (!current_surface_ && host_->is_accelerated_compositing_active() && |
| !released_front_lock_.get()) { |
| released_front_lock_ = window_->GetRootWindow()->GetCompositorLock(); |
| } |
| |
| AdjustSurfaceProtection(); |
| |
| #if defined(OS_WIN) |
| LPARAM lparam = reinterpret_cast<LPARAM>(this); |
| EnumChildWindows(ui::GetHiddenWindow(), ShowWindowsCallback, lparam); |
| #endif |
| } |
| |
| void RenderWidgetHostViewAura::WasHidden() { |
| if (host_->is_hidden()) |
| return; |
| host_->WasHidden(); |
| |
| released_front_lock_ = NULL; |
| |
| if (ShouldReleaseFrontSurface() && |
| host_->is_accelerated_compositing_active()) { |
| current_surface_ = 0; |
| UpdateExternalTexture(); |
| } |
| |
| AdjustSurfaceProtection(); |
| |
| #if defined(OS_WIN) |
| HWND parent = window_->GetRootWindow()->GetAcceleratedWidget(); |
| LPARAM lparam = reinterpret_cast<LPARAM>(this); |
| |
| EnumChildWindows(parent, HideWindowsCallback, lparam); |
| #endif |
| } |
| |
| void RenderWidgetHostViewAura::SetSize(const gfx::Size& size) { |
| SetBounds(gfx::Rect(window_->bounds().origin(), size)); |
| } |
| |
| void RenderWidgetHostViewAura::SetBounds(const gfx::Rect& rect) { |
| if (window_->bounds().size() != rect.size() && |
| host_->is_accelerated_compositing_active()) { |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| if (root_window) { |
| resize_locks_.push_back(make_linked_ptr( |
| new ResizeLock(root_window, rect.size()))); |
| } |
| } |
| window_->SetBounds(rect); |
| host_->WasResized(); |
| } |
| |
| gfx::NativeView RenderWidgetHostViewAura::GetNativeView() const { |
| return window_; |
| } |
| |
| gfx::NativeViewId RenderWidgetHostViewAura::GetNativeViewId() const { |
| #if defined(OS_WIN) |
| HWND window = window_->GetRootWindow()->GetAcceleratedWidget(); |
| return reinterpret_cast<gfx::NativeViewId>(window); |
| #else |
| return static_cast<gfx::NativeViewId>(NULL); |
| #endif |
| } |
| |
| gfx::NativeViewAccessible RenderWidgetHostViewAura::GetNativeViewAccessible() { |
| NOTIMPLEMENTED(); |
| return static_cast<gfx::NativeViewAccessible>(NULL); |
| } |
| |
| void RenderWidgetHostViewAura::MovePluginWindows( |
| const gfx::Point& scroll_offset, |
| const std::vector<webkit::npapi::WebPluginGeometry>& plugin_window_moves) { |
| #if defined(OS_WIN) |
| // We need to clip the rectangle to the tab's viewport, otherwise we will draw |
| // over the browser UI. |
| if (!window_->GetRootWindow()) { |
| DCHECK(plugin_window_moves.empty()); |
| return; |
| } |
| HWND parent = window_->GetRootWindow()->GetAcceleratedWidget(); |
| gfx::Rect view_bounds = window_->GetBoundsInRootWindow(); |
| std::vector<webkit::npapi::WebPluginGeometry> moves = plugin_window_moves; |
| |
| gfx::Rect view_port(scroll_offset.x(), scroll_offset.y(), view_bounds.width(), |
| view_bounds.height()); |
| |
| for (size_t i = 0; i < moves.size(); ++i) { |
| gfx::Rect clip = moves[i].clip_rect; |
| clip.Offset(moves[i].window_rect.origin()); |
| clip.Offset(scroll_offset); |
| clip = clip.Intersect(view_port); |
| clip.Offset(-moves[i].window_rect.x(), -moves[i].window_rect.y()); |
| clip.Offset(-scroll_offset.x(), -scroll_offset.y()); |
| moves[i].clip_rect = clip; |
| |
| moves[i].window_rect.Offset(view_bounds.origin()); |
| } |
| MovePluginWindowsHelper(parent, moves); |
| |
| // Make sure each plugin window (or its wrapper if it exists) has a pointer to |
| // |this|. |
| for (size_t i = 0; i < moves.size(); ++i) { |
| HWND window = moves[i].window; |
| if (GetParent(window) != parent) { |
| window = GetParent(window); |
| DCHECK(GetParent(window) == parent); |
| } |
| if (!GetProp(window, kWidgetOwnerProperty)) |
| CHECK(SetProp(window, kWidgetOwnerProperty, this)); |
| } |
| #endif // defined(OS_WIN) |
| } |
| |
| void RenderWidgetHostViewAura::Focus() { |
| // Make sure we have a FocusManager before attempting to Focus(). In some |
| // situations we may not yet be in a valid Window hierarchy (such as reloading |
| // after out of memory discared the tab). |
| if (window_->GetFocusManager()) |
| window_->Focus(); |
| } |
| |
| void RenderWidgetHostViewAura::Blur() { |
| window_->Blur(); |
| } |
| |
| bool RenderWidgetHostViewAura::HasFocus() const { |
| return window_->HasFocus(); |
| } |
| |
| bool RenderWidgetHostViewAura::IsSurfaceAvailableForCopy() const { |
| return current_surface_ != 0; |
| } |
| |
| void RenderWidgetHostViewAura::Show() { |
| window_->Show(); |
| } |
| |
| void RenderWidgetHostViewAura::Hide() { |
| window_->Hide(); |
| } |
| |
| bool RenderWidgetHostViewAura::IsShowing() { |
| return window_->IsVisible(); |
| } |
| |
| gfx::Rect RenderWidgetHostViewAura::GetViewBounds() const { |
| return window_->GetBoundsInScreen(); |
| } |
| |
| void RenderWidgetHostViewAura::UpdateCursor(const WebCursor& cursor) { |
| current_cursor_ = cursor; |
| const gfx::Display display = gfx::Screen::GetDisplayNearestWindow(window_); |
| current_cursor_.SetScaleFactor(display.device_scale_factor()); |
| UpdateCursorIfOverSelf(); |
| } |
| |
| void RenderWidgetHostViewAura::SetIsLoading(bool is_loading) { |
| is_loading_ = is_loading; |
| UpdateCursorIfOverSelf(); |
| } |
| |
| void RenderWidgetHostViewAura::TextInputStateChanged( |
| const ViewHostMsg_TextInputState_Params& params) { |
| if (text_input_type_ != params.type || |
| can_compose_inline_ != params.can_compose_inline) { |
| text_input_type_ = params.type; |
| can_compose_inline_ = params.can_compose_inline; |
| if (GetInputMethod()) |
| GetInputMethod()->OnTextInputTypeChanged(this); |
| } |
| } |
| |
| void RenderWidgetHostViewAura::ImeCancelComposition() { |
| if (GetInputMethod()) |
| GetInputMethod()->CancelComposition(this); |
| has_composition_text_ = false; |
| } |
| |
| void RenderWidgetHostViewAura::ImeCompositionRangeChanged( |
| const ui::Range& range, |
| const std::vector<gfx::Rect>& character_bounds) { |
| composition_character_bounds_ = character_bounds; |
| } |
| |
| void RenderWidgetHostViewAura::DidUpdateBackingStore( |
| const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, |
| const std::vector<gfx::Rect>& copy_rects) { |
| if (accelerated_compositing_state_changed_) |
| UpdateExternalTexture(); |
| |
| // Use the state of the RenderWidgetHost and not the window as the two may |
| // differ. In particular if the window is hidden but the renderer isn't and we |
| // ignore the update and the window is made visible again the layer isn't |
| // marked as dirty and we show the wrong thing. |
| // We do this after UpdateExternalTexture() so that when we become visible |
| // we're not drawing a stale texture. |
| if (host_->is_hidden()) |
| return; |
| |
| gfx::Rect clip_rect; |
| if (paint_canvas_) { |
| SkRect sk_clip_rect; |
| if (paint_canvas_->sk_canvas()->getClipBounds(&sk_clip_rect)) |
| clip_rect = gfx::SkRectToRect(sk_clip_rect); |
| } |
| |
| if (!scroll_rect.IsEmpty()) |
| SchedulePaintIfNotInClip(scroll_rect, clip_rect); |
| |
| for (size_t i = 0; i < copy_rects.size(); ++i) { |
| gfx::Rect rect = copy_rects[i].Subtract(scroll_rect); |
| if (rect.IsEmpty()) |
| continue; |
| |
| SchedulePaintIfNotInClip(rect, clip_rect); |
| |
| #if defined(OS_WIN) |
| // Send the invalid rect in screen coordinates. |
| gfx::Rect screen_rect = GetViewBounds(); |
| gfx::Rect invalid_screen_rect(rect); |
| invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y()); |
| HWND hwnd = window_->GetRootWindow()->GetAcceleratedWidget(); |
| PaintPluginWindowsHelper(hwnd, invalid_screen_rect); |
| #endif // defined(OS_WIN) |
| } |
| } |
| |
| void RenderWidgetHostViewAura::RenderViewGone(base::TerminationStatus status, |
| int error_code) { |
| UpdateCursorIfOverSelf(); |
| Destroy(); |
| } |
| |
| void RenderWidgetHostViewAura::Destroy() { |
| // Beware, this function is not called on all destruction paths. It will |
| // implicitly end up calling ~RenderWidgetHostViewAura though, so all |
| // destruction/cleanup code should happen there, not here. |
| in_shutdown_ = true; |
| delete window_; |
| } |
| |
| void RenderWidgetHostViewAura::SetTooltipText(const string16& tooltip_text) { |
| tooltip_ = tooltip_text; |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| if (aura::client::GetTooltipClient(root_window)) |
| aura::client::GetTooltipClient(root_window)->UpdateTooltip(window_); |
| } |
| |
| void RenderWidgetHostViewAura::SelectionChanged(const string16& text, |
| size_t offset, |
| const ui::Range& range) { |
| RenderWidgetHostViewBase::SelectionChanged(text, offset, range); |
| |
| #if defined(USE_X11) && !defined(OS_CHROMEOS) |
| if (text.empty() || range.is_empty()) |
| return; |
| |
| // Set the BUFFER_SELECTION to the ui::Clipboard. |
| ui::ScopedClipboardWriter clipboard_writer( |
| ui::Clipboard::GetForCurrentThread(), |
| ui::Clipboard::BUFFER_SELECTION); |
| clipboard_writer.WriteText(text); |
| #endif // defined(USE_X11) && !defined(OS_CHROMEOS) |
| } |
| |
| void RenderWidgetHostViewAura::SelectionBoundsChanged( |
| const gfx::Rect& start_rect, |
| WebKit::WebTextDirection start_direction, |
| const gfx::Rect& end_rect, |
| WebKit::WebTextDirection end_direction) { |
| if (selection_start_rect_ == start_rect && selection_end_rect_ == end_rect) |
| return; |
| |
| selection_start_rect_ = start_rect; |
| selection_end_rect_ = end_rect; |
| |
| if (GetInputMethod()) |
| GetInputMethod()->OnCaretBoundsChanged(this); |
| } |
| |
| BackingStore* RenderWidgetHostViewAura::AllocBackingStore( |
| const gfx::Size& size) { |
| return new BackingStoreAura(host_, size); |
| } |
| |
| void RenderWidgetHostViewAura::CopyFromCompositingSurface( |
| const gfx::Rect& src_subrect, |
| const gfx::Size& dst_size, |
| const base::Callback<void(bool)>& callback, |
| skia::PlatformCanvas* output) { |
| base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false)); |
| |
| std::map<uint64, scoped_refptr<ui::Texture> >::iterator it = |
| image_transport_clients_.find(current_surface_); |
| if (it == image_transport_clients_.end()) |
| return; |
| |
| ui::Texture* container = it->second; |
| DCHECK(container); |
| |
| gfx::Size dst_size_in_pixel = ConvertSizeToPixel(this, dst_size); |
| if (!output->initialize( |
| dst_size_in_pixel.width(), dst_size_in_pixel.height(), true)) |
| return; |
| |
| ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
| GLHelper* gl_helper = factory->GetGLHelper(); |
| if (!gl_helper) |
| return; |
| |
| unsigned char* addr = static_cast<unsigned char*>( |
| output->getTopDevice()->accessBitmap(true).getPixels()); |
| scoped_callback_runner.Release(); |
| // Wrap the callback with an internal handler so that we can inject our |
| // own completion handlers (where we can call AdjustSurfaceProtection). |
| base::Callback<void(bool)> wrapper_callback = base::Bind( |
| &RenderWidgetHostViewAura::CopyFromCompositingSurfaceFinished, |
| AsWeakPtr(), |
| callback); |
| pending_thumbnail_tasks_.push_back(callback); |
| |
| // Convert |src_subrect| from the views coordinate (upper-left origin) into |
| // the OpenGL coordinate (lower-left origin). |
| gfx::Rect src_subrect_in_gl = src_subrect; |
| src_subrect_in_gl.set_y(GetViewBounds().height() - src_subrect.bottom()); |
| |
| gfx::Rect src_subrect_in_pixel = ConvertRectToPixel(this, src_subrect_in_gl); |
| gl_helper->CopyTextureTo(container->texture_id(), |
| container->size(), |
| src_subrect_in_pixel, |
| dst_size_in_pixel, |
| addr, |
| wrapper_callback); |
| } |
| |
| void RenderWidgetHostViewAura::OnAcceleratedCompositingStateChange() { |
| // Delay processing the state change until we either get a software frame if |
| // switching to software mode or receive a buffers swapped notification |
| // if switching to accelerated mode. |
| // Sometimes (e.g. on a page load) the renderer will spuriously disable then |
| // re-enable accelerated compositing, causing us to flash. |
| // TODO(piman): factor the enable/disable accelerated compositing message into |
| // the UpdateRect/AcceleratedSurfaceBuffersSwapped messages so that we have |
| // fewer inconsistent temporary states. |
| accelerated_compositing_state_changed_ = true; |
| } |
| |
| void RenderWidgetHostViewAura::UpdateExternalTexture() { |
| // Delay processing accelerated compositing state change till here where we |
| // act upon the state change. (Clear the external texture if switching to |
| // software mode or set the external texture if going to accelerated mode). |
| if (accelerated_compositing_state_changed_) { |
| // Don't scale the contents in accelerated mode because the renderer takes |
| // care of it. |
| window_->layer()->set_scale_content( |
| !host_->is_accelerated_compositing_active()); |
| |
| accelerated_compositing_state_changed_ = false; |
| } |
| |
| if (current_surface_ != 0 && host_->is_accelerated_compositing_active()) { |
| ui::Texture* container = image_transport_clients_[current_surface_]; |
| window_->SetExternalTexture(container); |
| current_surface_in_use_by_compositor_ = true; |
| |
| if (!container) { |
| resize_locks_.clear(); |
| } else { |
| typedef std::vector<linked_ptr<ResizeLock> > ResizeLockList; |
| ResizeLockList::iterator it = resize_locks_.begin(); |
| while (it != resize_locks_.end()) { |
| gfx::Size container_size = ConvertSizeToDIP(this, |
| container->size()); |
| if ((*it)->expected_size() == container_size) |
| break; |
| ++it; |
| } |
| if (it != resize_locks_.end()) { |
| ++it; |
| ui::Compositor* compositor = GetCompositor(); |
| if (compositor) { |
| // Delay the release of the lock until we've kicked a frame with the |
| // new texture, to avoid resizing the UI before we have a chance to |
| // draw a "good" frame. |
| locks_pending_draw_.insert( |
| locks_pending_draw_.begin(), resize_locks_.begin(), it); |
| // However since we got the size we were looking for, unlock the |
| // compositor. |
| for (ResizeLockList::iterator it2 = resize_locks_.begin(); |
| it2 !=it; ++it2) { |
| it2->get()->UnlockCompositor(); |
| } |
| if (!compositor->HasObserver(this)) |
| compositor->AddObserver(this); |
| } |
| resize_locks_.erase(resize_locks_.begin(), it); |
| } |
| } |
| } else { |
| window_->SetExternalTexture(NULL); |
| if (ShouldReleaseFrontSurface() && |
| host_->is_accelerated_compositing_active()) { |
| // The current surface may have pipelined gl commands, so always wait for |
| // the next composite to start. If the current surface is still null, |
| // then we really know its no longer in use. |
| ui::Compositor* compositor = GetCompositor(); |
| if (compositor) { |
| on_compositing_will_start_callbacks_.push_back( |
| base::Bind(&RenderWidgetHostViewAura:: |
| SetSurfaceNotInUseByCompositor, |
| AsWeakPtr())); |
| if (!compositor->HasObserver(this)) |
| compositor->AddObserver(this); |
| } |
| } |
| resize_locks_.clear(); |
| } |
| } |
| |
| void RenderWidgetHostViewAura::AcceleratedSurfaceBuffersSwapped( |
| const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params_in_pixel, |
| int gpu_host_id) { |
| surface_route_id_ = params_in_pixel.route_id; |
| // If protection state changed, then this swap is stale. We must still ACK but |
| // do not update current_surface_ since it may have been discarded. |
| if (params_in_pixel.protection_state_id && |
| params_in_pixel.protection_state_id != protection_state_id_) { |
| DCHECK(!current_surface_); |
| if (!params_in_pixel.skip_ack) |
| InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, NULL); |
| return; |
| } |
| current_surface_ = params_in_pixel.surface_handle; |
| // If we don't require an ACK that means the content is not a fresh updated |
| // new frame, rather we are just resetting our handle to some old content that |
| // we still hadn't discarded. Although we could display immediately, by not |
| // resetting the compositor lock here, we give us some time to get a fresh |
| // frame which means fewer content flashes. |
| if (!params_in_pixel.skip_ack) |
| released_front_lock_ = NULL; |
| |
| UpdateExternalTexture(); |
| |
| ui::Compositor* compositor = GetCompositor(); |
| if (!compositor) { |
| // We have no compositor, so we have no way to display the surface. |
| // Must still send the ACK. |
| if (!params_in_pixel.skip_ack) |
| InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, NULL); |
| } else { |
| DCHECK(image_transport_clients_.find(params_in_pixel.surface_handle) != |
| image_transport_clients_.end()); |
| gfx::Size surface_size_in_pixel = |
| image_transport_clients_[params_in_pixel.surface_handle]->size(); |
| gfx::Size surface_size = ConvertSizeToDIP(this, |
| surface_size_in_pixel); |
| window_->SchedulePaintInRect(gfx::Rect(surface_size)); |
| |
| if (!params_in_pixel.skip_ack) { |
| if (!resize_locks_.empty()) { |
| // If we are waiting for the resize, fast-track the ACK. |
| if (compositor->IsThreaded()) { |
| // We need the compositor thread to pick up the active buffer before |
| // ACKing. |
| on_compositing_did_commit_callbacks_.push_back( |
| base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, |
| params_in_pixel.route_id, |
| gpu_host_id)); |
| if (!compositor->HasObserver(this)) |
| compositor->AddObserver(this); |
| } else { |
| // The compositor will pickup the active buffer during a draw, so we |
| // can ACK immediately. |
| InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, |
| compositor); |
| } |
| } else { |
| // Add sending an ACK to the list of things to do OnCompositingWillStart |
| on_compositing_will_start_callbacks_.push_back( |
| base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, |
| params_in_pixel.route_id, |
| gpu_host_id)); |
| if (!compositor->HasObserver(this)) |
| compositor->AddObserver(this); |
| } |
| } |
| } |
| } |
| |
| void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer( |
| const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params_in_pixel, |
| int gpu_host_id) { |
| surface_route_id_ = params_in_pixel.route_id; |
| // If visible state changed, then this PSB is stale. We must still ACK but |
| // do not update current_surface_. |
| if (params_in_pixel.protection_state_id && |
| params_in_pixel.protection_state_id != protection_state_id_) { |
| DCHECK(!current_surface_); |
| InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, NULL); |
| return; |
| } |
| current_surface_ = params_in_pixel.surface_handle; |
| released_front_lock_ = NULL; |
| DCHECK(current_surface_); |
| UpdateExternalTexture(); |
| |
| ui::Compositor* compositor = GetCompositor(); |
| if (!compositor) { |
| // We have no compositor, so we have no way to display the surface |
| // Must still send the ACK |
| InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, NULL); |
| } else { |
| DCHECK(image_transport_clients_.find(params_in_pixel.surface_handle) != |
| image_transport_clients_.end()); |
| gfx::Size surface_size_in_pixel = |
| image_transport_clients_[params_in_pixel.surface_handle]->size(); |
| |
| // Co-ordinates come in OpenGL co-ordinate space. |
| // We need to convert to layer space. |
| gfx::Rect rect_to_paint = ConvertRectToDIP(this, gfx::Rect( |
| params_in_pixel.x, |
| surface_size_in_pixel.height() - params_in_pixel.y - |
| params_in_pixel.height, |
| params_in_pixel.width, |
| params_in_pixel.height)); |
| |
| // Damage may not have been DIP aligned, so inflate damage to compensate |
| // for any round-off error. |
| rect_to_paint.Inset(-1, -1); |
| rect_to_paint = rect_to_paint.Intersect(window_->bounds()); |
| |
| window_->SchedulePaintInRect(rect_to_paint); |
| |
| if (!resize_locks_.empty()) { |
| // If we are waiting for the resize, fast-track the ACK. |
| if (compositor->IsThreaded()) { |
| // We need the compositor thread to pick up the active buffer before |
| // ACKing. |
| on_compositing_did_commit_callbacks_.push_back( |
| base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, |
| params_in_pixel.route_id, |
| gpu_host_id)); |
| if (!compositor->HasObserver(this)) |
| compositor->AddObserver(this); |
| } else { |
| // The compositor will pickup the active buffer during a draw, so we |
| // can ACK immediately. |
| InsertSyncPointAndACK(params_in_pixel.route_id, gpu_host_id, |
| compositor); |
| } |
| } else { |
| // Add sending an ACK to the list of things to do OnCompositingWillStart |
| on_compositing_will_start_callbacks_.push_back( |
| base::Bind(&RenderWidgetHostViewAura::InsertSyncPointAndACK, |
| params_in_pixel.route_id, |
| gpu_host_id)); |
| if (!compositor->HasObserver(this)) |
| compositor->AddObserver(this); |
| } |
| } |
| } |
| |
| void RenderWidgetHostViewAura::AcceleratedSurfaceSuspend() { |
| } |
| |
| 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; |
| } |
| |
| // TODO(backer): Drop the |shm_handle| once I remove some unused service side |
| // code. |
| void RenderWidgetHostViewAura::AcceleratedSurfaceNew( |
| int32 width_in_pixel, |
| int32 height_in_pixel, |
| uint64 surface_handle) { |
| ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
| scoped_refptr<ui::Texture> surface(factory->CreateTransportClient( |
| gfx::Size(width_in_pixel, height_in_pixel), device_scale_factor_, |
| surface_handle)); |
| if (!surface) { |
| LOG(ERROR) << "Failed to create ImageTransport texture"; |
| return; |
| } |
| |
| image_transport_clients_[surface_handle] = surface; |
| } |
| |
| void RenderWidgetHostViewAura::AcceleratedSurfaceRelease( |
| uint64 surface_handle) { |
| DCHECK(image_transport_clients_.find(surface_handle) != |
| image_transport_clients_.end()); |
| if (current_surface_ == surface_handle) { |
| current_surface_ = 0; |
| UpdateExternalTexture(); |
| } |
| image_transport_clients_.erase(surface_handle); |
| } |
| |
| void RenderWidgetHostViewAura::SetSurfaceNotInUseByCompositor(ui::Compositor*) { |
| if (current_surface_ || !host_->is_hidden()) |
| return; |
| current_surface_in_use_by_compositor_ = false; |
| AdjustSurfaceProtection(); |
| } |
| |
| void RenderWidgetHostViewAura::AdjustSurfaceProtection() { |
| // If the current surface is non null, it is protected. |
| // If we are visible, it is protected. |
| // Otherwise, change to not proctected once done thumbnailing and compositing. |
| bool surface_is_protected = |
| current_surface_ || |
| !host_->is_hidden() || |
| (current_surface_is_protected_ && |
| (!pending_thumbnail_tasks_.empty() || |
| current_surface_in_use_by_compositor_)); |
| if (current_surface_is_protected_ == surface_is_protected) |
| return; |
| current_surface_is_protected_ = surface_is_protected; |
| ++protection_state_id_; |
| |
| if (!surface_route_id_ || !shared_surface_handle_.parent_gpu_process_id) |
| return; |
| |
| RenderWidgetHostImpl::SendFrontSurfaceIsProtected( |
| surface_is_protected, |
| protection_state_id_, |
| surface_route_id_, |
| shared_surface_handle_.parent_gpu_process_id); |
| } |
| |
| void RenderWidgetHostViewAura::CopyFromCompositingSurfaceFinished( |
| base::Callback<void(bool)> callback, bool result) { |
| for (size_t i = 0; i != pending_thumbnail_tasks_.size(); ++i) { |
| if (pending_thumbnail_tasks_[i].Equals(callback)) { |
| pending_thumbnail_tasks_.erase(pending_thumbnail_tasks_.begin()+i); |
| break; |
| } |
| } |
| AdjustSurfaceProtection(); |
| callback.Run(result); |
| } |
| |
| void RenderWidgetHostViewAura::SetBackground(const SkBitmap& background) { |
| RenderWidgetHostViewBase::SetBackground(background); |
| host_->SetBackground(background); |
| window_->layer()->SetFillsBoundsOpaquely(background.isOpaque()); |
| } |
| |
| void RenderWidgetHostViewAura::GetScreenInfo(WebScreenInfo* results) { |
| GetScreenInfoForWindow(results, window_); |
| } |
| |
| gfx::Rect RenderWidgetHostViewAura::GetBoundsInRootWindow() { |
| return window_->GetToplevelWindow()->GetBoundsInRootWindow(); |
| } |
| |
| void RenderWidgetHostViewAura::ProcessTouchAck( |
| WebKit::WebInputEvent::Type type, bool processed) { |
| // The ACKs for the touch-events arrive in the same sequence as they were |
| // dispatched. |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| if (root_window) |
| root_window->AdvanceQueuedTouchEvent(window_, processed); |
| } |
| |
| void RenderWidgetHostViewAura::SetHasHorizontalScrollbar( |
| bool has_horizontal_scrollbar) { |
| // Not needed. Mac-only. |
| } |
| |
| void RenderWidgetHostViewAura::SetScrollOffsetPinning( |
| bool is_pinned_to_left, bool is_pinned_to_right) { |
| // Not needed. Mac-only. |
| } |
| |
| gfx::GLSurfaceHandle RenderWidgetHostViewAura::GetCompositingSurface() { |
| if (shared_surface_handle_.is_null()) { |
| ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
| shared_surface_handle_ = factory->CreateSharedSurfaceHandle(); |
| factory->AddObserver(this); |
| } |
| return shared_surface_handle_; |
| } |
| |
| bool RenderWidgetHostViewAura::LockMouse() { |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| if (!root_window) |
| return false; |
| |
| if (mouse_locked_) |
| return true; |
| |
| mouse_locked_ = true; |
| window_->SetCapture(); |
| aura::client::CursorClient* cursor_client = |
| aura::client::GetCursorClient(root_window); |
| if (cursor_client) |
| cursor_client->ShowCursor(false); |
| synthetic_move_sent_ = true; |
| window_->MoveCursorTo(gfx::Rect(window_->bounds().size()).CenterPoint()); |
| if (aura::client::GetTooltipClient(root_window)) |
| aura::client::GetTooltipClient(root_window)->SetTooltipsEnabled(false); |
| return true; |
| } |
| |
| void RenderWidgetHostViewAura::UnlockMouse() { |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| if (!mouse_locked_ || !root_window) |
| return; |
| |
| mouse_locked_ = false; |
| |
| window_->ReleaseCapture(); |
| window_->MoveCursorTo(unlocked_mouse_position_); |
| aura::client::CursorClient* cursor_client = |
| aura::client::GetCursorClient(root_window); |
| if (cursor_client) |
| cursor_client->ShowCursor(true); |
| if (aura::client::GetTooltipClient(root_window)) |
| aura::client::GetTooltipClient(root_window)->SetTooltipsEnabled(true); |
| |
| host_->LostMouseLock(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, ui::TextInputClient implementation: |
| void RenderWidgetHostViewAura::SetCompositionText( |
| const ui::CompositionText& composition) { |
| if (!host_) |
| return; |
| |
| // ui::CompositionUnderline should be identical to |
| // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely. |
| COMPILE_ASSERT(sizeof(ui::CompositionUnderline) == |
| sizeof(WebKit::WebCompositionUnderline), |
| ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff); |
| |
| // TODO(suzhe): convert both renderer_host and renderer to use |
| // ui::CompositionText. |
| const std::vector<WebKit::WebCompositionUnderline>& underlines = |
| reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>( |
| composition.underlines); |
| |
| // 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 |
| host_->ImeSetComposition(composition.text, underlines, |
| composition.selection.end(), |
| composition.selection.end()); |
| |
| has_composition_text_ = !composition.text.empty(); |
| } |
| |
| void RenderWidgetHostViewAura::ConfirmCompositionText() { |
| if (host_ && has_composition_text_) |
| host_->ImeConfirmComposition(); |
| has_composition_text_ = false; |
| } |
| |
| void RenderWidgetHostViewAura::ClearCompositionText() { |
| if (host_ && has_composition_text_) |
| host_->ImeCancelComposition(); |
| has_composition_text_ = false; |
| } |
| |
| void RenderWidgetHostViewAura::InsertText(const string16& text) { |
| DCHECK(text_input_type_ != ui::TEXT_INPUT_TYPE_NONE); |
| if (host_) |
| host_->ImeConfirmComposition(text); |
| has_composition_text_ = false; |
| } |
| |
| void RenderWidgetHostViewAura::InsertChar(char16 ch, int flags) { |
| if (popup_child_host_view_ && popup_child_host_view_->NeedsInputGrab()) { |
| popup_child_host_view_->InsertChar(ch, flags); |
| return; |
| } |
| |
| if (host_) { |
| // Send a WebKit::WebInputEvent::Char event to |host_|. |
| NativeWebKeyboardEvent webkit_event(ui::ET_KEY_PRESSED, |
| true /* is_char */, |
| ch, |
| flags, |
| base::Time::Now().ToDoubleT()); |
| host_->ForwardKeyboardEvent(webkit_event); |
| } |
| } |
| |
| ui::TextInputType RenderWidgetHostViewAura::GetTextInputType() const { |
| return text_input_type_; |
| } |
| |
| bool RenderWidgetHostViewAura::CanComposeInline() const { |
| return can_compose_inline_; |
| } |
| |
| gfx::Rect RenderWidgetHostViewAura::ConvertRectToScreen(const gfx::Rect& rect) { |
| gfx::Point origin = rect.origin(); |
| gfx::Point end = gfx::Point(rect.right(), rect.bottom()); |
| |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| aura::client::ScreenPositionClient* screen_position_client = |
| aura::client::GetScreenPositionClient(root_window); |
| 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::GetCaretBounds() { |
| const gfx::Rect rect = selection_start_rect_.Union(selection_end_rect_); |
| return ConvertRectToScreen(rect); |
| } |
| |
| bool RenderWidgetHostViewAura::GetCompositionCharacterBounds(uint32 index, |
| gfx::Rect* rect) { |
| DCHECK(rect); |
| if (index >= composition_character_bounds_.size()) |
| return false; |
| *rect = ConvertRectToScreen(composition_character_bounds_[index]); |
| return true; |
| } |
| |
| bool RenderWidgetHostViewAura::HasCompositionText() { |
| return has_composition_text_; |
| } |
| |
| bool RenderWidgetHostViewAura::GetTextRange(ui::Range* range) { |
| range->set_start(selection_text_offset_); |
| range->set_end(selection_text_offset_ + selection_text_.length()); |
| return true; |
| } |
| |
| bool RenderWidgetHostViewAura::GetCompositionTextRange(ui::Range* range) { |
| // TODO(suzhe): implement this method when fixing http://crbug.com/55130. |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| bool RenderWidgetHostViewAura::GetSelectionRange(ui::Range* range) { |
| range->set_start(selection_range_.start()); |
| range->set_end(selection_range_.end()); |
| return true; |
| } |
| |
| bool RenderWidgetHostViewAura::SetSelectionRange(const ui::Range& range) { |
| // TODO(suzhe): implement this method when fixing http://crbug.com/55130. |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| bool RenderWidgetHostViewAura::DeleteRange(const ui::Range& range) { |
| // TODO(suzhe): implement this method when fixing http://crbug.com/55130. |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| bool RenderWidgetHostViewAura::GetTextFromRange( |
| const ui::Range& range, |
| string16* text) { |
| ui::Range selection_text_range(selection_text_offset_, |
| selection_text_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_text_offset_, |
| range.length()); |
| } |
| return true; |
| } |
| |
| void RenderWidgetHostViewAura::OnInputMethodChanged() { |
| if (!host_) |
| return; |
| |
| if (GetInputMethod()) |
| host_->SetInputMethodActive(GetInputMethod()->IsActive()); |
| |
| // TODO(suzhe): implement the newly added “locale” property of HTML DOM |
| // TextEvent. |
| } |
| |
| bool RenderWidgetHostViewAura::ChangeTextDirectionAndLayoutAlignment( |
| base::i18n::TextDirection direction) { |
| if (!host_) |
| return false; |
| host_->UpdateTextDirection( |
| direction == base::i18n::RIGHT_TO_LEFT ? |
| WebKit::WebTextDirectionRightToLeft : |
| WebKit::WebTextDirectionLeftToRight); |
| host_->NotifyTextDirection(); |
| return true; |
| } |
| |
| void RenderWidgetHostViewAura::ExtendSelectionAndDelete( |
| size_t before, size_t after) { |
| // TODO(horo): implement this method if it is required. |
| // http://crbug.com/149155 |
| NOTIMPLEMENTED(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, aura::WindowDelegate implementation: |
| |
| gfx::Size RenderWidgetHostViewAura::GetMinimumSize() const { |
| return gfx::Size(); |
| } |
| |
| void RenderWidgetHostViewAura::OnBoundsChanged(const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds) { |
| // We don't care about this one, we are always sized via SetSize() or |
| // SetBounds(). |
| } |
| |
| void RenderWidgetHostViewAura::OnFocus(aura::Window* old_focused_window) { |
| // 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); |
| host_->SetInputMethodActive(input_method->IsActive()); |
| } else { |
| host_->SetInputMethodActive(false); |
| } |
| } |
| |
| void RenderWidgetHostViewAura::OnBlur() { |
| host_->SetActive(false); |
| host_->Blur(); |
| |
| DetachFromInputMethod(); |
| host_->SetInputMethodActive(false); |
| |
| // If we lose the focus while fullscreen, close the window; Pepper Flash won't |
| // do it for us (unlike NPAPI Flash). |
| if (is_fullscreen_ && !in_shutdown_) { |
| in_shutdown_ = true; |
| host_->Shutdown(); |
| } |
| } |
| |
| 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_ == WebKit::WebPopupTypeNone; |
| } |
| |
| void RenderWidgetHostViewAura::OnCaptureLost() { |
| host_->LostCapture(); |
| } |
| |
| void RenderWidgetHostViewAura::OnPaint(gfx::Canvas* canvas) { |
| paint_canvas_ = canvas; |
| BackingStore* backing_store = host_->GetBackingStore(true); |
| paint_canvas_ = NULL; |
| if (backing_store) { |
| static_cast<BackingStoreAura*>(backing_store)->SkiaShowRect(gfx::Point(), |
| canvas); |
| } else if (aura::Env::GetInstance()->render_white_bg()) { |
| canvas->DrawColor(SK_ColorWHITE); |
| } |
| } |
| |
| void RenderWidgetHostViewAura::OnDeviceScaleFactorChanged( |
| float device_scale_factor) { |
| if (!host_) |
| return; |
| |
| device_scale_factor_ = device_scale_factor; |
| BackingStoreAura* backing_store = static_cast<BackingStoreAura*>( |
| host_->GetBackingStore(false)); |
| if (backing_store) // NULL in hardware path. |
| backing_store->ScaleFactorChanged(device_scale_factor); |
| |
| host_->SetDeviceScaleFactor(device_scale_factor); |
| current_cursor_.SetScaleFactor(device_scale_factor); |
| } |
| |
| void RenderWidgetHostViewAura::OnWindowDestroying() { |
| #if defined(OS_WIN) |
| HWND parent = NULL; |
| // If the tab was hidden and it's closed, host_->is_hidden would have been |
| // reset to false in RenderWidgetHostImpl::RendererExited. |
| if (!window_->GetRootWindow() || host_->is_hidden()) { |
| parent = ui::GetHiddenWindow(); |
| } else { |
| parent = window_->GetRootWindow()->GetAcceleratedWidget(); |
| } |
| LPARAM lparam = reinterpret_cast<LPARAM>(this); |
| EnumChildWindows(parent, WindowDestroyingCallback, lparam); |
| #endif |
| } |
| |
| void RenderWidgetHostViewAura::OnWindowDestroyed() { |
| host_->ViewDestroyed(); |
| delete this; |
| } |
| |
| void RenderWidgetHostViewAura::OnWindowTargetVisibilityChanged(bool visible) { |
| } |
| |
| bool RenderWidgetHostViewAura::HasHitTestMask() const { |
| return false; |
| } |
| |
| void RenderWidgetHostViewAura::GetHitTestMask(gfx::Path* mask) const { |
| } |
| |
| scoped_refptr<ui::Texture> RenderWidgetHostViewAura::CopyTexture() { |
| if (!host_->is_accelerated_compositing_active()) |
| return scoped_refptr<ui::Texture>(); |
| |
| ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
| GLHelper* gl_helper = factory->GetGLHelper(); |
| if (!gl_helper) |
| return scoped_refptr<ui::Texture>(); |
| |
| std::map<uint64, scoped_refptr<ui::Texture> >::iterator it = |
| image_transport_clients_.find(current_surface_); |
| if (it == image_transport_clients_.end()) |
| return scoped_refptr<ui::Texture>(); |
| |
| ui::Texture* container = it->second; |
| DCHECK(container); |
| WebKit::WebGLId texture_id = |
| gl_helper->CopyTexture(container->texture_id(), container->size()); |
| if (!texture_id) |
| return scoped_refptr<ui::Texture>(); |
| |
| return scoped_refptr<ui::Texture>( |
| factory->CreateOwnedTexture( |
| container->size(), device_scale_factor_, texture_id)); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, ui::EventHandler implementation: |
| |
| ui::EventResult RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) { |
| TRACE_EVENT0("browser", "RenderWidgetHostViewAura::OnKeyEvent"); |
| if (popup_child_host_view_ && popup_child_host_view_->NeedsInputGrab() && |
| popup_child_host_view_->OnKeyEvent(event)) |
| return ui::ER_HANDLED; |
| |
| // We need to handle the Escape key for Pepper Flash. |
| if (is_fullscreen_ && event->key_code() == ui::VKEY_ESCAPE) { |
| // Focus the window we were created from. |
| if (host_tracker_.get() && !host_tracker_->windows().empty()) { |
| aura::Window* host = *(host_tracker_->windows().begin()); |
| if (host->GetFocusManager()) |
| host->Focus(); |
| } |
| if (!in_shutdown_) { |
| in_shutdown_ = true; |
| host_->Shutdown(); |
| } |
| } else { |
| // We don't have to communicate with an input method here. |
| if (!event->HasNativeEvent()) { |
| // Send a fabricated event, which is usually a VKEY_PROCESSKEY IME event. |
| NativeWebKeyboardEvent webkit_event(event->type(), |
| false /* is_char */, |
| event->GetCharacter(), |
| event->flags(), |
| base::Time::Now().ToDoubleT()); |
| host_->ForwardKeyboardEvent(webkit_event); |
| } else { |
| NativeWebKeyboardEvent webkit_event(event); |
| host_->ForwardKeyboardEvent(webkit_event); |
| } |
| } |
| return ui::ER_HANDLED; |
| } |
| |
| ui::EventResult RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) { |
| TRACE_EVENT0("browser", "RenderWidgetHostViewAura::OnMouseEvent"); |
| if (mouse_locked_) { |
| // Hide the cursor if someone else has shown it. |
| aura::client::CursorClient* cursor_client = |
| aura::client::GetCursorClient(window_->GetRootWindow()); |
| if (cursor_client && cursor_client->IsCursorVisible()) |
| cursor_client->ShowCursor(false); |
| |
| WebKit::WebMouseEvent mouse_event = MakeWebMouseEvent(event); |
| gfx::Point center(gfx::Rect(window_->bounds().size()).CenterPoint()); |
| |
| bool is_move_to_center_event = (event->type() == ui::ET_MOUSE_MOVED || |
| event->type() == ui::ET_MOUSE_DRAGGED) && |
| mouse_event.x == center.x() && mouse_event.y == center.y(); |
| |
| ModifyEventMovementAndCoords(&mouse_event); |
| |
| bool should_not_forward = is_move_to_center_event && synthetic_move_sent_; |
| if (should_not_forward) { |
| synthetic_move_sent_ = false; |
| } else { |
| // Check if the mouse has reached the border and needs to be centered. |
| if (ShouldMoveToCenter()) { |
| synthetic_move_sent_ = true; |
| window_->MoveCursorTo(center); |
| } |
| |
| // Forward event to renderer. |
| if (CanRendererHandleEvent(event)) |
| host_->ForwardMouseEvent(mouse_event); |
| } |
| |
| return ui::ER_UNHANDLED; |
| } |
| |
| if (event->type() == ui::ET_MOUSEWHEEL) { |
| WebKit::WebMouseWheelEvent mouse_wheel_event = |
| MakeWebMouseWheelEvent(static_cast<ui::MouseWheelEvent*>(event)); |
| if (mouse_wheel_event.deltaX != 0 || mouse_wheel_event.deltaY != 0) |
| host_->ForwardWheelEvent(mouse_wheel_event); |
| } else if (event->type() == ui::ET_SCROLL) { |
| WebKit::WebGestureEvent gesture_event = |
| MakeWebGestureEventFlingCancel(); |
| host_->ForwardGestureEvent(gesture_event); |
| WebKit::WebMouseWheelEvent mouse_wheel_event = |
| MakeWebMouseWheelEvent(static_cast<ui::ScrollEvent*>(event)); |
| host_->ForwardWheelEvent(mouse_wheel_event); |
| RecordAction(UserMetricsAction("TrackpadScroll")); |
| } else if (event->type() == ui::ET_SCROLL_FLING_START || |
| event->type() == ui::ET_SCROLL_FLING_CANCEL) { |
| WebKit::WebGestureEvent gesture_event = |
| MakeWebGestureEvent(static_cast<ui::ScrollEvent*>(event)); |
| host_->ForwardGestureEvent(gesture_event); |
| if (event->type() == ui::ET_SCROLL_FLING_START) |
| RecordAction(UserMetricsAction("TrackpadScrollFling")); |
| } else if (CanRendererHandleEvent(event)) { |
| WebKit::WebMouseEvent mouse_event = MakeWebMouseEvent(event); |
| ModifyEventMovementAndCoords(&mouse_event); |
| host_->ForwardMouseEvent(mouse_event); |
| } |
| |
| switch (event->type()) { |
| case ui::ET_MOUSE_PRESSED: |
| window_->SetCapture(); |
| // Confirm existing composition text on mouse click events, to make sure |
| // the input caret won't be moved with an ongoing composition text. |
| FinishImeCompositionSession(); |
| break; |
| case ui::ET_MOUSE_RELEASED: |
| window_->ReleaseCapture(); |
| break; |
| default: |
| break; |
| } |
| |
| // Needed to propagate mouse event to native_tab_contents_view_aura. |
| // TODO(pkotwicz): Find a better way of doing this. |
| if (window_->parent()->delegate()) |
| window_->parent()->delegate()->OnMouseEvent(event); |
| |
| // Return true so that we receive released/drag events. |
| return ui::ER_HANDLED; |
| } |
| |
| ui::TouchStatus RenderWidgetHostViewAura::OnTouchEvent( |
| ui::TouchEvent* event) { |
| TRACE_EVENT0("browser", "RenderWidgetHostViewAura::OnTouchEvent"); |
| // Update the touch event first. |
| WebKit::WebTouchPoint* point = UpdateWebTouchEvent(event, |
| &touch_event_); |
| |
| // Forward the touch event only if a touch point was updated, and there's a |
| // touch-event handler in the page. |
| if (point && host_->has_touch_handler()) { |
| host_->ForwardTouchEvent(touch_event_); |
| UpdateWebTouchEventAfterDispatch(&touch_event_, point); |
| return DecideTouchStatus(touch_event_, point); |
| } |
| |
| return ui::TOUCH_STATUS_UNKNOWN; |
| } |
| |
| ui::EventResult RenderWidgetHostViewAura::OnGestureEvent( |
| ui::GestureEvent* event) { |
| TRACE_EVENT0("browser", "RenderWidgetHostViewAura::OnGestureEvent"); |
| // Pinch gestures are currently disabled by default. See crbug.com/128477. |
| if ((event->type() == ui::ET_GESTURE_PINCH_BEGIN || |
| event->type() == ui::ET_GESTURE_PINCH_UPDATE || |
| event->type() == ui::ET_GESTURE_PINCH_END) && !ShouldSendPinchGesture()) { |
| return ui::ER_CONSUMED; |
| } |
| |
| RenderViewHostDelegate* delegate = NULL; |
| if (popup_type_ == WebKit::WebPopupTypeNone && !is_fullscreen_) |
| delegate = RenderViewHost::From(host_)->GetDelegate(); |
| if (delegate && event->type() == ui::ET_GESTURE_BEGIN && |
| event->details().touch_points() == 1) { |
| delegate->HandleGestureBegin(); |
| } |
| |
| WebKit::WebGestureEvent gesture = MakeWebGestureEvent(event); |
| if (event->type() == ui::ET_GESTURE_TAP_DOWN) { |
| // Webkit does not stop a fling-scroll on tap-down. So explicitly send an |
| // event to stop any in-progress flings. |
| WebKit::WebGestureEvent fling_cancel = gesture; |
| fling_cancel.type = WebKit::WebInputEvent::GestureFlingCancel; |
| host_->ForwardGestureEvent(fling_cancel); |
| } |
| |
| if (gesture.type != WebKit::WebInputEvent::Undefined) { |
| host_->ForwardGestureEvent(gesture); |
| |
| if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || |
| event->type() == ui::ET_GESTURE_SCROLL_UPDATE || |
| event->type() == ui::ET_GESTURE_SCROLL_END) { |
| RecordAction(UserMetricsAction("TouchscreenScroll")); |
| } else if (event->type() == ui::ET_SCROLL_FLING_START) { |
| RecordAction(UserMetricsAction("TouchscreenScrollFling")); |
| } |
| } |
| |
| if (delegate && event->type() == ui::ET_GESTURE_END && |
| event->details().touch_points() == 1) { |
| delegate->HandleGestureEnd(); |
| } |
| |
| // If a gesture is not processed by the webpage, then WebKit processes it |
| // (e.g. generates synthetic mouse events). So CONSUMED should be returned |
| // from here to avoid any duplicate synthetic mouse-events being generated |
| // from aura. |
| return ui::ER_CONSUMED; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, aura::client::ActivationDelegate implementation: |
| |
| bool RenderWidgetHostViewAura::ShouldActivate(const ui::Event* event) { |
| bool activate = false; |
| if (event) { |
| if (event->type() == ui::ET_MOUSE_PRESSED) { |
| activate = true; |
| } else if (event->type() == ui::ET_GESTURE_BEGIN) { |
| activate = static_cast<const ui::GestureEvent*>(event)-> |
| details().touch_points() == 1; |
| } |
| } |
| if (activate) |
| host_->OnPointerEventActivate(); |
| return is_fullscreen_; |
| } |
| |
| void RenderWidgetHostViewAura::OnActivated() { |
| } |
| |
| void RenderWidgetHostViewAura::OnLostActive() { |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, ui::CompositorObserver implementation: |
| |
| void RenderWidgetHostViewAura::OnCompositingDidCommit( |
| ui::Compositor* compositor) { |
| RunCompositingDidCommitCallbacks(compositor); |
| } |
| |
| void RenderWidgetHostViewAura::OnCompositingWillStart( |
| ui::Compositor* compositor) { |
| RunCompositingWillStartCallbacks(compositor); |
| } |
| |
| void RenderWidgetHostViewAura::OnCompositingStarted( |
| ui::Compositor* compositor) { |
| locks_pending_draw_.clear(); |
| } |
| |
| void RenderWidgetHostViewAura::OnCompositingEnded( |
| ui::Compositor* compositor) { |
| } |
| |
| void RenderWidgetHostViewAura::OnCompositingAborted( |
| ui::Compositor* compositor) { |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation: |
| |
| void RenderWidgetHostViewAura::OnLostResources() { |
| image_transport_clients_.clear(); |
| current_surface_ = 0; |
| protection_state_id_ = 0; |
| current_surface_is_protected_ = true; |
| current_surface_in_use_by_compositor_ = true; |
| surface_route_id_ = 0; |
| UpdateExternalTexture(); |
| locks_pending_draw_.clear(); |
| |
| DCHECK(!shared_surface_handle_.is_null()); |
| ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
| factory->DestroySharedSurfaceHandle(shared_surface_handle_); |
| shared_surface_handle_ = factory->CreateSharedSurfaceHandle(); |
| host_->CompositingSurfaceUpdated(); |
| host_->ScheduleComposite(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, private: |
| |
| RenderWidgetHostViewAura::~RenderWidgetHostViewAura() { |
| if (!shared_surface_handle_.is_null()) { |
| ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
| factory->DestroySharedSurfaceHandle(shared_surface_handle_); |
| factory->RemoveObserver(this); |
| } |
| window_->RemoveObserver(window_observer_.get()); |
| UnlockMouse(); |
| if (popup_type_ != WebKit::WebPopupTypeNone) { |
| DCHECK(popup_parent_host_view_); |
| popup_parent_host_view_->popup_child_host_view_ = NULL; |
| } |
| aura::client::SetTooltipText(window_, NULL); |
| |
| for (size_t i = 0; i != pending_thumbnail_tasks_.size(); ++i) |
| pending_thumbnail_tasks_[i].Run(false); |
| |
| // 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(); |
| } |
| |
| void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() { |
| const gfx::Point screen_point = gfx::Screen::GetCursorScreenPoint(); |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| if (!root_window) |
| return; |
| |
| gfx::Rect screen_rect = GetViewBounds(); |
| gfx::Point local_point = screen_point; |
| local_point.Offset(-screen_rect.x(), -screen_rect.y()); |
| |
| if (root_window->GetEventHandlerForPoint(local_point) != window_) |
| return; |
| |
| gfx::NativeCursor cursor = current_cursor_.GetNativeCursor(); |
| if (is_loading_) |
| 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 { |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| if (!root_window) |
| return NULL; |
| return root_window->GetProperty(aura::client::kRootWindowInputMethodKey); |
| } |
| |
| bool RenderWidgetHostViewAura::NeedsInputGrab() { |
| return popup_type_ == WebKit::WebPopupTypeSelect; |
| } |
| |
| void RenderWidgetHostViewAura::FinishImeCompositionSession() { |
| if (!has_composition_text_) |
| return; |
| if (host_) |
| host_->ImeConfirmComposition(); |
| ImeCancelComposition(); |
| } |
| |
| void RenderWidgetHostViewAura::ModifyEventMovementAndCoords( |
| WebKit::WebMouseEvent* event) { |
| // If the mouse has just entered, we must report zero movementX/Y. Hence we |
| // reset any global_mouse_position set previously. |
| if (event->type == WebKit::WebInputEvent::MouseEnter || |
| event->type == WebKit::WebInputEvent::MouseLeave) |
| global_mouse_position_.SetPoint(event->globalX, event->globalY); |
| |
| // Movement is computed by taking the difference of the new cursor position |
| // and the previous. Under mouse lock the cursor will be warped back to the |
| // center so that we are not limited by clipping boundaries. |
| // We do not measure movement as the delta from cursor to center because |
| // we may receive more mouse movement events before our warp has taken |
| // effect. |
| event->movementX = event->globalX - global_mouse_position_.x(); |
| event->movementY = event->globalY - global_mouse_position_.y(); |
| |
| global_mouse_position_.SetPoint(event->globalX, event->globalY); |
| |
| // Under mouse lock, coordinates of mouse are locked to what they were when |
| // mouse lock was entered. |
| if (mouse_locked_) { |
| event->x = unlocked_mouse_position_.x(); |
| event->y = unlocked_mouse_position_.y(); |
| event->windowX = unlocked_mouse_position_.x(); |
| event->windowY = unlocked_mouse_position_.y(); |
| event->globalX = unlocked_global_mouse_position_.x(); |
| event->globalY = unlocked_global_mouse_position_.y(); |
| } else { |
| unlocked_mouse_position_.SetPoint(event->windowX, event->windowY); |
| unlocked_global_mouse_position_.SetPoint(event->globalX, event->globalY); |
| } |
| } |
| |
| void RenderWidgetHostViewAura::SchedulePaintIfNotInClip( |
| const gfx::Rect& rect, |
| const gfx::Rect& clip) { |
| if (!clip.IsEmpty()) { |
| gfx::Rect to_paint = rect.Subtract(clip); |
| if (!to_paint.IsEmpty()) |
| window_->SchedulePaintInRect(to_paint); |
| } else { |
| window_->SchedulePaintInRect(rect); |
| } |
| } |
| |
| bool RenderWidgetHostViewAura::ShouldMoveToCenter() { |
| gfx::Rect rect = window_->bounds(); |
| int border_x = rect.width() * kMouseLockBorderPercentage / 100; |
| int border_y = rect.height() * kMouseLockBorderPercentage / 100; |
| |
| return global_mouse_position_.x() < rect.x() + border_x || |
| global_mouse_position_.x() > rect.right() - border_x || |
| global_mouse_position_.y() < rect.y() + border_y || |
| global_mouse_position_.y() > rect.bottom() - border_y; |
| } |
| |
| void RenderWidgetHostViewAura::RunCompositingDidCommitCallbacks( |
| ui::Compositor* compositor) { |
| for (std::vector< base::Callback<void(ui::Compositor*)> >::const_iterator |
| it = on_compositing_did_commit_callbacks_.begin(); |
| it != on_compositing_did_commit_callbacks_.end(); ++it) { |
| it->Run(compositor); |
| } |
| on_compositing_did_commit_callbacks_.clear(); |
| } |
| |
| void RenderWidgetHostViewAura::RunCompositingWillStartCallbacks( |
| ui::Compositor* compositor) { |
| for (std::vector< base::Callback<void(ui::Compositor*)> >::const_iterator |
| it = on_compositing_will_start_callbacks_.begin(); |
| it != on_compositing_will_start_callbacks_.end(); ++it) { |
| it->Run(compositor); |
| } |
| on_compositing_will_start_callbacks_.clear(); |
| } |
| |
| // static |
| void RenderWidgetHostViewAura::InsertSyncPointAndACK( |
| int32 route_id, int gpu_host_id, ui::Compositor* compositor) { |
| uint32 sync_point = 0; |
| // If we have no compositor, so we must still send the ACK. A zero |
| // sync point will not be waited for in the GPU process. |
| if (compositor) { |
| ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
| sync_point = factory->InsertSyncPoint(); |
| } |
| |
| RenderWidgetHostImpl::AcknowledgeBufferPresent( |
| route_id, gpu_host_id, sync_point); |
| } |
| |
| void RenderWidgetHostViewAura::RemovingFromRootWindow() { |
| // We are about to disconnect ourselves from the compositor, we need to issue |
| // the callbacks now, because we won't get notified when the frame is done. |
| // TODO(piman): this might in theory cause a race where the GPU process starts |
| // drawing to the buffer we haven't yet displayed. This will only show for 1 |
| // frame though, because we will reissue a new frame right away without that |
| // composited data. |
| ui::Compositor* compositor = GetCompositor(); |
| RunCompositingDidCommitCallbacks(compositor); |
| RunCompositingWillStartCallbacks(compositor); |
| locks_pending_draw_.clear(); |
| if (compositor && compositor->HasObserver(this)) |
| compositor->RemoveObserver(this); |
| DetachFromInputMethod(); |
| } |
| |
| ui::Compositor* RenderWidgetHostViewAura::GetCompositor() { |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| return root_window ? root_window->compositor() : NULL; |
| } |
| |
| void RenderWidgetHostViewAura::DetachFromInputMethod() { |
| ui::InputMethod* input_method = GetInputMethod(); |
| if (input_method && input_method->GetTextInputClient() == this) |
| input_method->SetFocusedTextInputClient(NULL); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostView, public: |
| |
| // static |
| RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( |
| RenderWidgetHost* widget) { |
| return new RenderWidgetHostViewAura(widget); |
| } |
| |
| // static |
| void RenderWidgetHostViewPort::GetDefaultScreenInfo(WebScreenInfo* results) { |
| GetScreenInfoForWindow(results, NULL); |
| } |
| |
| } // namespace content |