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

Side by Side Diff: components/exo/pointer.cc

Issue 2780623002: exo: Fix multi-display hardware cursor (Closed)
Patch Set: Remove capture on mouse enter Created 3 years, 8 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 unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/exo/pointer.h" 5 #include "components/exo/pointer.h"
6 6
7 #include "ash/public/cpp/shell_window_ids.h" 7 #include "ash/public/cpp/shell_window_ids.h"
8 #include "cc/output/copy_output_request.h" 8 #include "cc/output/copy_output_request.h"
9 #include "cc/output/copy_output_result.h" 9 #include "cc/output/copy_output_result.h"
10 #include "components/exo/pointer_delegate.h" 10 #include "components/exo/pointer_delegate.h"
11 #include "components/exo/pointer_stylus_delegate.h" 11 #include "components/exo/pointer_stylus_delegate.h"
12 #include "components/exo/surface.h" 12 #include "components/exo/surface.h"
13 #include "components/exo/wm_helper.h" 13 #include "components/exo/wm_helper.h"
14 #include "ui/aura/client/cursor_client.h" 14 #include "ui/aura/client/cursor_client.h"
15 #include "ui/aura/env.h" 15 #include "ui/aura/env.h"
16 #include "ui/aura/window.h" 16 #include "ui/aura/window.h"
17 #include "ui/display/manager/display_manager.h" 17 #include "ui/display/manager/display_manager.h"
18 #include "ui/display/manager/managed_display_info.h" 18 #include "ui/display/manager/managed_display_info.h"
19 #include "ui/display/screen.h" 19 #include "ui/display/screen.h"
20 #include "ui/events/event.h" 20 #include "ui/events/event.h"
21 #include "ui/gfx/geometry/vector2d_conversions.h" 21 #include "ui/gfx/geometry/vector2d_conversions.h"
22 #include "ui/gfx/transform_util.h" 22 #include "ui/gfx/transform.h"
23 23
24 #if defined(USE_OZONE) 24 #if defined(USE_OZONE)
25 #include "ui/ozone/public/cursor_factory_ozone.h" 25 #include "ui/ozone/public/cursor_factory_ozone.h"
26 #endif 26 #endif
27 27
28 #if defined(USE_X11) 28 #if defined(USE_X11)
29 #include "ui/base/cursor/cursor_loader_x11.h" 29 #include "ui/base/cursor/cursor_loader_x11.h"
30 #endif 30 #endif
31 31
32 namespace exo { 32 namespace exo {
33 namespace { 33 namespace {
34 34
35 const float kLargeCursorScale = 2.8f; 35 // TODO(oshima): Some accessibility features, including large cursors, disable
36 // hardware cursors. Ash does not support compositing for custom cursors, so it
37 // replaces them with the default cursor. As a result, this scale has no effect
38 // for now. See crbug.com/708378.
39 float GetCursorScale(ui::CursorSetType cursor_set) {
40 return cursor_set == ui::CURSOR_SET_LARGE ? 2.8f : 1.0f;
41 }
36 42
37 // Synthesized events typically lack floating point precision so to avoid 43 // Synthesized events typically lack floating point precision so to avoid
38 // generating mouse event jitter we consider the location of these events 44 // generating mouse event jitter we consider the location of these events
39 // to be the same as |location| if floored values match. 45 // to be the same as |location| if floored values match.
40 bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) { 46 bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) {
41 if (event->flags() & ui::EF_IS_SYNTHESIZED) 47 if (event->flags() & ui::EF_IS_SYNTHESIZED)
42 return event->location() == gfx::ToFlooredPoint(location); 48 return event->location() == gfx::ToFlooredPoint(location);
43 49
44 return event->location_f() == location; 50 return event->location_f() == location;
45 } 51 }
46 52
47 } // namespace 53 } // namespace
48 54
49 //////////////////////////////////////////////////////////////////////////////// 55 ////////////////////////////////////////////////////////////////////////////////
50 // Pointer, public: 56 // Pointer, public:
51 57
52 Pointer::Pointer(PointerDelegate* delegate) 58 Pointer::Pointer(PointerDelegate* delegate)
53 : delegate_(delegate), 59 : delegate_(delegate),
54 cursor_(ui::kCursorNull), 60 cursor_(new aura::Window(nullptr)),
55 cursor_capture_source_id_(base::UnguessableToken::Create()), 61 cursor_capture_source_id_(base::UnguessableToken::Create()),
56 cursor_capture_weak_ptr_factory_(this) { 62 cursor_capture_weak_ptr_factory_(this) {
57 auto* helper = WMHelper::GetInstance(); 63 auto* helper = WMHelper::GetInstance();
58 helper->AddPreTargetHandler(this); 64 helper->AddPreTargetHandler(this);
59 helper->AddCursorObserver(this); 65 helper->AddCursorObserver(this);
66
67 cursor_scale_ = GetCursorScale(helper->GetCursorSet());
68
69 cursor_->SetName("ExoCursor");
70 cursor_->Init(ui::LAYER_NOT_DRAWN);
71 cursor_->set_owned_by_parent(false);
72 OnCursorDisplayChanging(display::Screen::GetScreen()->GetPrimaryDisplay());
60 } 73 }
61 74
62 Pointer::~Pointer() { 75 Pointer::~Pointer() {
63 delegate_->OnPointerDestroying(this); 76 delegate_->OnPointerDestroying(this);
64 if (surface_) 77 if (surface_)
65 surface_->RemoveSurfaceObserver(this); 78 surface_->RemoveSurfaceObserver(this);
66 if (focus_) { 79 if (focus_) {
67 focus_->RemoveSurfaceObserver(this); 80 focus_->RemoveSurfaceObserver(this);
68 focus_->UnregisterCursorProvider(this); 81 focus_->UnregisterCursorProvider(this);
69 } 82 }
(...skipping 11 matching lines...) Expand all
81 bool cursor_changed = false; 94 bool cursor_changed = false;
82 95
83 // If surface is different than the current pointer surface then remove the 96 // If surface is different than the current pointer surface then remove the
84 // current surface and add the new surface. 97 // current surface and add the new surface.
85 if (surface != surface_) { 98 if (surface != surface_) {
86 if (surface && surface->HasSurfaceDelegate()) { 99 if (surface && surface->HasSurfaceDelegate()) {
87 DLOG(ERROR) << "Surface has already been assigned a role"; 100 DLOG(ERROR) << "Surface has already been assigned a role";
88 return; 101 return;
89 } 102 }
90 if (surface_) { 103 if (surface_) {
91 surface_->window()->SetTransform(gfx::Transform()); 104 cursor_->RemoveChild(surface_->window());
92 WMHelper::GetInstance()
93 ->GetContainer(ash::kShellWindowId_MouseCursorContainer)
94 ->RemoveChild(surface_->window());
95 surface_->SetSurfaceDelegate(nullptr); 105 surface_->SetSurfaceDelegate(nullptr);
96 surface_->RemoveSurfaceObserver(this); 106 surface_->RemoveSurfaceObserver(this);
97 } 107 }
98 surface_ = surface; 108 surface_ = surface;
99 if (surface_) { 109 if (surface_) {
100 surface_->SetSurfaceDelegate(this); 110 surface_->SetSurfaceDelegate(this);
101 surface_->AddSurfaceObserver(this); 111 surface_->AddSurfaceObserver(this);
102 // Note: Surface window needs to be added to the tree so we can take a 112 cursor_->AddChild(surface_->window());
103 // snapshot. Where in the tree is not important but we might as well use 113 surface_->window()->Show();
104 // the cursor container.
105 WMHelper::GetInstance()
106 ->GetContainer(ash::kShellWindowId_MouseCursorContainer)
107 ->AddChild(surface_->window());
108 } 114 }
109 cursor_changed = true; 115 cursor_changed = true;
110 } 116 }
111 117
112 // Update hotspot. 118 // Update hotspot.
113 if (hotspot != hotspot_) { 119 if (hotspot != hotspot_) {
114 hotspot_ = hotspot; 120 hotspot_ = hotspot;
115 cursor_changed = true; 121 cursor_changed = true;
116 } 122 }
117 123
118 // Early out if cursor did not change. 124 // Early out if cursor did not change.
119 if (!cursor_changed) 125 if (!cursor_changed)
120 return; 126 return;
121 127
122 // If |surface_| is set then asynchronously capture a snapshot of cursor, 128 // If |surface_| is set then asynchronously capture a snapshot of cursor,
123 // otherwise cancel pending capture and immediately set the cursor to "none". 129 // otherwise cancel pending capture and immediately set the cursor to "none".
124 if (surface_) { 130 if (surface_) {
125 CaptureCursor(); 131 CaptureCursor();
126 } else { 132 } else {
127 cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs(); 133 cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
128 cursor_ = ui::kCursorNone; 134 UpdateCursor(ui::kCursorNone);
129 UpdateCursor();
130 } 135 }
131 } 136 }
132 137
133 gfx::NativeCursor Pointer::GetCursor() { 138 gfx::NativeCursor Pointer::GetCursor() {
134 return cursor_; 139 if (focus_)
140 if (auto* root_window = focus_->window()->GetRootWindow())
141 if (auto* cursor_client = aura::client::GetCursorClient(root_window))
142 return cursor_client->GetCursor();
143
144 return ui::kCursorNull;
135 } 145 }
136 146
137 //////////////////////////////////////////////////////////////////////////////// 147 ////////////////////////////////////////////////////////////////////////////////
138 // ui::EventHandler overrides: 148 // ui::EventHandler overrides:
139 149
140 void Pointer::OnMouseEvent(ui::MouseEvent* event) { 150 void Pointer::OnMouseEvent(ui::MouseEvent* event) {
141 Surface* target = GetEffectiveTargetForEvent(event); 151 Surface* target = GetEffectiveTargetForEvent(event);
142 152
143 // If target is different than the current pointer focus then we need to 153 // If target is different than the current pointer focus then we need to
144 // generate enter and leave events. 154 // generate enter and leave events.
145 if (target != focus_) { 155 if (target != focus_) {
146 // First generate a leave event if we currently have a target in focus. 156 // First generate a leave event if we currently have a target in focus.
147 if (focus_) { 157 if (focus_) {
148 delegate_->OnPointerLeave(focus_); 158 delegate_->OnPointerLeave(focus_);
149 focus_->RemoveSurfaceObserver(this); 159 focus_->RemoveSurfaceObserver(this);
150 // Require SetCursor() to be called and cursor to be re-defined in 160 // Require SetCursor() to be called and cursor to be re-defined in
151 // response to each OnPointerEnter() call. 161 // response to each OnPointerEnter() call.
152 focus_->UnregisterCursorProvider(this); 162 focus_->UnregisterCursorProvider(this);
153 focus_ = nullptr; 163 focus_ = nullptr;
154 cursor_ = ui::kCursorNull;
155 cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs(); 164 cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
156 } 165 }
157 // Second generate an enter event if focus moved to a new target. 166 // Second generate an enter event if focus moved to a new target.
158 if (target) { 167 if (target) {
159 delegate_->OnPointerEnter(target, event->location_f(), 168 delegate_->OnPointerEnter(target, event->location_f(),
160 event->button_flags()); 169 event->button_flags());
161 location_ = event->location_f(); 170 location_ = event->location_f();
162 focus_ = target; 171 focus_ = target;
163 focus_->AddSurfaceObserver(this); 172 focus_->AddSurfaceObserver(this);
164 focus_->RegisterCursorProvider(this); 173 focus_->RegisterCursorProvider(this);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 case ui::ET_MOUSE_MOVED: 228 case ui::ET_MOUSE_MOVED:
220 case ui::ET_MOUSE_DRAGGED: 229 case ui::ET_MOUSE_DRAGGED:
221 case ui::ET_MOUSE_ENTERED: 230 case ui::ET_MOUSE_ENTERED:
222 case ui::ET_MOUSE_EXITED: 231 case ui::ET_MOUSE_EXITED:
223 case ui::ET_MOUSE_CAPTURE_CHANGED: 232 case ui::ET_MOUSE_CAPTURE_CHANGED:
224 break; 233 break;
225 default: 234 default:
226 NOTREACHED(); 235 NOTREACHED();
227 break; 236 break;
228 } 237 }
229
230 UpdateCursorScale();
231 } 238 }
232 239
233 void Pointer::OnScrollEvent(ui::ScrollEvent* event) { 240 void Pointer::OnScrollEvent(ui::ScrollEvent* event) {
234 OnMouseEvent(event); 241 OnMouseEvent(event);
235 } 242 }
236 243
237 //////////////////////////////////////////////////////////////////////////////// 244 ////////////////////////////////////////////////////////////////////////////////
238 // WMHelper::CursorObserver overrides: 245 // WMHelper::CursorObserver overrides:
239 246
240 void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) { 247 void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) {
241 if (focus_) 248 cursor_scale_ = GetCursorScale(cursor_set);
242 UpdateCursorScale(); 249 if (focus_ && surface_)
250 CaptureCursor();
251 }
252
253 void Pointer::OnCursorDisplayChanging(const display::Display& display) {
254 WMHelper* helper = WMHelper::GetInstance();
255 aura::Window* container = helper->GetContainer(
256 display.id(), ash::kShellWindowId_MouseCursorContainer);
257
258 // Reparent the cursor to the root window where the mouse is located.
reveman 2017/04/10 21:47:13 is this re-parenting really needed?
Dominik Laskowski 2017/04/11 04:42:55 Yes. Layer size is in DIPs, which depends on the D
reveman 2017/04/11 19:25:13 Ok. Can we parent the cursor surface at the first
Dominik Laskowski 2017/04/11 20:40:37 That would break client-side dragging, i.e. we wou
reveman 2017/04/11 22:25:34 Why would it break client side dragging? The compo
259 if (container->GetRootWindow() != cursor_->GetRootWindow()) {
260 if (cursor_->parent())
261 cursor_->parent()->RemoveChild(cursor_.get());
262 container->AddChild(cursor_.get());
263 }
264
265 auto info = helper->GetDisplayInfo(display.id());
266 display_scale_ = info.GetEffectiveUIScale() * info.device_scale_factor();
267 device_scale_factor_ = display.device_scale_factor();
243 } 268 }
244 269
245 //////////////////////////////////////////////////////////////////////////////// 270 ////////////////////////////////////////////////////////////////////////////////
246 // SurfaceDelegate overrides: 271 // SurfaceDelegate overrides:
247 272
248 void Pointer::OnSurfaceCommit() { 273 void Pointer::OnSurfaceCommit() {
249 surface_->CheckIfSurfaceHierarchyNeedsCommitToNewSurfaces(); 274 surface_->CheckIfSurfaceHierarchyNeedsCommitToNewSurfaces();
250 surface_->CommitSurfaceHierarchy(); 275 surface_->CommitSurfaceHierarchy();
251 276
252 // Capture new cursor to reflect result of commit. 277 // Capture new cursor to reflect result of commit.
(...skipping 23 matching lines...) Expand all
276 301
277 Surface* Pointer::GetEffectiveTargetForEvent(ui::Event* event) const { 302 Surface* Pointer::GetEffectiveTargetForEvent(ui::Event* event) const {
278 Surface* target = 303 Surface* target =
279 Surface::AsSurface(static_cast<aura::Window*>(event->target())); 304 Surface::AsSurface(static_cast<aura::Window*>(event->target()));
280 if (!target) 305 if (!target)
281 return nullptr; 306 return nullptr;
282 307
283 return delegate_->CanAcceptPointerEventsForSurface(target) ? target : nullptr; 308 return delegate_->CanAcceptPointerEventsForSurface(target) ? target : nullptr;
284 } 309 }
285 310
286 void Pointer::UpdateCursorScale() {
287 DCHECK(focus_);
288
289 display::Screen* screen = display::Screen::GetScreen();
290 WMHelper* helper = WMHelper::GetInstance();
291
292 // Update cursor scale if the effective UI scale has changed.
293 display::Display display = screen->GetDisplayNearestWindow(focus_->window());
294 float scale = helper->GetDisplayInfo(display.id()).GetEffectiveUIScale();
295
296 if (display::Display::HasInternalDisplay()) {
297 float primary_device_scale_factor =
298 screen->GetPrimaryDisplay().device_scale_factor();
299 // The size of the cursor surface is the quotient of its physical size and
300 // the DSF of the primary display. The physical size is proportional to the
301 // DSF of the internal display. For external displays (and the internal
302 // display when secondary to a display with a different DSF), scale the
303 // cursor so its physical size matches with the single display case.
304 if (!display.IsInternal() ||
305 display.device_scale_factor() != primary_device_scale_factor) {
306 scale *= primary_device_scale_factor /
307 helper->GetDisplayInfo(display::Display::InternalDisplayId())
308 .device_scale_factor();
309 }
310 }
311
312 if (helper->GetCursorSet() == ui::CURSOR_SET_LARGE)
313 scale *= kLargeCursorScale;
314
315 if (scale != cursor_scale_) {
316 cursor_scale_ = scale;
317 if (surface_)
318 CaptureCursor();
319 }
320 }
321
322 void Pointer::CaptureCursor() { 311 void Pointer::CaptureCursor() {
323 DCHECK(surface_); 312 DCHECK(surface_);
324 DCHECK(focus_); 313 DCHECK(focus_);
325 314
326 // Set UI scale before submitting capture request. 315 float scale = cursor_scale_ * display_scale_;
327 surface_->window()->layer()->SetTransform( 316 float layer_scale = scale / device_scale_factor_;
328 gfx::GetScaleTransform(gfx::Point(), cursor_scale_));
329 317
330 float primary_device_scale_factor = 318 gfx::Transform transform;
331 display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); 319 transform.Scale(layer_scale, layer_scale);
320 surface_->window()->SetTransform(transform);
332 321
333 std::unique_ptr<cc::CopyOutputRequest> request = 322 std::unique_ptr<cc::CopyOutputRequest> request =
334 cc::CopyOutputRequest::CreateBitmapRequest( 323 cc::CopyOutputRequest::CreateBitmapRequest(
335 base::Bind(&Pointer::OnCursorCaptured, 324 base::Bind(&Pointer::OnCursorCaptured,
336 cursor_capture_weak_ptr_factory_.GetWeakPtr(), 325 cursor_capture_weak_ptr_factory_.GetWeakPtr(),
337 gfx::ScaleToFlooredPoint( 326 gfx::ScaleToFlooredPoint(hotspot_, scale)));
338 hotspot_, 327
339 // |hotspot_| is in surface coordinate space so apply
340 // both device scale and UI scale.
341 cursor_scale_ * primary_device_scale_factor)));
342 request->set_source(cursor_capture_source_id_); 328 request->set_source(cursor_capture_source_id_);
343 surface_->window()->layer()->RequestCopyOfOutput(std::move(request)); 329 cursor_->layer()->RequestCopyOfOutput(std::move(request));
344 } 330 }
345 331
346 void Pointer::OnCursorCaptured(const gfx::Point& hotspot, 332 void Pointer::OnCursorCaptured(const gfx::Point& hotspot,
347 std::unique_ptr<cc::CopyOutputResult> result) { 333 std::unique_ptr<cc::CopyOutputResult> result) {
348 if (!focus_) 334 if (!focus_)
349 return; 335 return;
350 336
351 cursor_ = ui::kCursorNone; 337 gfx::NativeCursor cursor = ui::kCursorNull;
352 if (!result->IsEmpty()) { 338 if (!result->IsEmpty()) {
353 DCHECK(result->HasBitmap()); 339 DCHECK(result->HasBitmap());
354 std::unique_ptr<SkBitmap> bitmap = result->TakeBitmap(); 340 std::unique_ptr<SkBitmap> bitmap = result->TakeBitmap();
355 341
356 ui::PlatformCursor platform_cursor; 342 ui::PlatformCursor platform_cursor;
357 #if defined(USE_OZONE) 343 #if defined(USE_OZONE)
358 // TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers 344 // TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers
359 // and use that here instead of the current bitmap API. crbug.com/686600 345 // and use that here instead of the current bitmap API. crbug.com/686600
360 platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor( 346 platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor(
361 *bitmap.get(), hotspot); 347 *bitmap.get(), hotspot);
362 #elif defined(USE_X11) 348 #elif defined(USE_X11)
363 XcursorImage* image = ui::SkBitmapToXcursorImage(bitmap.get(), hotspot); 349 XcursorImage* image = ui::SkBitmapToXcursorImage(bitmap.get(), hotspot);
364 platform_cursor = ui::CreateReffedCustomXCursor(image); 350 platform_cursor = ui::CreateReffedCustomXCursor(image);
365 #endif 351 #endif
366 cursor_ = ui::kCursorCustom; 352 cursor = ui::kCursorCustom;
367 cursor_.SetPlatformCursor(platform_cursor); 353 cursor.SetPlatformCursor(platform_cursor);
368 #if defined(USE_OZONE) 354 #if defined(USE_OZONE)
369 ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor); 355 ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor);
370 #elif defined(USE_X11) 356 #elif defined(USE_X11)
371 ui::UnrefCustomXCursor(platform_cursor); 357 ui::UnrefCustomXCursor(platform_cursor);
372 #endif 358 #endif
373 } 359 }
374 360
375 UpdateCursor(); 361 UpdateCursor(cursor);
376 } 362 }
377 363
378 void Pointer::UpdateCursor() { 364 void Pointer::UpdateCursor(gfx::NativeCursor cursor) {
379 DCHECK(focus_); 365 DCHECK(focus_);
380 366
381 aura::Window* root_window = focus_->window()->GetRootWindow(); 367 aura::Window* root_window = focus_->window()->GetRootWindow();
382 if (!root_window) 368 if (!root_window)
383 return; 369 return;
384 370
385 aura::client::CursorClient* cursor_client = 371 aura::client::CursorClient* cursor_client =
386 aura::client::GetCursorClient(root_window); 372 aura::client::GetCursorClient(root_window);
387 if (cursor_client) 373 if (cursor_client)
388 cursor_client->SetCursor(cursor_); 374 cursor_client->SetCursor(cursor);
389 } 375 }
390 376
391 } // namespace exo 377 } // namespace exo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698