OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |