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

Unified Diff: components/exo/pointer.cc

Issue 2780623002: exo: Fix multi-display hardware cursor (Closed)
Patch Set: Rebase properly Created 3 years, 9 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 092501a46248c805c0403528c72492abcd7e9d73..be71559b947628b6b2a11c43e8cc208da1776f1b 100644
--- a/components/exo/pointer.cc
+++ b/components/exo/pointer.cc
@@ -19,7 +19,7 @@
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
-#include "ui/gfx/transform_util.h"
+#include "ui/gfx/transform.h"
#if defined(USE_OZONE)
#include "ui/ozone/public/cursor_factory_ozone.h"
@@ -32,7 +32,12 @@
namespace exo {
namespace {
-const float kLargeCursorScale = 2.8f;
+// TODO: Some accessibility features, including large cursors, disable hardware
reveman 2017/03/30 07:47:53 nit: TODO(name) and please add a bug number
Dominik Laskowski 2017/04/05 17:59:25 Done. TODO(oshima) to be consistent with: https:/
+// 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.
+float GetCursorScale(ui::CursorSetType cursor_set) {
+ return cursor_set == ui::CURSOR_SET_LARGE ? 2.8f : 1.0f;
+}
// Synthesized events typically lack floating point precision so to avoid
// generating mouse event jitter we consider the location of these events
@@ -51,12 +56,19 @@ bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) {
Pointer::Pointer(PointerDelegate* delegate)
: delegate_(delegate),
- cursor_(ui::kCursorNull),
+ cursor_(new aura::Window(nullptr)),
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());
+
+ cursor_->SetName("ExoCursor");
+ cursor_->Init(ui::LAYER_NOT_DRAWN);
+ cursor_->set_owned_by_parent(false);
+ OnCursorDisplayChanging(display::Screen::GetScreen()->GetPrimaryDisplay());
}
Pointer::~Pointer() {
@@ -88,10 +100,7 @@ void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) {
return;
}
if (surface_) {
- surface_->window()->SetTransform(gfx::Transform());
- WMHelper::GetInstance()
- ->GetContainer(ash::kShellWindowId_MouseCursorContainer)
- ->RemoveChild(surface_->window());
+ cursor_->RemoveChild(surface_->window());
surface_->SetSurfaceDelegate(nullptr);
surface_->RemoveSurfaceObserver(this);
}
@@ -99,12 +108,8 @@ void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) {
if (surface_) {
surface_->SetSurfaceDelegate(this);
surface_->AddSurfaceObserver(this);
- // Note: Surface window needs to be added to the tree so we can take a
- // snapshot. Where in the tree is not important but we might as well use
- // the cursor container.
- WMHelper::GetInstance()
- ->GetContainer(ash::kShellWindowId_MouseCursorContainer)
- ->AddChild(surface_->window());
+ cursor_->AddChild(surface_->window());
+ surface_->window()->Show();
}
cursor_changed = true;
}
@@ -122,16 +127,20 @@ void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) {
// 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(false);
} else {
cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
- cursor_ = ui::kCursorNone;
- UpdateCursor();
+ UpdateCursor(ui::kCursorNone, false);
}
}
gfx::NativeCursor Pointer::GetCursor() {
- return cursor_;
reveman 2017/03/30 07:47:53 why does all this need to change? I think the prev
Dominik Laskowski 2017/04/05 17:59:25 Keeping track of the latest cursor is unnecessary,
+ if (!focus_)
+ return ui::kCursorNull;
reveman 2017/03/30 07:47:53 I think returning null cursor in this case is inco
Dominik Laskowski 2017/04/05 17:59:25 This is equivalent to the old code. Also, the curs
+
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(focus_->window()->GetRootWindow());
+ return cursor_client ? cursor_client->GetCursor() : ui::kCursorNull;
}
////////////////////////////////////////////////////////////////////////////////
@@ -151,7 +160,6 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
// response to each OnPointerEnter() call.
focus_->UnregisterCursorProvider(this);
focus_ = nullptr;
- cursor_ = ui::kCursorNull;
cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
}
// Second generate an enter event if focus moved to a new target.
@@ -162,6 +170,9 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
focus_ = target;
focus_->AddSurfaceObserver(this);
focus_->RegisterCursorProvider(this);
+
+ if (surface_)
reveman 2017/03/30 07:47:53 this is incorrect I think. the client needs to pro
Dominik Laskowski 2017/04/05 17:59:25 The client does not do that currently. Is that req
+ CaptureCursor(false);
}
delegate_->OnPointerFrame();
}
@@ -226,8 +237,6 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
NOTREACHED();
break;
}
-
- UpdateCursorScale();
}
void Pointer::OnScrollEvent(ui::ScrollEvent* event) {
@@ -238,8 +247,34 @@ void Pointer::OnScrollEvent(ui::ScrollEvent* event) {
// WMHelper::CursorObserver overrides:
void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) {
- if (focus_)
- UpdateCursorScale();
+ cursor_scale_ = GetCursorScale(cursor_set);
+ if (focus_ && surface_)
+ CaptureCursor(false);
+}
+
+void Pointer::OnCursorDisplayChanging(const display::Display& display) {
+ WMHelper* helper = WMHelper::GetInstance();
+ aura::Window* container = helper->GetContainer(
+ display.id(), ash::kShellWindowId_MouseCursorContainer);
+
+ // Reparent the cursor to the root window where the mouse is located.
+ if (container->GetRootWindow() != cursor_->GetRootWindow()) {
+ if (cursor_->parent())
+ cursor_->parent()->RemoveChild(cursor_.get());
+ container->AddChild(cursor_.get());
+ }
+
+ auto info = helper->GetDisplayInfo(display.id());
+ display_scale_ = info.GetEffectiveUIScale() * info.device_scale_factor();
+ device_scale_factor_ = display.device_scale_factor();
+
+ if (focus_ && surface_) {
+ // Capture is asynchronous, so avoid rendering old cursor in the meantime.
reveman 2017/03/30 07:47:53 I don't understand why we need to do all this. Thi
Dominik Laskowski 2017/04/05 17:59:25 This special case is needed when dragging across d
+ cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
+ UpdateCursor(ui::kCursorNone, true);
+ // Force the cursor to be updated even if locked.
+ CaptureCursor(true);
+ }
}
////////////////////////////////////////////////////////////////////////////////
@@ -251,7 +286,7 @@ void Pointer::OnSurfaceCommit() {
// Capture new cursor to reflect result of commit.
if (focus_)
- CaptureCursor();
+ CaptureCursor(false);
}
bool Pointer::IsSurfaceSynchronized() const {
@@ -283,72 +318,38 @@ 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(bool force) {
DCHECK(surface_);
DCHECK(focus_);
- // Set UI scale before submitting capture request.
- surface_->window()->layer()->SetTransform(
- gfx::GetScaleTransform(gfx::Point(), cursor_scale_));
+ float scale = cursor_scale_ * display_scale_;
+ float layer_scale = scale / device_scale_factor_;
- float primary_device_scale_factor =
- display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
+ gfx::Transform transform;
+ transform.Scale(layer_scale, layer_scale);
+ surface_->window()->SetTransform(transform);
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)));
+ gfx::ScaleToFlooredPoint(hotspot_, scale), force));
+
request->set_source(cursor_capture_source_id_);
- surface_->window()->layer()->RequestCopyOfOutput(std::move(request));
+ cursor_->layer()->RequestCopyOfOutput(std::move(request));
+
+ // Prevent subsequent requests in the same frame from aborting this capture.
reveman 2017/03/30 07:47:53 why is this needed?
Dominik Laskowski 2017/04/05 17:59:25 If the client happens to commit or call wl_pointer
+ if (force)
+ cursor_capture_source_id_ = base::UnguessableToken::Create();
}
-void Pointer::OnCursorCaptured(const gfx::Point& hotspot,
+void Pointer::OnCursorCaptured(gfx::Point hotspot,
+ bool force,
std::unique_ptr<cc::CopyOutputResult> result) {
if (!focus_)
return;
- cursor_ = ui::kCursorNone;
+ gfx::NativeCursor cursor = ui::kCursorNull;
if (!result->IsEmpty()) {
DCHECK(result->HasBitmap());
std::unique_ptr<SkBitmap> bitmap = result->TakeBitmap();
@@ -363,8 +364,8 @@ void Pointer::OnCursorCaptured(const gfx::Point& hotspot,
XcursorImage* image = ui::SkBitmapToXcursorImage(bitmap.get(), hotspot);
platform_cursor = ui::CreateReffedCustomXCursor(image);
#endif
- cursor_ = ui::kCursorCustom;
- cursor_.SetPlatformCursor(platform_cursor);
+ cursor = ui::kCursorCustom;
+ cursor.SetPlatformCursor(platform_cursor);
#if defined(USE_OZONE)
ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor);
#elif defined(USE_X11)
@@ -372,16 +373,21 @@ void Pointer::OnCursorCaptured(const gfx::Point& hotspot,
#endif
}
- UpdateCursor();
+ UpdateCursor(cursor, force);
}
-void Pointer::UpdateCursor() {
+void Pointer::UpdateCursor(gfx::NativeCursor cursor, bool force) {
DCHECK(focus_);
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(focus_->window()->GetRootWindow());
- if (cursor_client)
- cursor_client->SetCursor(cursor_);
+ if (!cursor_client)
+ return;
+
+ cursor_client->SetCursor(cursor);
+
+ if (force && cursor_client->IsCursorLocked())
reveman 2017/03/30 07:47:53 what's the situation where this is currently causi
Dominik Laskowski 2017/04/05 17:59:25 |force| being true implies that the cursor is lock
+ WMHelper::GetInstance()->SetCursor(cursor);
}
} // namespace exo

Powered by Google App Engine
This is Rietveld 408576698