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