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

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

Issue 2780623002: exo: Fix multi-display hardware cursor (Closed)
Patch Set: Fix accessibility test Created 3 years, 6 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 <utility> 7 #include <utility>
8 8
9 #include "ash/public/cpp/shell_window_ids.h" 9 #include "ash/public/cpp/shell_window_ids.h"
10 #include "cc/output/copy_output_request.h" 10 #include "cc/output/copy_output_request.h"
11 #include "cc/output/copy_output_result.h" 11 #include "cc/output/copy_output_result.h"
12 #include "components/exo/pointer_delegate.h" 12 #include "components/exo/pointer_delegate.h"
13 #include "components/exo/pointer_stylus_delegate.h" 13 #include "components/exo/pointer_stylus_delegate.h"
14 #include "components/exo/surface.h" 14 #include "components/exo/surface.h"
15 #include "components/exo/wm_helper.h" 15 #include "components/exo/wm_helper.h"
16 #include "ui/aura/client/cursor_client.h" 16 #include "ui/aura/client/cursor_client.h"
17 #include "ui/aura/env.h" 17 #include "ui/aura/env.h"
18 #include "ui/aura/window.h" 18 #include "ui/aura/window.h"
19 #include "ui/base/cursor/cursor_util.h"
19 #include "ui/display/manager/display_manager.h" 20 #include "ui/display/manager/display_manager.h"
20 #include "ui/display/manager/managed_display_info.h" 21 #include "ui/display/manager/managed_display_info.h"
21 #include "ui/display/screen.h" 22 #include "ui/display/screen.h"
22 #include "ui/events/event.h" 23 #include "ui/events/event.h"
23 #include "ui/gfx/geometry/vector2d_conversions.h" 24 #include "ui/gfx/geometry/vector2d_conversions.h"
24 #include "ui/gfx/transform_util.h" 25 #include "ui/gfx/transform_util.h"
25 26
26 #if defined(USE_OZONE) 27 #if defined(USE_OZONE)
27 #include "ui/ozone/public/cursor_factory_ozone.h" 28 #include "ui/ozone/public/cursor_factory_ozone.h"
28 #endif 29 #endif
29 30
30 #if defined(USE_X11) 31 #if defined(USE_X11)
31 #include "ui/base/cursor/cursor_loader_x11.h" 32 #include "ui/base/cursor/cursor_loader_x11.h"
32 #endif 33 #endif
33 34
34 namespace exo { 35 namespace exo {
35 namespace { 36 namespace {
36 37
38 // TODO(oshima): Some accessibility features, including large cursors, disable
39 // hardware cursors. Ash does not support compositing for custom cursors, so it
40 // replaces them with the default cursor. As a result, this scale has no effect
41 // for now. See crbug.com/708378.
37 const float kLargeCursorScale = 2.8f; 42 const float kLargeCursorScale = 2.8f;
43
44 const float kCursorCaptureScale = 2.0f;
reveman 2017/05/31 03:33:10 nit: blank line below this and a short comment abo
Dominik Laskowski 2017/05/31 20:35:55 Done.
38 const double kLocatedEventEpsilonSquared = 1.0 / (2000.0 * 2000.0); 45 const double kLocatedEventEpsilonSquared = 1.0 / (2000.0 * 2000.0);
39 46
40 // Synthesized events typically lack floating point precision so to avoid 47 // Synthesized events typically lack floating point precision so to avoid
41 // generating mouse event jitter we consider the location of these events 48 // generating mouse event jitter we consider the location of these events
42 // to be the same as |location| if floored values match. 49 // to be the same as |location| if floored values match.
43 bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) { 50 bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) {
44 if (event->flags() & ui::EF_IS_SYNTHESIZED) 51 if (event->flags() & ui::EF_IS_SYNTHESIZED)
45 return event->location() == gfx::ToFlooredPoint(location); 52 return event->location() == gfx::ToFlooredPoint(location);
46 53
47 // In general, it is good practice to compare floats using an epsilon. 54 // In general, it is good practice to compare floats using an epsilon.
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 surface_->RemoveSurfaceObserver(this); 113 surface_->RemoveSurfaceObserver(this);
107 } 114 }
108 surface_ = surface; 115 surface_ = surface;
109 if (surface_) { 116 if (surface_) {
110 surface_->SetSurfaceDelegate(this); 117 surface_->SetSurfaceDelegate(this);
111 surface_->AddSurfaceObserver(this); 118 surface_->AddSurfaceObserver(this);
112 // Note: Surface window needs to be added to the tree so we can take a 119 // Note: Surface window needs to be added to the tree so we can take a
113 // snapshot. Where in the tree is not important but we might as well use 120 // snapshot. Where in the tree is not important but we might as well use
114 // the cursor container. 121 // the cursor container.
115 WMHelper::GetInstance() 122 WMHelper::GetInstance()
116 ->GetContainer(ash::kShellWindowId_MouseCursorContainer) 123 ->GetContainer(display::Screen::GetScreen()->GetPrimaryDisplay().id(),
124 ash::kShellWindowId_MouseCursorContainer)
117 ->AddChild(surface_->window()); 125 ->AddChild(surface_->window());
118 } 126 }
119 cursor_changed = true; 127 cursor_changed = true;
120 } 128 }
121 129
122 // Update hotspot. 130 if (hotspot != hotspot_)
123 if (hotspot != hotspot_) {
124 hotspot_ = hotspot;
125 cursor_changed = true; 131 cursor_changed = true;
126 }
127 132
128 // Early out if cursor did not change. 133 // Early out if cursor did not change.
129 if (!cursor_changed) 134 if (!cursor_changed)
130 return; 135 return;
131 136
132 // If |surface_| is set then asynchronously capture a snapshot of cursor, 137 // If |surface_| is set then asynchronously capture a snapshot of cursor,
133 // otherwise cancel pending capture and immediately set the cursor to "none". 138 // otherwise cancel pending capture and immediately set the cursor to "none".
134 if (surface_) { 139 if (surface_) {
135 CaptureCursor(); 140 CaptureCursor(hotspot);
136 } else { 141 } else {
142 cursor_bitmap_.reset();
137 cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs(); 143 cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
138 cursor_ = ui::CursorType::kNone; 144 cursor_ = ui::CursorType::kNone;
139 UpdateCursor(); 145 SetCursor();
140 } 146 }
141 } 147 }
142 148
143 gfx::NativeCursor Pointer::GetCursor() { 149 gfx::NativeCursor Pointer::GetCursor() {
144 return cursor_; 150 return cursor_;
145 } 151 }
146 152
147 //////////////////////////////////////////////////////////////////////////////// 153 ////////////////////////////////////////////////////////////////////////////////
148 // ui::EventHandler overrides: 154 // ui::EventHandler overrides:
149 155
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 case ui::ET_MOUSE_ENTERED: 250 case ui::ET_MOUSE_ENTERED:
245 case ui::ET_MOUSE_EXITED: 251 case ui::ET_MOUSE_EXITED:
246 case ui::ET_MOUSE_CAPTURE_CHANGED: 252 case ui::ET_MOUSE_CAPTURE_CHANGED:
247 break; 253 break;
248 default: 254 default:
249 NOTREACHED(); 255 NOTREACHED();
250 break; 256 break;
251 } 257 }
252 258
253 last_event_type_ = event->type(); 259 last_event_type_ = event->type();
254 UpdateCursorScale();
255 } 260 }
256 261
257 void Pointer::OnScrollEvent(ui::ScrollEvent* event) { 262 void Pointer::OnScrollEvent(ui::ScrollEvent* event) {
258 OnMouseEvent(event); 263 OnMouseEvent(event);
259 } 264 }
260 265
261 //////////////////////////////////////////////////////////////////////////////// 266 ////////////////////////////////////////////////////////////////////////////////
262 // WMHelper::CursorObserver overrides: 267 // WMHelper::CursorObserver overrides:
263 268
264 void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) { 269 void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) {
265 if (focus_) 270 if (focus_)
266 UpdateCursorScale(); 271 UpdateCursor();
272 }
273
274 void Pointer::OnCursorDisplayChanged(const display::Display& display) {
275 if (focus_)
276 UpdateCursor();
267 } 277 }
268 278
269 //////////////////////////////////////////////////////////////////////////////// 279 ////////////////////////////////////////////////////////////////////////////////
270 // SurfaceDelegate overrides: 280 // SurfaceDelegate overrides:
271 281
272 void Pointer::OnSurfaceCommit() { 282 void Pointer::OnSurfaceCommit() {
273 surface_->CheckIfSurfaceHierarchyNeedsCommitToNewSurfaces(); 283 surface_->CheckIfSurfaceHierarchyNeedsCommitToNewSurfaces();
274 surface_->CommitSurfaceHierarchy(); 284 surface_->CommitSurfaceHierarchy();
275 285
276 // Capture new cursor to reflect result of commit. 286 // Capture new cursor to reflect result of commit.
277 if (focus_) 287 if (focus_)
278 CaptureCursor(); 288 CaptureCursor(hotspot_);
279 } 289 }
280 290
281 bool Pointer::IsSurfaceSynchronized() const { 291 bool Pointer::IsSurfaceSynchronized() const {
282 // A pointer surface is always desynchronized. 292 // A pointer surface is always desynchronized.
283 return false; 293 return false;
284 } 294 }
285 295
286 //////////////////////////////////////////////////////////////////////////////// 296 ////////////////////////////////////////////////////////////////////////////////
287 // SurfaceObserver overrides: 297 // SurfaceObserver overrides:
288 298
(...skipping 11 matching lines...) Expand all
300 310
301 Surface* Pointer::GetEffectiveTargetForEvent(ui::Event* event) const { 311 Surface* Pointer::GetEffectiveTargetForEvent(ui::Event* event) const {
302 Surface* target = 312 Surface* target =
303 Surface::AsSurface(static_cast<aura::Window*>(event->target())); 313 Surface::AsSurface(static_cast<aura::Window*>(event->target()));
304 if (!target) 314 if (!target)
305 return nullptr; 315 return nullptr;
306 316
307 return delegate_->CanAcceptPointerEventsForSurface(target) ? target : nullptr; 317 return delegate_->CanAcceptPointerEventsForSurface(target) ? target : nullptr;
308 } 318 }
309 319
310 void Pointer::UpdateCursorScale() { 320 void Pointer::CaptureCursor(const gfx::Point& hotspot) {
311 DCHECK(focus_);
312
313 display::Screen* screen = display::Screen::GetScreen();
314 WMHelper* helper = WMHelper::GetInstance();
315
316 // Update cursor scale if the effective UI scale has changed.
317 display::Display display = screen->GetDisplayNearestWindow(focus_->window());
318 float scale = helper->GetDisplayInfo(display.id()).GetEffectiveUIScale();
319
320 if (display::Display::HasInternalDisplay()) {
321 float primary_device_scale_factor =
322 screen->GetPrimaryDisplay().device_scale_factor();
323 // The size of the cursor surface is the quotient of its physical size and
324 // the DSF of the primary display. The physical size is proportional to the
325 // DSF of the internal display. For external displays (and the internal
326 // display when secondary to a display with a different DSF), scale the
327 // cursor so its physical size matches with the single display case.
328 if (!display.IsInternal() ||
329 display.device_scale_factor() != primary_device_scale_factor) {
330 scale *= primary_device_scale_factor /
331 helper->GetDisplayInfo(display::Display::InternalDisplayId())
332 .device_scale_factor();
333 }
334 }
335
336 if (helper->GetCursorSet() == ui::CURSOR_SET_LARGE)
337 scale *= kLargeCursorScale;
338
339 if (scale != cursor_scale_) {
340 cursor_scale_ = scale;
341 if (surface_)
342 CaptureCursor();
343 }
344 }
345
346 void Pointer::CaptureCursor() {
347 DCHECK(surface_); 321 DCHECK(surface_);
348 DCHECK(focus_); 322 DCHECK(focus_);
349 323
350 // Set UI scale before submitting capture request. 324 // Surface size is in DIPs, while layer size is in pseudo-DIP units that
351 surface_->window()->layer()->SetTransform( 325 // depend on the DSF of the display mode. Scale the layer to capture the
352 gfx::GetScaleTransform(gfx::Point(), cursor_scale_)); 326 // surface at a constant pixel size, regardless of the primary display's
353 327 // UI scale and display mode DSF.
354 float primary_device_scale_factor = 328 display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
355 display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); 329 auto* helper = WMHelper::GetInstance();
330 float scale = helper->GetDisplayInfo(display.id()).GetEffectiveUIScale() *
331 kCursorCaptureScale / display.device_scale_factor();
332 surface_->window()->SetTransform(gfx::GetScaleTransform(gfx::Point(), scale));
356 333
357 std::unique_ptr<cc::CopyOutputRequest> request = 334 std::unique_ptr<cc::CopyOutputRequest> request =
358 cc::CopyOutputRequest::CreateBitmapRequest( 335 cc::CopyOutputRequest::CreateBitmapRequest(
359 base::Bind(&Pointer::OnCursorCaptured, 336 base::Bind(&Pointer::OnCursorCaptured,
360 cursor_capture_weak_ptr_factory_.GetWeakPtr(), 337 cursor_capture_weak_ptr_factory_.GetWeakPtr(), hotspot));
361 gfx::ScaleToFlooredPoint( 338
362 hotspot_,
363 // |hotspot_| is in surface coordinate space so apply
364 // both device scale and UI scale.
365 cursor_scale_ * primary_device_scale_factor)));
366 request->set_source(cursor_capture_source_id_); 339 request->set_source(cursor_capture_source_id_);
367 surface_->window()->layer()->RequestCopyOfOutput(std::move(request)); 340 surface_->window()->layer()->RequestCopyOfOutput(std::move(request));
368 } 341 }
369 342
370 void Pointer::OnCursorCaptured(const gfx::Point& hotspot, 343 void Pointer::OnCursorCaptured(const gfx::Point& hotspot,
371 std::unique_ptr<cc::CopyOutputResult> result) { 344 std::unique_ptr<cc::CopyOutputResult> result) {
372 if (!focus_) 345 if (!focus_)
373 return; 346 return;
374 347
375 cursor_ = ui::CursorType::kNone; 348 if (result->IsEmpty()) {
376 if (!result->IsEmpty()) { 349 cursor_bitmap_.reset();
377 DCHECK(result->HasBitmap()); 350 cursor_ = ui::CursorType::kNone;
378 std::unique_ptr<SkBitmap> bitmap = result->TakeBitmap(); 351 SetCursor();
379 352 return;
380 ui::PlatformCursor platform_cursor;
381 #if defined(USE_OZONE)
382 // TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers
383 // and use that here instead of the current bitmap API. crbug.com/686600
384 platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor(
385 *bitmap.get(), hotspot, cursor_scale_);
386 #elif defined(USE_X11)
387 XcursorImage* image = ui::SkBitmapToXcursorImage(bitmap.get(), hotspot);
388 platform_cursor = ui::CreateReffedCustomXCursor(image);
389 #endif
390 cursor_ = ui::CursorType::kCustom;
391 cursor_.SetPlatformCursor(platform_cursor);
392 #if defined(USE_OZONE)
393 ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor);
394 #elif defined(USE_X11)
395 ui::UnrefCustomXCursor(platform_cursor);
396 #endif
397 } 353 }
398 354
355 DCHECK(result->HasBitmap());
356 cursor_bitmap_ = *result->TakeBitmap();
357 hotspot_ = hotspot;
399 UpdateCursor(); 358 UpdateCursor();
400 } 359 }
401 360
402 void Pointer::UpdateCursor() { 361 void Pointer::UpdateCursor() {
403 DCHECK(focus_); 362 DCHECK(focus_);
404 363
364 if (cursor_bitmap_.drawsNothing())
reveman 2017/05/31 03:33:10 should this set the cursor to None?
Dominik Laskowski 2017/05/31 20:35:55 Done. I've also merged SetCursor into UpdateCursor
365 return;
366
367 SkBitmap bitmap = cursor_bitmap_;
368 gfx::Point hotspot = gfx::ScaleToFlooredPoint(hotspot_, kCursorCaptureScale);
369
370 auto* helper = WMHelper::GetInstance();
371 const display::Display& display = helper->GetCursorDisplay();
372 float scale = helper->GetDisplayInfo(display.id()).device_scale_factor() /
373 kCursorCaptureScale;
374
375 if (helper->GetCursorSet() == ui::CURSOR_SET_LARGE)
376 scale *= kLargeCursorScale;
377
378 ui::ScaleAndRotateCursorBitmapAndHotpoint(
379 scale, display.rotation(), &bitmap, &hotspot);
380
381 ui::PlatformCursor platform_cursor;
382 #if defined(USE_OZONE)
383 // TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers
384 // and use that here instead of the current bitmap API. crbug.com/686600
385 platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor(
386 bitmap, hotspot, 0);
387 #elif defined(USE_X11)
388 XcursorImage* image = ui::SkBitmapToXcursorImage(&bitmap, hotspot);
389 platform_cursor = ui::CreateReffedCustomXCursor(image);
390 #endif
391 cursor_ = ui::CursorType::kCustom;
392 cursor_.SetPlatformCursor(platform_cursor);
393 #if defined(USE_OZONE)
394 ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor);
395 #elif defined(USE_X11)
396 ui::UnrefCustomXCursor(platform_cursor);
397 #endif
398
399 SetCursor();
400 }
401
402 void Pointer::SetCursor() {
403 DCHECK(focus_);
404
405 aura::Window* root_window = focus_->window()->GetRootWindow(); 405 aura::Window* root_window = focus_->window()->GetRootWindow();
406 if (!root_window) 406 if (!root_window)
407 return; 407 return;
408 408
409 aura::client::CursorClient* cursor_client = 409 aura::client::CursorClient* cursor_client =
410 aura::client::GetCursorClient(root_window); 410 aura::client::GetCursorClient(root_window);
411 if (cursor_client) 411 if (cursor_client)
412 cursor_client->SetCursor(cursor_); 412 cursor_client->SetCursor(cursor_);
413 } 413 }
414 414
415 } // namespace exo 415 } // namespace exo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698