| // 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/logging.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/string_number_conversions.h" |
| #include "content/browser/renderer_host/backing_store_skia.h" |
| #include "content/browser/renderer_host/image_transport_client.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/port/browser/render_widget_host_view_port.h" |
| #include "content/public/browser/browser_thread.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/tooltip_client.h" |
| #include "ui/aura/client/window_types.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/event.h" |
| #include "ui/aura/monitor.h" |
| #include "ui/aura/monitor_manager.h" |
| #include "ui/aura/root_window.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_observer.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/gfx/canvas.h" |
| #include "ui/gfx/compositor/compositor.h" |
| #include "ui/gfx/compositor/layer.h" |
| #include "ui/gfx/screen.h" |
| #include "ui/gfx/skia_util.h" |
| |
| using content::BrowserThread; |
| using content::RenderWidgetHost; |
| using content::RenderWidgetHostImpl; |
| using content::RenderWidgetHostView; |
| using WebKit::WebTouchEvent; |
| |
| 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; |
| |
| 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 aura::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; |
| } |
| |
| // Creates a content::GLHelper for the given compositor. |
| content::GLHelper* CreateGLHelper(ui::Compositor* compositor) { |
| ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
| WebKit::WebGraphicsContext3D* context = |
| factory->GetSharedContext(compositor); |
| DCHECK(context); |
| WebKit::WebGraphicsContext3D* context_for_thread = |
| factory->AsContextFactory()->CreateOffscreenContext(compositor); |
| DCHECK(context_for_thread); |
| return new content::GLHelper(context, context_for_thread); |
| } |
| |
| void GetScreenInfoForWindow(WebKit::WebScreenInfo* results, |
| const aura::Window* window) { |
| aura::MonitorManager* monitor_manager = |
| aura::Env::GetInstance()->monitor_manager(); |
| const aura::Monitor* monitor = window ? |
| monitor_manager->GetMonitorNearestWindow(window) : |
| monitor_manager->GetMonitorAt(0); |
| |
| const gfx::Size size = monitor->size(); |
| results->rect = WebKit::WebRect(0, 0, size.width(), size.height()); |
| results->availableRect = results->rect; |
| // TODO(derat): Don't hardcode this? |
| results->depth = 24; |
| results->depthPerComponent = 8; |
| int default_dpi = monitor->GetDeviceScaleFactor() * 160; |
| // TODO(fsamuel): This is a temporary hack until Monitor code is complete. |
| const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| if (command_line.HasSwitch(switches::kDefaultDeviceScaleFactor)) { |
| int default_device_scale_factor; |
| base::StringToInt(command_line.GetSwitchValueASCII( |
| switches::kDefaultDeviceScaleFactor), |
| &default_device_scale_factor); |
| default_dpi = default_device_scale_factor * 160; |
| } |
| results->verticalDPI = default_dpi; |
| results->horizontalDPI = default_dpi; |
| } |
| |
| } // 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: |
| 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 base::SupportsWeakPtr<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()) { |
| root_window_->HoldMouseMoves(); |
| |
| BrowserThread::PostDelayedTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&RenderWidgetHostViewAura::ResizeLock::CancelLock, |
| AsWeakPtr()), |
| 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_; |
| |
| 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))), |
| 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), |
| current_surface_(0), |
| paint_canvas_(NULL), |
| synthetic_move_sent_(false), |
| needs_update_texture_(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::~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); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // 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& pos) { |
| 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"); |
| |
| window_->SetParent(NULL); |
| SetBounds(pos); |
| 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); |
| window_->SetParent(NULL); |
| Show(); |
| Focus(); |
| } |
| |
| RenderWidgetHost* RenderWidgetHostViewAura::GetRenderWidgetHost() const { |
| return host_; |
| } |
| |
| void RenderWidgetHostViewAura::DidBecomeSelected() { |
| host_->WasRestored(); |
| } |
| |
| void RenderWidgetHostViewAura::WasHidden() { |
| host_->WasHidden(); |
| } |
| |
| 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()) { |
| resize_locks_.push_back(make_linked_ptr( |
| new ResizeLock(window_->GetRootWindow(), rect.size()))); |
| } |
| window_->SetBounds(rect); |
| host_->WasResized(); |
| } |
| |
| gfx::NativeView RenderWidgetHostViewAura::GetNativeView() const { |
| return window_; |
| } |
| |
| gfx::NativeViewId RenderWidgetHostViewAura::GetNativeViewId() const { |
| return static_cast<gfx::NativeViewId>(NULL); |
| } |
| |
| gfx::NativeViewAccessible RenderWidgetHostViewAura::GetNativeViewAccessible() { |
| NOTIMPLEMENTED(); |
| return static_cast<gfx::NativeViewAccessible>(NULL); |
| } |
| |
| void RenderWidgetHostViewAura::MovePluginWindows( |
| const std::vector<webkit::npapi::WebPluginGeometry>& moves) { |
| // We don't support windowed plugins. |
| } |
| |
| void RenderWidgetHostViewAura::Focus() { |
| window_->Focus(); |
| } |
| |
| void RenderWidgetHostViewAura::Blur() { |
| window_->Blur(); |
| } |
| |
| bool RenderWidgetHostViewAura::HasFocus() const { |
| return window_->HasFocus(); |
| } |
| |
| void RenderWidgetHostViewAura::Show() { |
| window_->Show(); |
| } |
| |
| void RenderWidgetHostViewAura::Hide() { |
| window_->Hide(); |
| } |
| |
| bool RenderWidgetHostViewAura::IsShowing() { |
| return window_->IsVisible(); |
| } |
| |
| gfx::Rect RenderWidgetHostViewAura::GetViewBounds() const { |
| return window_->GetScreenBounds(); |
| } |
| |
| void RenderWidgetHostViewAura::UpdateCursor(const WebCursor& cursor) { |
| current_cursor_ = cursor; |
| UpdateCursorIfOverSelf(); |
| } |
| |
| void RenderWidgetHostViewAura::SetIsLoading(bool is_loading) { |
| is_loading_ = is_loading; |
| UpdateCursorIfOverSelf(); |
| } |
| |
| void RenderWidgetHostViewAura::TextInputStateChanged( |
| ui::TextInputType type, |
| bool can_compose_inline) { |
| if (text_input_type_ != type || can_compose_inline_ != can_compose_inline) { |
| text_input_type_ = type; |
| can_compose_inline_ = can_compose_inline; |
| GetInputMethod()->OnTextInputTypeChanged(this); |
| } |
| } |
| |
| void RenderWidgetHostViewAura::ImeCancelComposition() { |
| GetInputMethod()->CancelComposition(this); |
| has_composition_text_ = false; |
| } |
| |
| void RenderWidgetHostViewAura::DidUpdateBackingStore( |
| const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, |
| const std::vector<gfx::Rect>& copy_rects) { |
| if (!window_->IsVisible()) |
| return; |
| |
| if (needs_update_texture_) |
| UpdateExternalTexture(); |
| |
| 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); |
| } |
| } |
| |
| 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. |
| 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::SelectionBoundsChanged( |
| const gfx::Rect& start_rect, |
| const gfx::Rect& end_rect) { |
| if (selection_start_rect_ == start_rect && selection_end_rect_ == end_rect) |
| return; |
| |
| selection_start_rect_ = start_rect; |
| selection_end_rect_ = end_rect; |
| |
| GetInputMethod()->OnCaretBoundsChanged(this); |
| } |
| |
| BackingStore* RenderWidgetHostViewAura::AllocBackingStore( |
| const gfx::Size& size) { |
| return new BackingStoreSkia(host_, size); |
| } |
| |
| bool RenderWidgetHostViewAura::CopyFromCompositingSurface( |
| const gfx::Size& size, |
| skia::PlatformCanvas* output) { |
| ui::Compositor* compositor = GetCompositor(); |
| if (!compositor) |
| return false; |
| |
| ImageTransportClient* container = image_transport_clients_[current_surface_]; |
| if (!container) |
| return false; |
| |
| if (!output->initialize(size.width(), size.height(), true)) |
| return false; |
| |
| if (!gl_helper_.get()) |
| gl_helper_.reset(CreateGLHelper(compositor)); |
| |
| unsigned char* addr = static_cast<unsigned char*>( |
| output->getTopDevice()->accessBitmap(true).getPixels()); |
| return gl_helper_->CopyTextureTo(container->texture_id(), |
| container->size(), |
| size, |
| addr); |
| } |
| |
| void RenderWidgetHostViewAura::AsyncCopyFromCompositingSurface( |
| const gfx::Size& size, |
| skia::PlatformCanvas* output, |
| base::Callback<void(bool)> callback) { |
| base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false)); |
| ui::Compositor* compositor = GetCompositor(); |
| if (!compositor) |
| return; |
| |
| ImageTransportClient* container = image_transport_clients_[current_surface_]; |
| if (!container) |
| return; |
| |
| if (!output->initialize(size.width(), size.height(), true)) |
| return; |
| |
| if (!gl_helper_.get()) |
| gl_helper_.reset(CreateGLHelper(compositor)); |
| |
| scoped_callback_runner.Release(); |
| unsigned char* addr = static_cast<unsigned char*>( |
| output->getTopDevice()->accessBitmap(true).getPixels()); |
| gl_helper_->AsyncCopyTextureTo(container->texture_id(), |
| container->size(), |
| size, |
| addr, |
| callback); |
| } |
| |
| void RenderWidgetHostViewAura::OnAcceleratedCompositingStateChange() { |
| // Delay UpdateExternalTexture until we actually got a software frame. |
| // 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. |
| needs_update_texture_ = true; |
| } |
| |
| void RenderWidgetHostViewAura::UpdateExternalTexture() { |
| needs_update_texture_ = false; |
| if (current_surface_ != 0 && |
| host_->is_accelerated_compositing_active()) { |
| |
| ImageTransportClient* container = |
| image_transport_clients_[current_surface_]; |
| if (container) |
| container->Update(); |
| window_->SetExternalTexture(container); |
| |
| if (!container) { |
| resize_locks_.clear(); |
| } else { |
| typedef std::vector<linked_ptr<ResizeLock> > ResizeLockList; |
| ResizeLockList::iterator it = resize_locks_.begin(); |
| while (it != resize_locks_.end()) { |
| 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); |
| resize_locks_.clear(); |
| } |
| } |
| |
| void RenderWidgetHostViewAura::AcceleratedSurfaceBuffersSwapped( |
| const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, |
| int gpu_host_id) { |
| current_surface_ = params.surface_handle; |
| 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. |
| RenderWidgetHostImpl::AcknowledgeSwapBuffers(params.route_id, gpu_host_id); |
| } else { |
| gfx::Size surface_size = |
| image_transport_clients_[params.surface_handle]->size(); |
| window_->SchedulePaintInRect(gfx::Rect(surface_size)); |
| |
| if (!resize_locks_.empty() && !compositor->DrawPending()) { |
| // If we are waiting for the resize, fast-track the ACK. |
| // However only do so if we're not between the Draw() and the |
| // OnCompositingEnded(), because out-of-order execution in the GPU process |
| // might corrupt the "front buffer" for the currently issued frame. |
| RenderWidgetHostImpl::AcknowledgeSwapBuffers( |
| params.route_id, gpu_host_id); |
| } else { |
| // Add sending an ACK to the list of things to do OnCompositingEnded |
| on_compositing_ended_callbacks_.push_back( |
| base::Bind(&RenderWidgetHostImpl::AcknowledgeSwapBuffers, |
| params.route_id, gpu_host_id)); |
| if (!compositor->HasObserver(this)) |
| compositor->AddObserver(this); |
| } |
| } |
| } |
| |
| void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer( |
| const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params, |
| int gpu_host_id) { |
| current_surface_ = params.surface_handle; |
| 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 |
| RenderWidgetHostImpl::AcknowledgePostSubBuffer( |
| params.route_id, gpu_host_id); |
| } else { |
| gfx::Size surface_size = |
| image_transport_clients_[params.surface_handle]->size(); |
| |
| // Co-ordinates come in OpenGL co-ordinate space. |
| // We need to convert to layer space. |
| window_->SchedulePaintInRect(gfx::Rect( |
| params.x, |
| surface_size.height() - params.y - params.height, |
| params.width, |
| params.height)); |
| |
| if (!resize_locks_.empty() && !compositor->DrawPending()) { |
| // If we are waiting for the resize, fast-track the ACK. |
| // However only do so if we're not between the Draw() and the |
| // OnCompositingEnded(), because out-of-order execution in the GPU process |
| // might corrupt the "front buffer" for the currently issued frame. |
| RenderWidgetHostImpl::AcknowledgePostSubBuffer( |
| params.route_id, gpu_host_id); |
| } else { |
| // Add sending an ACK to the list of things to do OnCompositingEnded |
| on_compositing_ended_callbacks_.push_back( |
| base::Bind(&RenderWidgetHostImpl::AcknowledgePostSubBuffer, |
| params.route_id, gpu_host_id)); |
| if (!compositor->HasObserver(this)) |
| compositor->AddObserver(this); |
| } |
| } |
| } |
| |
| void RenderWidgetHostViewAura::AcceleratedSurfaceSuspend() { |
| } |
| |
| void RenderWidgetHostViewAura::AcceleratedSurfaceNew( |
| int32 width, |
| int32 height, |
| uint64* surface_handle, |
| TransportDIB::Handle* shm_handle) { |
| ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
| scoped_refptr<ImageTransportClient> surface(factory->CreateTransportClient( |
| gfx::Size(width, height), surface_handle)); |
| if (!surface) { |
| LOG(ERROR) << "Failed to create ImageTransportClient"; |
| return; |
| } |
| *shm_handle = surface->Handle(); |
| |
| image_transport_clients_[*surface_handle] = surface; |
| } |
| |
| void RenderWidgetHostViewAura::AcceleratedSurfaceRelease( |
| uint64 surface_handle) { |
| if (current_surface_ == surface_handle) { |
| current_surface_ = 0; |
| UpdateExternalTexture(); |
| } |
| image_transport_clients_.erase(surface_handle); |
| } |
| |
| void RenderWidgetHostViewAura::SetBackground(const SkBitmap& background) { |
| content::RenderWidgetHostViewBase::SetBackground(background); |
| host_->SetBackground(background); |
| window_->layer()->SetFillsBoundsOpaquely(background.isOpaque()); |
| } |
| |
| void RenderWidgetHostViewAura::GetScreenInfo(WebKit::WebScreenInfo* results) { |
| GetScreenInfoForWindow(results, window_); |
| } |
| |
| gfx::Rect RenderWidgetHostViewAura::GetRootWindowBounds() { |
| return window_->GetToplevelWindow()->bounds(); |
| } |
| |
| 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() { |
| ui::Compositor* compositor = GetCompositor(); |
| if (shared_surface_handle_.is_null() && compositor) { |
| ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
| shared_surface_handle_ = factory->CreateSharedSurfaceHandle(compositor); |
| 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; |
| |
| root_window->SetCapture(window_, ui::CW_LOCK_MOUSE); |
| if (root_window->ConfineCursorToWindow()) { |
| root_window->ShowCursor(false); |
| synthetic_move_sent_ = true; |
| root_window->MoveCursorTo(window_->bounds().CenterPoint()); |
| if (aura::client::GetTooltipClient(root_window)) |
| aura::client::GetTooltipClient(root_window)->SetTooltipsEnabled(false); |
| return true; |
| } else { |
| mouse_locked_ = false; |
| root_window->ReleaseCapture(window_); |
| return false; |
| } |
| } |
| |
| void RenderWidgetHostViewAura::UnlockMouse() { |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| if (!mouse_locked_ || !root_window) |
| return; |
| |
| mouse_locked_ = false; |
| |
| root_window->ReleaseCapture(window_); |
| root_window->MoveCursorTo(unlocked_global_mouse_position_); |
| root_window->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::GetCaretBounds() { |
| const gfx::Rect rect = selection_start_rect_.Union(selection_end_rect_); |
| gfx::Point origin = rect.origin(); |
| gfx::Point end = gfx::Point(rect.right(), rect.bottom()); |
| |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| aura::Window::ConvertPointToWindow(window_, root_window, &origin); |
| aura::Window::ConvertPointToWindow(window_, root_window, &end); |
| // TODO(yusukes): Unlike Chrome OS, |root_window| origin might not be the |
| // same as the system screen origin on Windows and Linux. Probably we should |
| // (implement and) use something like ConvertPointToScreen(). |
| |
| return gfx::Rect(origin.x(), |
| origin.y(), |
| end.x() - origin.x(), |
| end.y() - origin.y()); |
| } |
| |
| 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; |
| |
| 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; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // 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() { |
| // 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(); |
| |
| ui::InputMethod* input_method = GetInputMethod(); |
| if (input_method) { |
| if (input_method->GetTextInputClient() == this) |
| input_method->SetFocusedTextInputClient(NULL); |
| } |
| host_->SetInputMethodActive(false); |
| } |
| |
| bool RenderWidgetHostViewAura::OnKeyEvent(aura::KeyEvent* event) { |
| if (popup_child_host_view_ && popup_child_host_view_->NeedsInputGrab() && |
| popup_child_host_view_->OnKeyEvent(event)) |
| return true; |
| |
| // We need to handle the Escape key for Pepper Flash. |
| if (is_fullscreen_ && event->key_code() == ui::VKEY_ESCAPE) { |
| 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 true; |
| } |
| |
| 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::OnMouseEvent(aura::MouseEvent* event) { |
| if (mouse_locked_) { |
| WebKit::WebMouseEvent mouse_event = content::MakeWebMouseEvent(event); |
| gfx::Point center = window_->bounds().CenterPoint(); |
| |
| bool is_move_to_center_event = (event->type() == ui::ET_MOUSE_MOVED || |
| event->type() == ui::ET_MOUSE_DRAGGED) && |
| mouse_event.globalX == center.x() && mouse_event.globalY == 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_->GetRootWindow()->MoveCursorTo(center); |
| } |
| |
| // Forward event to renderer. |
| if (CanRendererHandleEvent(event)) |
| host_->ForwardMouseEvent(mouse_event); |
| } |
| |
| return false; |
| } |
| |
| if (event->type() == ui::ET_MOUSEWHEEL) { |
| WebKit::WebMouseWheelEvent mouse_wheel_event = |
| content::MakeWebMouseWheelEvent(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::WebMouseWheelEvent mouse_wheel_event = |
| content::MakeWebMouseWheelEvent(static_cast<aura::ScrollEvent*>(event)); |
| host_->ForwardWheelEvent(mouse_wheel_event); |
| } else if (event->type() == ui::ET_SCROLL_FLING_START || |
| event->type() == ui::ET_SCROLL_FLING_CANCEL) { |
| WebKit::WebGestureEvent gesture_event = |
| content::MakeWebGestureEvent(static_cast<aura::ScrollEvent*>(event)); |
| host_->ForwardGestureEvent(gesture_event); |
| } else if (CanRendererHandleEvent(event)) { |
| WebKit::WebMouseEvent mouse_event = content::MakeWebMouseEvent(event); |
| ModifyEventMovementAndCoords(&mouse_event); |
| host_->ForwardMouseEvent(mouse_event); |
| } |
| |
| switch (event->type()) { |
| case ui::ET_MOUSE_PRESSED: |
| window_->SetCapture(ui::CW_LOCK_MOUSE); |
| // 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 true; |
| } |
| |
| ui::TouchStatus RenderWidgetHostViewAura::OnTouchEvent( |
| aura::TouchEvent* event) { |
| // Update the touch event first. |
| WebKit::WebTouchPoint* point = content::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::GestureStatus RenderWidgetHostViewAura::OnGestureEvent( |
| aura::GestureEvent* event) { |
| WebKit::WebGestureEvent gesture = content::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); |
| } |
| host_->ForwardGestureEvent(gesture); |
| |
| // 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::GESTURE_STATUS_CONSUMED; |
| } |
| |
| bool RenderWidgetHostViewAura::CanFocus() { |
| return popup_type_ == WebKit::WebPopupTypeNone; |
| } |
| |
| void RenderWidgetHostViewAura::OnCaptureLost() { |
| host_->LostCapture(); |
| } |
| |
| void RenderWidgetHostViewAura::OnPaint(gfx::Canvas* canvas) { |
| if (!window_->IsVisible()) |
| return; |
| paint_canvas_ = canvas; |
| BackingStore* backing_store = host_->GetBackingStore(true); |
| paint_canvas_ = NULL; |
| if (backing_store) { |
| static_cast<BackingStoreSkia*>(backing_store)->SkiaShowRect(gfx::Point(), |
| canvas); |
| } else { |
| canvas->FillRect(gfx::Rect(window_->bounds().size()), SK_ColorWHITE); |
| } |
| } |
| |
| void RenderWidgetHostViewAura::OnWindowDestroying() { |
| } |
| |
| void RenderWidgetHostViewAura::OnWindowDestroyed() { |
| host_->ViewDestroyed(); |
| delete this; |
| } |
| |
| void RenderWidgetHostViewAura::OnWindowVisibilityChanged(bool visible) { |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, aura::client::ActivationDelegate implementation: |
| |
| bool RenderWidgetHostViewAura::ShouldActivate(const aura::Event* event) { |
| if (event && event->type() == ui::ET_MOUSE_PRESSED) |
| host_->OnMouseActivate(); |
| return is_fullscreen_; |
| } |
| |
| void RenderWidgetHostViewAura::OnActivated() { |
| } |
| |
| void RenderWidgetHostViewAura::OnLostActive() { |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, ui::CompositorDelegate implementation: |
| |
| void RenderWidgetHostViewAura::OnCompositingStarted( |
| ui::Compositor* compositor) { |
| locks_pending_draw_.clear(); |
| } |
| |
| void RenderWidgetHostViewAura::OnCompositingEnded(ui::Compositor* compositor) { |
| RunCompositingCallbacks(); |
| compositor->RemoveObserver(this); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation: |
| |
| void RenderWidgetHostViewAura::OnLostResources(ui::Compositor* compositor) { |
| image_transport_clients_.clear(); |
| current_surface_ = 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(compositor); |
| host_->CompositingSurfaceUpdated(); |
| host_->ScheduleComposite(); |
| |
| if (gl_helper_.get()) { |
| // Detach the resources to avoid deleting them using the invalid context. |
| // They've been released anyway when the GPU process died. |
| gl_helper_->Detach(); |
| gl_helper_.reset(CreateGLHelper(compositor)); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostViewAura, private: |
| |
| void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() { |
| const gfx::Point screen_point = gfx::Screen::GetCursorScreenPoint(); |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| if (!root_window) |
| return; |
| |
| if (root_window->GetEventHandlerForPoint(screen_point) != window_) |
| return; |
| |
| gfx::NativeCursor cursor = current_cursor_.GetNativeCursor(); |
| if (is_loading_ && cursor == ui::kCursorPointer) |
| cursor = ui::kCursorProgress; |
| |
| root_window->SetCursor(cursor); |
| } |
| |
| ui::InputMethod* RenderWidgetHostViewAura::GetInputMethod() const { |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| 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::RunCompositingCallbacks() { |
| for (std::vector< base::Callback<void(void)> >::const_iterator |
| it = on_compositing_ended_callbacks_.begin(); |
| it != on_compositing_ended_callbacks_.end(); ++it) { |
| it->Run(); |
| } |
| on_compositing_ended_callbacks_.clear(); |
| } |
| |
| 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. |
| RunCompositingCallbacks(); |
| locks_pending_draw_.clear(); |
| ui::Compositor* compositor = GetCompositor(); |
| if (compositor && compositor->HasObserver(this)) |
| compositor->RemoveObserver(this); |
| } |
| |
| ui::Compositor* RenderWidgetHostViewAura::GetCompositor() { |
| aura::RootWindow* root_window = window_->GetRootWindow(); |
| return root_window ? root_window->compositor() : NULL; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // RenderWidgetHostView, public: |
| |
| // static |
| RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( |
| RenderWidgetHost* widget) { |
| return new RenderWidgetHostViewAura(widget); |
| } |
| |
| // static |
| void content::RenderWidgetHostViewPort::GetDefaultScreenInfo( |
| WebKit::WebScreenInfo* results) { |
| GetScreenInfoForWindow(results, NULL); |
| } |