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

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

Issue 2780623002: exo: Fix multi-display hardware cursor (Closed)
Patch Set: Fix style error 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
« no previous file with comments | « components/exo/pointer.h ('k') | components/exo/shell_surface.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // Scale at which cursor snapshot is captured. The resulting bitmap is scaled on
45 // displays whose DSF does not match this scale.
46 const float kCursorCaptureScale = 2.0f;
47
38 const double kLocatedEventEpsilonSquared = 1.0 / (2000.0 * 2000.0); 48 const double kLocatedEventEpsilonSquared = 1.0 / (2000.0 * 2000.0);
39 49
40 // Synthesized events typically lack floating point precision so to avoid 50 // Synthesized events typically lack floating point precision so to avoid
41 // generating mouse event jitter we consider the location of these events 51 // generating mouse event jitter we consider the location of these events
42 // to be the same as |location| if floored values match. 52 // to be the same as |location| if floored values match.
43 bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) { 53 bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) {
44 if (event->flags() & ui::EF_IS_SYNTHESIZED) 54 if (event->flags() & ui::EF_IS_SYNTHESIZED)
45 return event->location() == gfx::ToFlooredPoint(location); 55 return event->location() == gfx::ToFlooredPoint(location);
46 56
47 // In general, it is good practice to compare floats using an epsilon. 57 // 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); 116 surface_->RemoveSurfaceObserver(this);
107 } 117 }
108 surface_ = surface; 118 surface_ = surface;
109 if (surface_) { 119 if (surface_) {
110 surface_->SetSurfaceDelegate(this); 120 surface_->SetSurfaceDelegate(this);
111 surface_->AddSurfaceObserver(this); 121 surface_->AddSurfaceObserver(this);
112 // Note: Surface window needs to be added to the tree so we can take a 122 // 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 123 // snapshot. Where in the tree is not important but we might as well use
114 // the cursor container. 124 // the cursor container.
115 WMHelper::GetInstance() 125 WMHelper::GetInstance()
116 ->GetContainer(ash::kShellWindowId_MouseCursorContainer) 126 ->GetPrimaryDisplayContainer(ash::kShellWindowId_MouseCursorContainer)
117 ->AddChild(surface_->window()); 127 ->AddChild(surface_->window());
118 } 128 }
119 cursor_changed = true; 129 cursor_changed = true;
120 } 130 }
121 131
122 // Update hotspot. 132 if (hotspot != hotspot_)
123 if (hotspot != hotspot_) {
124 hotspot_ = hotspot;
125 cursor_changed = true; 133 cursor_changed = true;
126 }
127 134
128 // Early out if cursor did not change. 135 // Early out if cursor did not change.
129 if (!cursor_changed) 136 if (!cursor_changed)
130 return; 137 return;
131 138
132 // If |surface_| is set then asynchronously capture a snapshot of cursor, 139 // If |surface_| is set then asynchronously capture a snapshot of cursor,
133 // otherwise cancel pending capture and immediately set the cursor to "none". 140 // otherwise cancel pending capture and immediately set the cursor to "none".
134 if (surface_) { 141 if (surface_) {
135 CaptureCursor(); 142 CaptureCursor(hotspot);
136 } else { 143 } else {
144 cursor_bitmap_.reset();
137 cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs(); 145 cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
138 cursor_ = ui::CursorType::kNone;
139 UpdateCursor(); 146 UpdateCursor();
140 } 147 }
141 } 148 }
142 149
143 gfx::NativeCursor Pointer::GetCursor() { 150 gfx::NativeCursor Pointer::GetCursor() {
144 return cursor_; 151 return cursor_;
145 } 152 }
146 153
147 //////////////////////////////////////////////////////////////////////////////// 154 ////////////////////////////////////////////////////////////////////////////////
148 // ui::EventHandler overrides: 155 // ui::EventHandler overrides:
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 case ui::ET_MOUSE_ENTERED: 251 case ui::ET_MOUSE_ENTERED:
245 case ui::ET_MOUSE_EXITED: 252 case ui::ET_MOUSE_EXITED:
246 case ui::ET_MOUSE_CAPTURE_CHANGED: 253 case ui::ET_MOUSE_CAPTURE_CHANGED:
247 break; 254 break;
248 default: 255 default:
249 NOTREACHED(); 256 NOTREACHED();
250 break; 257 break;
251 } 258 }
252 259
253 last_event_type_ = event->type(); 260 last_event_type_ = event->type();
254 UpdateCursorScale();
255 } 261 }
256 262
257 void Pointer::OnScrollEvent(ui::ScrollEvent* event) { 263 void Pointer::OnScrollEvent(ui::ScrollEvent* event) {
258 OnMouseEvent(event); 264 OnMouseEvent(event);
259 } 265 }
260 266
261 //////////////////////////////////////////////////////////////////////////////// 267 ////////////////////////////////////////////////////////////////////////////////
262 // WMHelper::CursorObserver overrides: 268 // WMHelper::CursorObserver overrides:
263 269
264 void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) { 270 void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) {
265 if (focus_) 271 if (focus_)
266 UpdateCursorScale(); 272 UpdateCursor();
273 }
274
275 void Pointer::OnCursorDisplayChanged(const display::Display& display) {
276 if (focus_)
277 UpdateCursor();
267 } 278 }
268 279
269 //////////////////////////////////////////////////////////////////////////////// 280 ////////////////////////////////////////////////////////////////////////////////
270 // SurfaceDelegate overrides: 281 // SurfaceDelegate overrides:
271 282
272 void Pointer::OnSurfaceCommit() { 283 void Pointer::OnSurfaceCommit() {
273 surface_->CheckIfSurfaceHierarchyNeedsCommitToNewSurfaces(); 284 surface_->CheckIfSurfaceHierarchyNeedsCommitToNewSurfaces();
274 surface_->CommitSurfaceHierarchy(); 285 surface_->CommitSurfaceHierarchy();
275 286
276 // Capture new cursor to reflect result of commit. 287 // Capture new cursor to reflect result of commit.
277 if (focus_) 288 if (focus_)
278 CaptureCursor(); 289 CaptureCursor(hotspot_);
279 } 290 }
280 291
281 bool Pointer::IsSurfaceSynchronized() const { 292 bool Pointer::IsSurfaceSynchronized() const {
282 // A pointer surface is always desynchronized. 293 // A pointer surface is always desynchronized.
283 return false; 294 return false;
284 } 295 }
285 296
286 //////////////////////////////////////////////////////////////////////////////// 297 ////////////////////////////////////////////////////////////////////////////////
287 // SurfaceObserver overrides: 298 // SurfaceObserver overrides:
288 299
(...skipping 11 matching lines...) Expand all
300 311
301 Surface* Pointer::GetEffectiveTargetForEvent(ui::Event* event) const { 312 Surface* Pointer::GetEffectiveTargetForEvent(ui::Event* event) const {
302 Surface* target = 313 Surface* target =
303 Surface::AsSurface(static_cast<aura::Window*>(event->target())); 314 Surface::AsSurface(static_cast<aura::Window*>(event->target()));
304 if (!target) 315 if (!target)
305 return nullptr; 316 return nullptr;
306 317
307 return delegate_->CanAcceptPointerEventsForSurface(target) ? target : nullptr; 318 return delegate_->CanAcceptPointerEventsForSurface(target) ? target : nullptr;
308 } 319 }
309 320
310 void Pointer::UpdateCursorScale() { 321 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_); 322 DCHECK(surface_);
348 DCHECK(focus_); 323 DCHECK(focus_);
349 324
350 // Set UI scale before submitting capture request. 325 // Surface size is in DIPs, while layer size is in pseudo-DIP units that
351 surface_->window()->layer()->SetTransform( 326 // depend on the DSF of the display mode. Scale the layer to capture the
352 gfx::GetScaleTransform(gfx::Point(), cursor_scale_)); 327 // surface at a constant pixel size, regardless of the primary display's
353 328 // UI scale and display mode DSF.
354 float primary_device_scale_factor = 329 display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
355 display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); 330 auto* helper = WMHelper::GetInstance();
331 float scale = helper->GetDisplayInfo(display.id()).GetEffectiveUIScale() *
332 kCursorCaptureScale / display.device_scale_factor();
333 surface_->window()->SetTransform(gfx::GetScaleTransform(gfx::Point(), scale));
356 334
357 std::unique_ptr<cc::CopyOutputRequest> request = 335 std::unique_ptr<cc::CopyOutputRequest> request =
358 cc::CopyOutputRequest::CreateBitmapRequest( 336 cc::CopyOutputRequest::CreateBitmapRequest(
359 base::Bind(&Pointer::OnCursorCaptured, 337 base::Bind(&Pointer::OnCursorCaptured,
360 cursor_capture_weak_ptr_factory_.GetWeakPtr(), 338 cursor_capture_weak_ptr_factory_.GetWeakPtr(), hotspot));
361 gfx::ScaleToFlooredPoint( 339
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_); 340 request->set_source(cursor_capture_source_id_);
367 surface_->window()->layer()->RequestCopyOfOutput(std::move(request)); 341 surface_->window()->layer()->RequestCopyOfOutput(std::move(request));
368 } 342 }
369 343
370 void Pointer::OnCursorCaptured(const gfx::Point& hotspot, 344 void Pointer::OnCursorCaptured(const gfx::Point& hotspot,
371 std::unique_ptr<cc::CopyOutputResult> result) { 345 std::unique_ptr<cc::CopyOutputResult> result) {
372 if (!focus_) 346 if (!focus_)
373 return; 347 return;
374 348
375 cursor_ = ui::CursorType::kNone; 349 if (result->IsEmpty()) {
376 if (!result->IsEmpty()) { 350 cursor_bitmap_.reset();
351 } else {
377 DCHECK(result->HasBitmap()); 352 DCHECK(result->HasBitmap());
378 std::unique_ptr<SkBitmap> bitmap = result->TakeBitmap(); 353 cursor_bitmap_ = *result->TakeBitmap();
354 hotspot_ = hotspot;
355 }
356
357 UpdateCursor();
358 }
359
360 void Pointer::UpdateCursor() {
361 DCHECK(focus_);
362
363 if (cursor_bitmap_.drawsNothing()) {
364 cursor_ = ui::CursorType::kNone;
365 } else {
366 SkBitmap bitmap = cursor_bitmap_;
367 gfx::Point hotspot =
368 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(scale, display.rotation(),
379 &bitmap, &hotspot);
379 380
380 ui::PlatformCursor platform_cursor; 381 ui::PlatformCursor platform_cursor;
381 #if defined(USE_OZONE) 382 #if defined(USE_OZONE)
382 // TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers 383 // TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers
383 // and use that here instead of the current bitmap API. crbug.com/686600 384 // and use that here instead of the current bitmap API. crbug.com/686600
384 platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor( 385 platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor(
385 *bitmap.get(), hotspot, cursor_scale_); 386 bitmap, hotspot, 0);
386 #elif defined(USE_X11) 387 #elif defined(USE_X11)
387 XcursorImage* image = ui::SkBitmapToXcursorImage(bitmap.get(), hotspot); 388 XcursorImage* image = ui::SkBitmapToXcursorImage(&bitmap, hotspot);
388 platform_cursor = ui::CreateReffedCustomXCursor(image); 389 platform_cursor = ui::CreateReffedCustomXCursor(image);
389 #endif 390 #endif
390 cursor_ = ui::CursorType::kCustom; 391 cursor_ = ui::CursorType::kCustom;
391 cursor_.SetPlatformCursor(platform_cursor); 392 cursor_.SetPlatformCursor(platform_cursor);
392 #if defined(USE_OZONE) 393 #if defined(USE_OZONE)
393 ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor); 394 ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor);
394 #elif defined(USE_X11) 395 #elif defined(USE_X11)
395 ui::UnrefCustomXCursor(platform_cursor); 396 ui::UnrefCustomXCursor(platform_cursor);
396 #endif 397 #endif
397 } 398 }
398 399
399 UpdateCursor();
400 }
401
402 void Pointer::UpdateCursor() {
403 DCHECK(focus_);
404
405 aura::Window* root_window = focus_->window()->GetRootWindow(); 400 aura::Window* root_window = focus_->window()->GetRootWindow();
406 if (!root_window) 401 if (!root_window)
407 return; 402 return;
408 403
409 aura::client::CursorClient* cursor_client = 404 aura::client::CursorClient* cursor_client =
410 aura::client::GetCursorClient(root_window); 405 aura::client::GetCursorClient(root_window);
411 if (cursor_client) 406 if (cursor_client)
412 cursor_client->SetCursor(cursor_); 407 cursor_client->SetCursor(cursor_);
413 } 408 }
414 409
415 } // namespace exo 410 } // namespace exo
OLDNEW
« no previous file with comments | « components/exo/pointer.h ('k') | components/exo/shell_surface.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698