1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/touch/touch_transformer_controller.h"
7 #include "ash/display/display_controller.h"
8 #include "ash/display/display_manager.h"
9 #include "ash/host/ash_window_tree_host.h"
10 #include "ash/root_window_controller.h"
11 #include "ash/shell.h"
12 #include "ui/aura/window_tree_host.h"
13 #include "ui/display/chromeos/display_configurator.h"
14 #include "ui/display/types/display_snapshot.h"
15 #include "ui/events/devices/device_data_manager.h"
21 DisplayManager
* GetDisplayManager() {
22 return Shell::GetInstance()->display_manager();
25 ui::TouchscreenDevice
FindTouchscreenById(unsigned int id
) {
26 const std::vector
<ui::TouchscreenDevice
>& touchscreens
=
27 ui::DeviceDataManager::GetInstance()->touchscreen_devices();
28 for (auto touchscreen
: touchscreens
) {
29 if (touchscreen
.id
== id
)
33 return ui::TouchscreenDevice();
38 // This is to compute the scale ratio for the TouchEvent's radius. The
39 // configured resolution of the display is not always the same as the touch
40 // screen's reporting resolution, e.g. the display could be set as
41 // 1920x1080 while the touchscreen is reporting touch position range at
42 // 32767x32767. Touch radius is reported in the units the same as touch position
43 // so we need to scale the touch radius to be compatible with the display's
44 // resolution. We compute the scale as
45 // sqrt of (display_area / touchscreen_area)
46 double TouchTransformerController::GetTouchResolutionScale(
47 const DisplayInfo
& touch_display
,
48 const ui::TouchscreenDevice
& touch_device
) const {
49 if (touch_device
.id
== ui::InputDevice::kInvalidId
||
50 touch_device
.size
.IsEmpty() ||
51 touch_display
.bounds_in_native().size().IsEmpty())
54 double display_area
= touch_display
.bounds_in_native().size().GetArea();
55 double touch_area
= touch_device
.size
.GetArea();
56 double ratio
= std::sqrt(display_area
/ touch_area
);
58 VLOG(2) << "Display size: "
59 << touch_display
.bounds_in_native().size().ToString()
60 << ", Touchscreen size: " << touch_device
.size
.ToString()
61 << ", Touch radius scale ratio: " << ratio
;
65 gfx::Transform
TouchTransformerController::GetTouchTransform(
66 const DisplayInfo
& display
,
67 const ui::TouchscreenDevice
& touchscreen
,
68 const gfx::Size
& framebuffer_size
) const {
69 gfx::SizeF current_size
= display
.bounds_in_native().size();
70 gfx::SizeF native_size
= display
.GetNativeModeSize();
71 #if defined(USE_OZONE)
72 gfx::SizeF touch_area
= touchscreen
.size
;
73 #elif defined(USE_X11)
74 // On X11 touches are reported in the framebuffer coordinate space.
75 gfx::SizeF touch_area
= framebuffer_size
;
80 if (current_size
.IsEmpty() || native_size
.IsEmpty() || touch_area
.IsEmpty() ||
81 touchscreen
.id
== ui::InputDevice::kInvalidId
)
84 // Take care of panel fitting only if supported.
85 // If panel fitting is enabled then the aspect ratio is preserved and the
86 // display is scaled acordingly. In this case blank regions would be present
87 // in order to center the displayed area.
88 if (display
.is_aspect_preserving_scaling()) {
89 float native_ar
= native_size
.width() / native_size
.height();
90 float current_ar
= current_size
.width() / current_size
.height();
92 if (current_ar
> native_ar
) { // Letterboxing
94 0, (1 - current_ar
/ native_ar
) * 0.5 * current_size
.height());
95 ctm
.Scale(1, current_ar
/ native_ar
);
96 } else if (native_ar
> current_ar
) { // Pillarboxing
98 (1 - native_ar
/ current_ar
) * 0.5 * current_size
.width(), 0);
99 ctm
.Scale(native_ar
/ current_ar
, 1);
103 // Take care of scaling between touchscreen area and display resolution.
104 ctm
.Scale(current_size
.width() / touch_area
.width(),
105 current_size
.height() / touch_area
.height());
109 TouchTransformerController::TouchTransformerController() {
110 Shell::GetInstance()->display_controller()->AddObserver(this);
113 TouchTransformerController::~TouchTransformerController() {
114 Shell::GetInstance()->display_controller()->RemoveObserver(this);
117 void TouchTransformerController::UpdateTouchTransformer() const {
118 ui::DeviceDataManager
* device_manager
= ui::DeviceDataManager::GetInstance();
119 device_manager
->ClearTouchTransformerRecord();
121 // Display IDs and DisplayInfo for mirror or extended mode.
122 int64 display1_id
= gfx::Display::kInvalidDisplayID
;
123 int64 display2_id
= gfx::Display::kInvalidDisplayID
;
124 DisplayInfo display1
;
125 DisplayInfo display2
;
126 // Display ID and DisplayInfo for single display mode.
127 int64 single_display_id
= gfx::Display::kInvalidDisplayID
;
128 DisplayInfo single_display
;
130 DisplayController
* display_controller
=
131 Shell::GetInstance()->display_controller();
132 ui::MultipleDisplayState display_state
=
133 Shell::GetInstance()->display_configurator()->display_state();
134 if (display_state
== ui::MULTIPLE_DISPLAY_STATE_INVALID
||
135 display_state
== ui::MULTIPLE_DISPLAY_STATE_HEADLESS
) {
137 } else if (display_state
== ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
||
138 display_state
== ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
) {
139 DisplayIdPair id_pair
= GetDisplayManager()->GetCurrentDisplayIdPair();
140 display1_id
= id_pair
.first
;
141 display2_id
= id_pair
.second
;
142 DCHECK(display1_id
!= gfx::Display::kInvalidDisplayID
&&
143 display2_id
!= gfx::Display::kInvalidDisplayID
);
144 display1
= GetDisplayManager()->GetDisplayInfo(display1_id
);
145 display2
= GetDisplayManager()->GetDisplayInfo(display2_id
);
146 device_manager
->UpdateTouchRadiusScale(
147 display1
.touch_device_id(),
148 GetTouchResolutionScale(
150 FindTouchscreenById(display1
.touch_device_id())));
151 device_manager
->UpdateTouchRadiusScale(
152 display2
.touch_device_id(),
153 GetTouchResolutionScale(
155 FindTouchscreenById(display2
.touch_device_id())));
157 single_display_id
= GetDisplayManager()->first_display_id();
158 DCHECK(single_display_id
!= gfx::Display::kInvalidDisplayID
);
159 single_display
= GetDisplayManager()->GetDisplayInfo(single_display_id
);
160 device_manager
->UpdateTouchRadiusScale(
161 single_display
.touch_device_id(),
162 GetTouchResolutionScale(
164 FindTouchscreenById(single_display
.touch_device_id())));
168 Shell::GetInstance()->display_configurator()->framebuffer_size();
170 if (display_state
== ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
) {
171 // In mirror mode, both displays share the same root window so
172 // both display ids are associated with the root window.
173 aura::Window
* root
= display_controller
->GetPrimaryRootWindow();
174 RootWindowController::ForWindow(root
)->ash_host()->UpdateDisplayID(
175 display1_id
, display2_id
);
176 device_manager
->UpdateTouchInfoForDisplay(
178 display1
.touch_device_id(),
179 GetTouchTransform(display1
,
180 FindTouchscreenById(display1
.touch_device_id()),
182 device_manager
->UpdateTouchInfoForDisplay(
184 display2
.touch_device_id(),
185 GetTouchTransform(display2
,
186 FindTouchscreenById(display2
.touch_device_id()),
191 if (display_state
== ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
) {
192 // In extended but software mirroring mode, ther is only one X root window
193 // that associates with both displays.
194 if (GetDisplayManager()->software_mirroring_enabled()) {
195 aura::Window
* root
= display_controller
->GetPrimaryRootWindow();
196 RootWindowController::ForWindow(root
)->ash_host()->UpdateDisplayID(
197 display1_id
, display2_id
);
198 DisplayInfo source_display
=
199 gfx::Display::InternalDisplayId() == display1_id
?
201 // Mapping from framebuffer size to the source display's native
203 device_manager
->UpdateTouchInfoForDisplay(
205 display1
.touch_device_id(),
206 GetTouchTransform(source_display
,
207 FindTouchscreenById(display1
.touch_device_id()),
209 device_manager
->UpdateTouchInfoForDisplay(
211 display2
.touch_device_id(),
212 GetTouchTransform(source_display
,
213 FindTouchscreenById(display2
.touch_device_id()),
216 // In actual extended mode, each display is associated with one root
218 aura::Window
* root1
=
219 display_controller
->GetRootWindowForDisplayId(display1_id
);
220 aura::Window
* root2
=
221 display_controller
->GetRootWindowForDisplayId(display2_id
);
222 RootWindowController::ForWindow(root1
)->ash_host()->UpdateDisplayID(
223 display1_id
, gfx::Display::kInvalidDisplayID
);
224 RootWindowController::ForWindow(root2
)->ash_host()->UpdateDisplayID(
225 display2_id
, gfx::Display::kInvalidDisplayID
);
226 // Mapping from framebuffer size to each display's native resolution.
227 device_manager
->UpdateTouchInfoForDisplay(
229 display1
.touch_device_id(),
230 GetTouchTransform(display1
,
231 FindTouchscreenById(display1
.touch_device_id()),
233 device_manager
->UpdateTouchInfoForDisplay(
235 display2
.touch_device_id(),
236 GetTouchTransform(display2
,
237 FindTouchscreenById(display2
.touch_device_id()),
243 // Single display mode. The root window has one associated display id.
245 display_controller
->GetRootWindowForDisplayId(single_display
.id());
246 RootWindowController::ForWindow(root
)->ash_host()->UpdateDisplayID(
247 single_display
.id(), gfx::Display::kInvalidDisplayID
);
248 device_manager
->UpdateTouchInfoForDisplay(
250 single_display
.touch_device_id(),
251 GetTouchTransform(single_display
,
252 FindTouchscreenById(single_display
.touch_device_id()),
256 void TouchTransformerController::OnDisplaysInitialized() {
257 UpdateTouchTransformer();
260 void TouchTransformerController::OnDisplayConfigurationChanged() {
261 UpdateTouchTransformer();