Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(977)

Unified Diff: components/exo/pointer.cc

Issue 2780623002: exo: Fix multi-display hardware cursor (Closed)
Patch Set: Address comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698