Index: components/exo/pointer.cc |
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc |
index 073c750192f374b967e3c25061542d8f88136460..3764f4d5ce7e753cd4c9f58bf6c32912e316c338 100644 |
--- a/components/exo/pointer.cc |
+++ b/components/exo/pointer.cc |
@@ -14,6 +14,7 @@ |
#include "ui/aura/client/cursor_client.h" |
#include "ui/aura/env.h" |
#include "ui/aura/window.h" |
+#include "ui/base/cursor/cursor_util.h" |
#include "ui/display/manager/display_manager.h" |
#include "ui/display/manager/managed_display_info.h" |
#include "ui/display/screen.h" |
@@ -32,7 +33,13 @@ |
namespace exo { |
namespace { |
-const float kLargeCursorScale = 2.8f; |
+// TODO(oshima): Some accessibility features, including large cursors, disable |
+// hardware cursors. Ash does not support compositing for custom cursors, so it |
+// replaces them with the default cursor. As a result, this scale has no effect |
+// for now. See crbug.com/708378. |
+float GetCursorScale(ui::CursorSetType cursor_set) { |
+ return cursor_set == ui::CURSOR_SET_LARGE ? 2.8f : 1.0f; |
reveman
2017/05/25 10:52:55
I still prefer if this was folded into UpdateCurso
Dominik Laskowski
2017/05/31 02:06:26
Done.
|
+} |
// Synthesized events typically lack floating point precision so to avoid |
// generating mouse event jitter we consider the location of these events |
@@ -44,6 +51,13 @@ bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) { |
return event->location_f() == location; |
} |
+inline const display::ManagedDisplayInfo& GetDisplayInfo( |
reveman
2017/05/25 10:52:55
this helper doesn't seem useful. please use WMHelp
Dominik Laskowski
2017/05/31 02:06:26
Done.
|
+ const display::Display& display) { |
+ return WMHelper::GetInstance()->GetDisplayInfo(display.id()); |
+} |
+ |
+constexpr float kCursorCaptureScale = 2.0f; |
+ |
} // namespace |
//////////////////////////////////////////////////////////////////////////////// |
@@ -51,12 +65,17 @@ bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) { |
Pointer::Pointer(PointerDelegate* delegate) |
: delegate_(delegate), |
- cursor_(ui::CursorType::kNull), |
cursor_capture_source_id_(base::UnguessableToken::Create()), |
cursor_capture_weak_ptr_factory_(this) { |
auto* helper = WMHelper::GetInstance(); |
helper->AddPreTargetHandler(this); |
helper->AddCursorObserver(this); |
+ |
+ cursor_scale_ = GetCursorScale(helper->GetCursorSet()); |
+ |
+ display::Screen* screen = display::Screen::GetScreen(); |
+ OnCursorDisplayChanging( |
+ screen->GetDisplayNearestPoint(screen->GetCursorScreenPoint())); |
reveman
2017/05/25 10:52:55
these lines should not be necessary after addressi
Dominik Laskowski
2017/05/31 02:06:26
Done.
|
} |
Pointer::~Pointer() { |
@@ -77,9 +96,6 @@ void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) { |
if (!focus_) |
return; |
- // This is used to avoid unnecessary cursor changes. |
reveman
2017/05/25 10:52:55
I'd like to keep this logic as before.
Dominik Laskowski
2017/05/31 02:06:26
Done.
|
- bool cursor_changed = false; |
- |
// If surface is different than the current pointer surface then remove the |
// current surface and add the new surface. |
if (surface != surface_) { |
@@ -102,35 +118,33 @@ void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) { |
// snapshot. Where in the tree is not important but we might as well use |
// the cursor container. |
WMHelper::GetInstance() |
- ->GetContainer(ash::kShellWindowId_MouseCursorContainer) |
+ ->GetContainer(display::Screen::GetScreen()->GetPrimaryDisplay().id(), |
+ ash::kShellWindowId_MouseCursorContainer) |
->AddChild(surface_->window()); |
} |
- cursor_changed = true; |
- } |
- |
- // Update hotspot. |
- if (hotspot != hotspot_) { |
- hotspot_ = hotspot; |
- cursor_changed = true; |
- } |
- |
- // Early out if cursor did not change. |
- if (!cursor_changed) |
+ } else if (hotspot == hotspot_) { |
+ // Early out if cursor did not change. |
return; |
+ } |
// If |surface_| is set then asynchronously capture a snapshot of cursor, |
// otherwise cancel pending capture and immediately set the cursor to "none". |
if (surface_) { |
- CaptureCursor(); |
+ CaptureCursor(hotspot); |
} else { |
+ cursor_bitmap_.reset(); |
cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs(); |
- cursor_ = ui::CursorType::kNone; |
- UpdateCursor(); |
+ SetCursor(ui::CursorType::kNone); |
} |
} |
gfx::NativeCursor Pointer::GetCursor() { |
- return cursor_; |
+ if (focus_) |
+ if (auto* root_window = focus_->window()->GetRootWindow()) |
+ if (auto* cursor_client = aura::client::GetCursorClient(root_window)) |
+ return cursor_client->GetCursor(); |
+ |
+ return ui::CursorType::kNull; |
} |
//////////////////////////////////////////////////////////////////////////////// |
@@ -150,7 +164,6 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) { |
// response to each OnPointerEnter() call. |
focus_->UnregisterCursorProvider(this); |
focus_ = nullptr; |
- cursor_ = ui::CursorType::kNull; |
cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs(); |
} |
// Second generate an enter event if focus moved to a new target. |
@@ -240,7 +253,6 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) { |
} |
last_event_type_ = event->type(); |
- UpdateCursorScale(); |
} |
void Pointer::OnScrollEvent(ui::ScrollEvent* event) { |
@@ -251,8 +263,14 @@ void Pointer::OnScrollEvent(ui::ScrollEvent* event) { |
// WMHelper::CursorObserver overrides: |
void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) { |
+ cursor_scale_ = GetCursorScale(cursor_set); |
if (focus_) |
- UpdateCursorScale(); |
+ UpdateCursor(); |
+} |
+ |
+void Pointer::OnCursorDisplayChanging(const display::Display& display) { |
+ cursor_device_scale_factor_ = GetDisplayInfo(display).device_scale_factor(); |
reveman
2017/05/25 10:52:55
hm, do we need |cursor_scale_| and |cursor_rotatio
Dominik Laskowski
2017/05/31 02:06:26
Done.
|
+ cursor_rotation_ = display.rotation(); |
} |
//////////////////////////////////////////////////////////////////////////////// |
@@ -264,7 +282,7 @@ void Pointer::OnSurfaceCommit() { |
// Capture new cursor to reflect result of commit. |
if (focus_) |
- CaptureCursor(); |
+ CaptureCursor(hotspot_); |
} |
bool Pointer::IsSurfaceSynchronized() const { |
@@ -296,62 +314,24 @@ Surface* Pointer::GetEffectiveTargetForEvent(ui::Event* event) const { |
return delegate_->CanAcceptPointerEventsForSurface(target) ? target : nullptr; |
} |
-void Pointer::UpdateCursorScale() { |
- DCHECK(focus_); |
- |
- display::Screen* screen = display::Screen::GetScreen(); |
- WMHelper* helper = WMHelper::GetInstance(); |
- |
- // Update cursor scale if the effective UI scale has changed. |
- display::Display display = screen->GetDisplayNearestWindow(focus_->window()); |
- float scale = helper->GetDisplayInfo(display.id()).GetEffectiveUIScale(); |
- |
- if (display::Display::HasInternalDisplay()) { |
- float primary_device_scale_factor = |
- screen->GetPrimaryDisplay().device_scale_factor(); |
- // The size of the cursor surface is the quotient of its physical size and |
- // the DSF of the primary display. The physical size is proportional to the |
- // DSF of the internal display. For external displays (and the internal |
- // display when secondary to a display with a different DSF), scale the |
- // cursor so its physical size matches with the single display case. |
- if (!display.IsInternal() || |
- display.device_scale_factor() != primary_device_scale_factor) { |
- scale *= primary_device_scale_factor / |
- helper->GetDisplayInfo(display::Display::InternalDisplayId()) |
- .device_scale_factor(); |
- } |
- } |
- |
- if (helper->GetCursorSet() == ui::CURSOR_SET_LARGE) |
- scale *= kLargeCursorScale; |
- |
- if (scale != cursor_scale_) { |
- cursor_scale_ = scale; |
- if (surface_) |
- CaptureCursor(); |
- } |
-} |
- |
-void Pointer::CaptureCursor() { |
+void Pointer::CaptureCursor(const gfx::Point& hotspot) { |
DCHECK(surface_); |
DCHECK(focus_); |
- // Set UI scale before submitting capture request. |
- surface_->window()->layer()->SetTransform( |
- gfx::GetScaleTransform(gfx::Point(), cursor_scale_)); |
- |
- float primary_device_scale_factor = |
- display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); |
+ // Surface size is in DIPs, while layer size is in pseudo-DIP units that |
+ // depend on the DSF of the display mode. Scale the layer to capture the |
+ // surface at a constant pixel size, regardless of the primary display's |
+ // UI scale and display mode DSF. |
+ display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay(); |
+ float scale = GetDisplayInfo(display).GetEffectiveUIScale() * |
+ kCursorCaptureScale / display.device_scale_factor(); |
+ surface_->window()->SetTransform(gfx::GetScaleTransform(gfx::Point(), scale)); |
std::unique_ptr<cc::CopyOutputRequest> request = |
cc::CopyOutputRequest::CreateBitmapRequest( |
base::Bind(&Pointer::OnCursorCaptured, |
- cursor_capture_weak_ptr_factory_.GetWeakPtr(), |
- gfx::ScaleToFlooredPoint( |
- hotspot_, |
- // |hotspot_| is in surface coordinate space so apply |
- // both device scale and UI scale. |
- cursor_scale_ * primary_device_scale_factor))); |
+ cursor_capture_weak_ptr_factory_.GetWeakPtr(), hotspot)); |
+ |
request->set_source(cursor_capture_source_id_); |
surface_->window()->layer()->RequestCopyOfOutput(std::move(request)); |
} |
@@ -361,34 +341,53 @@ void Pointer::OnCursorCaptured(const gfx::Point& hotspot, |
if (!focus_) |
return; |
- cursor_ = ui::CursorType::kNone; |
- if (!result->IsEmpty()) { |
- DCHECK(result->HasBitmap()); |
- std::unique_ptr<SkBitmap> bitmap = result->TakeBitmap(); |
+ if (result->IsEmpty()) { |
+ cursor_bitmap_.reset(); |
+ SetCursor(ui::CursorType::kNone); |
+ return; |
+ } |
- ui::PlatformCursor platform_cursor; |
+ DCHECK(result->HasBitmap()); |
+ cursor_bitmap_ = *result->TakeBitmap(); |
+ hotspot_ = hotspot; |
+ UpdateCursor(); |
+} |
+ |
+void Pointer::UpdateCursor() { |
+ DCHECK(focus_); |
+ |
+ if (cursor_bitmap_.drawsNothing()) |
+ return; |
+ |
+ SkBitmap bitmap = cursor_bitmap_; |
+ gfx::Point hotspot = gfx::ScaleToFlooredPoint(hotspot_, kCursorCaptureScale); |
+ |
+ ui::ScaleAndRotateCursorBitmapAndHotpoint( |
+ cursor_scale_ * cursor_device_scale_factor_ / kCursorCaptureScale, |
+ cursor_rotation_, &bitmap, &hotspot); |
+ |
+ ui::PlatformCursor platform_cursor; |
#if defined(USE_OZONE) |
- // TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers |
- // and use that here instead of the current bitmap API. crbug.com/686600 |
- platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor( |
- *bitmap.get(), hotspot, cursor_scale_); |
+ // TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers |
+ // and use that here instead of the current bitmap API. crbug.com/686600 |
+ platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor( |
+ bitmap, hotspot, 0); |
#elif defined(USE_X11) |
- XcursorImage* image = ui::SkBitmapToXcursorImage(bitmap.get(), hotspot); |
- platform_cursor = ui::CreateReffedCustomXCursor(image); |
+ XcursorImage* image = ui::SkBitmapToXcursorImage(&bitmap, hotspot); |
+ platform_cursor = ui::CreateReffedCustomXCursor(image); |
#endif |
- cursor_ = ui::CursorType::kCustom; |
- cursor_.SetPlatformCursor(platform_cursor); |
+ gfx::NativeCursor cursor = ui::CursorType::kCustom; |
+ cursor.SetPlatformCursor(platform_cursor); |
#if defined(USE_OZONE) |
- ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor); |
+ ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor); |
#elif defined(USE_X11) |
- ui::UnrefCustomXCursor(platform_cursor); |
+ ui::UnrefCustomXCursor(platform_cursor); |
#endif |
- } |
- UpdateCursor(); |
+ SetCursor(cursor); |
} |
-void Pointer::UpdateCursor() { |
+void Pointer::SetCursor(gfx::NativeCursor cursor) { |
DCHECK(focus_); |
aura::Window* root_window = focus_->window()->GetRootWindow(); |
@@ -398,7 +397,7 @@ void Pointer::UpdateCursor() { |
aura::client::CursorClient* cursor_client = |
aura::client::GetCursorClient(root_window); |
if (cursor_client) |
- cursor_client->SetCursor(cursor_); |
+ cursor_client->SetCursor(cursor); |
} |
} // namespace exo |