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

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, 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 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 <algorithm>
8
7 #include "ash/public/cpp/shell_window_ids.h" 9 #include "ash/public/cpp/shell_window_ids.h"
8 #include "cc/output/copy_output_request.h" 10 #include "cc/output/copy_output_request.h"
9 #include "cc/output/copy_output_result.h" 11 #include "cc/output/copy_output_result.h"
10 #include "components/exo/pointer_delegate.h" 12 #include "components/exo/pointer_delegate.h"
11 #include "components/exo/pointer_stylus_delegate.h" 13 #include "components/exo/pointer_stylus_delegate.h"
12 #include "components/exo/surface.h" 14 #include "components/exo/surface.h"
13 #include "components/exo/wm_helper.h" 15 #include "components/exo/wm_helper.h"
14 #include "ui/aura/client/cursor_client.h" 16 #include "ui/aura/client/cursor_client.h"
15 #include "ui/aura/env.h" 17 #include "ui/aura/env.h"
16 #include "ui/aura/window.h" 18 #include "ui/aura/window.h"
19 #include "ui/base/cursor/cursor_util.h"
17 #include "ui/display/manager/display_manager.h" 20 #include "ui/display/manager/display_manager.h"
18 #include "ui/display/manager/managed_display_info.h" 21 #include "ui/display/manager/managed_display_info.h"
19 #include "ui/display/screen.h" 22 #include "ui/display/screen.h"
20 #include "ui/events/event.h" 23 #include "ui/events/event.h"
21 #include "ui/gfx/geometry/vector2d_conversions.h" 24 #include "ui/gfx/geometry/vector2d_conversions.h"
22 #include "ui/gfx/transform_util.h" 25 #include "ui/gfx/transform_util.h"
23 26
24 #if defined(USE_OZONE) 27 #if defined(USE_OZONE)
25 #include "ui/ozone/public/cursor_factory_ozone.h" 28 #include "ui/ozone/public/cursor_factory_ozone.h"
26 #endif 29 #endif
27 30
28 #if defined(USE_X11) 31 #if defined(USE_X11)
29 #include "ui/base/cursor/cursor_loader_x11.h" 32 #include "ui/base/cursor/cursor_loader_x11.h"
30 #endif 33 #endif
31 34
32 namespace exo { 35 namespace exo {
33 namespace { 36 namespace {
34 37
35 const float kLargeCursorScale = 2.8f; 38 // TODO(oshima): Some accessibility features, including large cursors, disable
reveman 2017/05/23 17:06:57 please minimize the patch and avoid this change th
Dominik Laskowski 2017/05/24 00:43:04 It's needed due to the new logic for updating scal
reveman 2017/05/25 10:52:55 I'm failing to see why. Please explain.
Dominik Laskowski 2017/05/31 02:06:26 Folded into UpdateCursor.
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.
42 float GetCursorScale(ui::CursorSetType cursor_set) {
43 return cursor_set == ui::CURSOR_SET_LARGE ? 2.8f : 1.0f;
44 }
36 45
37 // Synthesized events typically lack floating point precision so to avoid 46 // Synthesized events typically lack floating point precision so to avoid
38 // generating mouse event jitter we consider the location of these events 47 // generating mouse event jitter we consider the location of these events
39 // to be the same as |location| if floored values match. 48 // to be the same as |location| if floored values match.
40 bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) { 49 bool SameLocation(const ui::LocatedEvent* event, const gfx::PointF& location) {
41 if (event->flags() & ui::EF_IS_SYNTHESIZED) 50 if (event->flags() & ui::EF_IS_SYNTHESIZED)
42 return event->location() == gfx::ToFlooredPoint(location); 51 return event->location() == gfx::ToFlooredPoint(location);
43 52
44 return event->location_f() == location; 53 return event->location_f() == location;
45 } 54 }
46 55
56 inline const display::ManagedDisplayInfo& GetDisplayInfo(
57 const display::Display& display) {
58 return WMHelper::GetInstance()->GetDisplayInfo(display.id());
59 }
60
61 display::Display GetCaptureDisplay() {
reveman 2017/05/23 17:06:57 What if no DSF 2.0 display exists but is later add
Dominik Laskowski 2017/05/24 00:43:04 Good point. Capturing at constant pixel size is si
62 const auto& displays = display::Screen::GetScreen()->GetAllDisplays();
63 DCHECK(!displays.empty());
64 return *std::max_element(
65 displays.begin(), displays.end(),
66 [](const display::Display& lhs, const display::Display& rhs) -> bool {
67 return GetDisplayInfo(lhs).device_scale_factor() <
68 GetDisplayInfo(rhs).device_scale_factor();
69 });
70 }
71
47 } // namespace 72 } // namespace
48 73
49 //////////////////////////////////////////////////////////////////////////////// 74 ////////////////////////////////////////////////////////////////////////////////
50 // Pointer, public: 75 // Pointer, public:
51 76
52 Pointer::Pointer(PointerDelegate* delegate) 77 Pointer::Pointer(PointerDelegate* delegate)
53 : delegate_(delegate), 78 : delegate_(delegate),
54 cursor_(ui::CursorType::kNull),
55 cursor_capture_source_id_(base::UnguessableToken::Create()), 79 cursor_capture_source_id_(base::UnguessableToken::Create()),
56 cursor_capture_weak_ptr_factory_(this) { 80 cursor_capture_weak_ptr_factory_(this) {
57 auto* helper = WMHelper::GetInstance(); 81 auto* helper = WMHelper::GetInstance();
58 helper->AddPreTargetHandler(this); 82 helper->AddPreTargetHandler(this);
59 helper->AddCursorObserver(this); 83 helper->AddCursorObserver(this);
84
reveman 2017/05/23 17:06:57 why are the following 4 lines needed?
Dominik Laskowski 2017/05/24 00:43:04 To initialize the state updated by OnCursorSetChan
85 cursor_scale_ = GetCursorScale(helper->GetCursorSet());
86
87 OnCursorDisplayChanging(display::Screen::GetScreen()->GetPrimaryDisplay());
60 } 88 }
61 89
62 Pointer::~Pointer() { 90 Pointer::~Pointer() {
63 delegate_->OnPointerDestroying(this); 91 delegate_->OnPointerDestroying(this);
64 if (surface_) 92 if (surface_)
65 surface_->RemoveSurfaceObserver(this); 93 surface_->RemoveSurfaceObserver(this);
66 if (focus_) { 94 if (focus_) {
67 focus_->RemoveSurfaceObserver(this); 95 focus_->RemoveSurfaceObserver(this);
68 focus_->UnregisterCursorProvider(this); 96 focus_->UnregisterCursorProvider(this);
69 } 97 }
(...skipping 25 matching lines...) Expand all
95 surface_->RemoveSurfaceObserver(this); 123 surface_->RemoveSurfaceObserver(this);
96 } 124 }
97 surface_ = surface; 125 surface_ = surface;
98 if (surface_) { 126 if (surface_) {
99 surface_->SetSurfaceDelegate(this); 127 surface_->SetSurfaceDelegate(this);
100 surface_->AddSurfaceObserver(this); 128 surface_->AddSurfaceObserver(this);
101 // Note: Surface window needs to be added to the tree so we can take a 129 // Note: Surface window needs to be added to the tree so we can take a
102 // snapshot. Where in the tree is not important but we might as well use 130 // snapshot. Where in the tree is not important but we might as well use
103 // the cursor container. 131 // the cursor container.
104 WMHelper::GetInstance() 132 WMHelper::GetInstance()
105 ->GetContainer(ash::kShellWindowId_MouseCursorContainer) 133 ->GetContainer(GetCaptureDisplay().id(),
134 ash::kShellWindowId_MouseCursorContainer)
106 ->AddChild(surface_->window()); 135 ->AddChild(surface_->window());
107 } 136 }
108 cursor_changed = true; 137 cursor_changed = true;
109 } 138 }
110 139
111 // Update hotspot. 140 // Update hotspot.
112 if (hotspot != hotspot_) { 141 if (hotspot != hotspot_) {
113 hotspot_ = hotspot; 142 hotspot_ = hotspot;
114 cursor_changed = true; 143 cursor_changed = true;
115 } 144 }
116 145
117 // Early out if cursor did not change. 146 // Early out if cursor did not change.
118 if (!cursor_changed) 147 if (!cursor_changed)
119 return; 148 return;
120 149
121 // If |surface_| is set then asynchronously capture a snapshot of cursor, 150 // If |surface_| is set then asynchronously capture a snapshot of cursor,
122 // otherwise cancel pending capture and immediately set the cursor to "none". 151 // otherwise cancel pending capture and immediately set the cursor to "none".
123 if (surface_) { 152 if (surface_) {
124 CaptureCursor(); 153 CaptureCursor();
125 } else { 154 } else {
155 cursor_.reset();
126 cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs(); 156 cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
127 cursor_ = ui::CursorType::kNone; 157 SetCursor(ui::CursorType::kNone);
128 UpdateCursor();
129 } 158 }
130 } 159 }
131 160
132 gfx::NativeCursor Pointer::GetCursor() { 161 gfx::NativeCursor Pointer::GetCursor() {
133 return cursor_; 162 if (focus_)
163 if (auto* root_window = focus_->window()->GetRootWindow())
164 if (auto* cursor_client = aura::client::GetCursorClient(root_window))
165 return cursor_client->GetCursor();
166
167 return ui::CursorType::kNull;
134 } 168 }
135 169
136 //////////////////////////////////////////////////////////////////////////////// 170 ////////////////////////////////////////////////////////////////////////////////
137 // ui::EventHandler overrides: 171 // ui::EventHandler overrides:
138 172
139 void Pointer::OnMouseEvent(ui::MouseEvent* event) { 173 void Pointer::OnMouseEvent(ui::MouseEvent* event) {
140 Surface* target = GetEffectiveTargetForEvent(event); 174 Surface* target = GetEffectiveTargetForEvent(event);
141 175
142 // If target is different than the current pointer focus then we need to 176 // If target is different than the current pointer focus then we need to
143 // generate enter and leave events. 177 // generate enter and leave events.
144 if (target != focus_) { 178 if (target != focus_) {
145 // First generate a leave event if we currently have a target in focus. 179 // First generate a leave event if we currently have a target in focus.
146 if (focus_) { 180 if (focus_) {
147 delegate_->OnPointerLeave(focus_); 181 delegate_->OnPointerLeave(focus_);
148 focus_->RemoveSurfaceObserver(this); 182 focus_->RemoveSurfaceObserver(this);
149 // Require SetCursor() to be called and cursor to be re-defined in 183 // Require SetCursor() to be called and cursor to be re-defined in
150 // response to each OnPointerEnter() call. 184 // response to each OnPointerEnter() call.
151 focus_->UnregisterCursorProvider(this); 185 focus_->UnregisterCursorProvider(this);
152 focus_ = nullptr; 186 focus_ = nullptr;
153 cursor_ = ui::CursorType::kNull;
154 cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs(); 187 cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
155 } 188 }
156 // Second generate an enter event if focus moved to a new target. 189 // Second generate an enter event if focus moved to a new target.
157 if (target) { 190 if (target) {
158 delegate_->OnPointerEnter(target, event->location_f(), 191 delegate_->OnPointerEnter(target, event->location_f(),
159 event->button_flags()); 192 event->button_flags());
160 location_ = event->location_f(); 193 location_ = event->location_f();
161 focus_ = target; 194 focus_ = target;
162 focus_->AddSurfaceObserver(this); 195 focus_->AddSurfaceObserver(this);
163 focus_->RegisterCursorProvider(this); 196 focus_->RegisterCursorProvider(this);
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 case ui::ET_MOUSE_ENTERED: 266 case ui::ET_MOUSE_ENTERED:
234 case ui::ET_MOUSE_EXITED: 267 case ui::ET_MOUSE_EXITED:
235 case ui::ET_MOUSE_CAPTURE_CHANGED: 268 case ui::ET_MOUSE_CAPTURE_CHANGED:
236 break; 269 break;
237 default: 270 default:
238 NOTREACHED(); 271 NOTREACHED();
239 break; 272 break;
240 } 273 }
241 274
242 last_event_type_ = event->type(); 275 last_event_type_ = event->type();
243 UpdateCursorScale();
244 } 276 }
245 277
246 void Pointer::OnScrollEvent(ui::ScrollEvent* event) { 278 void Pointer::OnScrollEvent(ui::ScrollEvent* event) {
247 OnMouseEvent(event); 279 OnMouseEvent(event);
248 } 280 }
249 281
250 //////////////////////////////////////////////////////////////////////////////// 282 ////////////////////////////////////////////////////////////////////////////////
251 // WMHelper::CursorObserver overrides: 283 // WMHelper::CursorObserver overrides:
252 284
253 void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) { 285 void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) {
286 cursor_scale_ = GetCursorScale(cursor_set);
254 if (focus_) 287 if (focus_)
255 UpdateCursorScale(); 288 UpdateCursor();
289 }
290
291 void Pointer::OnCursorDisplayChanging(const display::Display& display) {
292 device_scale_factor_ = GetDisplayInfo(display).device_scale_factor();
293 rotation_ = display.rotation();
256 } 294 }
257 295
258 //////////////////////////////////////////////////////////////////////////////// 296 ////////////////////////////////////////////////////////////////////////////////
259 // SurfaceDelegate overrides: 297 // SurfaceDelegate overrides:
260 298
261 void Pointer::OnSurfaceCommit() { 299 void Pointer::OnSurfaceCommit() {
262 surface_->CheckIfSurfaceHierarchyNeedsCommitToNewSurfaces(); 300 surface_->CheckIfSurfaceHierarchyNeedsCommitToNewSurfaces();
263 surface_->CommitSurfaceHierarchy(); 301 surface_->CommitSurfaceHierarchy();
264 302
265 // Capture new cursor to reflect result of commit. 303 // Capture new cursor to reflect result of commit.
(...skipping 23 matching lines...) Expand all
289 327
290 Surface* Pointer::GetEffectiveTargetForEvent(ui::Event* event) const { 328 Surface* Pointer::GetEffectiveTargetForEvent(ui::Event* event) const {
291 Surface* target = 329 Surface* target =
292 Surface::AsSurface(static_cast<aura::Window*>(event->target())); 330 Surface::AsSurface(static_cast<aura::Window*>(event->target()));
293 if (!target) 331 if (!target)
294 return nullptr; 332 return nullptr;
295 333
296 return delegate_->CanAcceptPointerEventsForSurface(target) ? target : nullptr; 334 return delegate_->CanAcceptPointerEventsForSurface(target) ? target : nullptr;
297 } 335 }
298 336
299 void Pointer::UpdateCursorScale() {
300 DCHECK(focus_);
301
302 display::Screen* screen = display::Screen::GetScreen();
303 WMHelper* helper = WMHelper::GetInstance();
304
305 // Update cursor scale if the effective UI scale has changed.
306 display::Display display = screen->GetDisplayNearestWindow(focus_->window());
307 float scale = helper->GetDisplayInfo(display.id()).GetEffectiveUIScale();
308
309 if (display::Display::HasInternalDisplay()) {
310 float primary_device_scale_factor =
311 screen->GetPrimaryDisplay().device_scale_factor();
312 // The size of the cursor surface is the quotient of its physical size and
313 // the DSF of the primary display. The physical size is proportional to the
314 // DSF of the internal display. For external displays (and the internal
315 // display when secondary to a display with a different DSF), scale the
316 // cursor so its physical size matches with the single display case.
317 if (!display.IsInternal() ||
318 display.device_scale_factor() != primary_device_scale_factor) {
319 scale *= primary_device_scale_factor /
320 helper->GetDisplayInfo(display::Display::InternalDisplayId())
321 .device_scale_factor();
322 }
323 }
324
325 if (helper->GetCursorSet() == ui::CURSOR_SET_LARGE)
326 scale *= kLargeCursorScale;
327
328 if (scale != cursor_scale_) {
329 cursor_scale_ = scale;
330 if (surface_)
331 CaptureCursor();
332 }
333 }
334
335 void Pointer::CaptureCursor() { 337 void Pointer::CaptureCursor() {
336 DCHECK(surface_); 338 DCHECK(surface_);
337 DCHECK(focus_); 339 DCHECK(focus_);
338 340
339 // Set UI scale before submitting capture request. 341 // Surface size is in DIPs, while layer size is in pseudo-DIP units that
340 surface_->window()->layer()->SetTransform( 342 // depend on the DSF of the display mode. Scale the layer to capture the
341 gfx::GetScaleTransform(gfx::Point(), cursor_scale_)); 343 // surface at a constant pixel size converted from DIPs using the DSF of
342 344 // the capture display, regardless of its UI scale and display mode DSF.
343 float primary_device_scale_factor = 345 display::Display display = GetCaptureDisplay();
344 display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); 346 const auto& info = GetDisplayInfo(display);
347 float display_scale = info.GetEffectiveUIScale() * info.device_scale_factor();
348 surface_->window()->SetTransform(gfx::GetScaleTransform(
349 gfx::Point(), display_scale / display.device_scale_factor()));
345 350
346 std::unique_ptr<cc::CopyOutputRequest> request = 351 std::unique_ptr<cc::CopyOutputRequest> request =
347 cc::CopyOutputRequest::CreateBitmapRequest( 352 cc::CopyOutputRequest::CreateBitmapRequest(
348 base::Bind(&Pointer::OnCursorCaptured, 353 base::Bind(&Pointer::OnCursorCaptured,
349 cursor_capture_weak_ptr_factory_.GetWeakPtr(), 354 cursor_capture_weak_ptr_factory_.GetWeakPtr()));
350 gfx::ScaleToFlooredPoint( 355
351 hotspot_,
352 // |hotspot_| is in surface coordinate space so apply
353 // both device scale and UI scale.
354 cursor_scale_ * primary_device_scale_factor)));
355 request->set_source(cursor_capture_source_id_); 356 request->set_source(cursor_capture_source_id_);
356 surface_->window()->layer()->RequestCopyOfOutput(std::move(request)); 357 surface_->window()->layer()->RequestCopyOfOutput(std::move(request));
357 } 358 }
358 359
359 void Pointer::OnCursorCaptured(const gfx::Point& hotspot, 360 void Pointer::OnCursorCaptured(std::unique_ptr<cc::CopyOutputResult> result) {
360 std::unique_ptr<cc::CopyOutputResult> result) {
361 if (!focus_) 361 if (!focus_)
362 return; 362 return;
363 363
364 cursor_ = ui::CursorType::kNone; 364 if (result->IsEmpty()) {
365 if (!result->IsEmpty()) { 365 cursor_.reset();
366 DCHECK(result->HasBitmap()); 366 SetCursor(ui::CursorType::kNone);
367 std::unique_ptr<SkBitmap> bitmap = result->TakeBitmap(); 367 return;
368
369 ui::PlatformCursor platform_cursor;
370 #if defined(USE_OZONE)
371 // TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers
372 // and use that here instead of the current bitmap API. crbug.com/686600
373 platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor(
374 *bitmap.get(), hotspot, cursor_scale_);
375 #elif defined(USE_X11)
376 XcursorImage* image = ui::SkBitmapToXcursorImage(bitmap.get(), hotspot);
377 platform_cursor = ui::CreateReffedCustomXCursor(image);
378 #endif
379 cursor_ = ui::CursorType::kCustom;
380 cursor_.SetPlatformCursor(platform_cursor);
381 #if defined(USE_OZONE)
382 ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor);
383 #elif defined(USE_X11)
384 ui::UnrefCustomXCursor(platform_cursor);
385 #endif
386 } 368 }
387 369
370 DCHECK(result->HasBitmap());
371 cursor_ = *result->TakeBitmap();
388 UpdateCursor(); 372 UpdateCursor();
389 } 373 }
390 374
391 void Pointer::UpdateCursor() { 375 void Pointer::UpdateCursor() {
392 DCHECK(focus_); 376 DCHECK(focus_);
393 377
378 if (cursor_.drawsNothing())
379 return;
380
381 const auto& info = GetDisplayInfo(GetCaptureDisplay());
382
383 SkBitmap bitmap = cursor_;
384 gfx::Point hotspot =
385 gfx::ScaleToFlooredPoint(hotspot_, info.device_scale_factor());
386
387 ui::ScaleAndRotateCursorBitmapAndHotpoint(
388 cursor_scale_ * device_scale_factor_ / info.device_scale_factor(),
389 rotation_, &bitmap, &hotspot);
390
391 ui::PlatformCursor platform_cursor;
392 #if defined(USE_OZONE)
393 // TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers
394 // and use that here instead of the current bitmap API. crbug.com/686600
395 platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor(
396 bitmap, hotspot, 0);
397 #elif defined(USE_X11)
398 XcursorImage* image = ui::SkBitmapToXcursorImage(&bitmap, hotspot);
399 platform_cursor = ui::CreateReffedCustomXCursor(image);
400 #endif
401 gfx::NativeCursor cursor = ui::CursorType::kCustom;
402 cursor.SetPlatformCursor(platform_cursor);
403 #if defined(USE_OZONE)
404 ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor);
405 #elif defined(USE_X11)
406 ui::UnrefCustomXCursor(platform_cursor);
407 #endif
408
409 SetCursor(cursor);
410 }
411
412 void Pointer::SetCursor(gfx::NativeCursor cursor) {
413 DCHECK(focus_);
414
394 aura::Window* root_window = focus_->window()->GetRootWindow(); 415 aura::Window* root_window = focus_->window()->GetRootWindow();
395 if (!root_window) 416 if (!root_window)
396 return; 417 return;
397 418
398 aura::client::CursorClient* cursor_client = 419 aura::client::CursorClient* cursor_client =
399 aura::client::GetCursorClient(root_window); 420 aura::client::GetCursorClient(root_window);
400 if (cursor_client) 421 if (cursor_client)
401 cursor_client->SetCursor(cursor_); 422 cursor_client->SetCursor(cursor);
402 } 423 }
403 424
404 } // namespace exo 425 } // namespace exo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698