Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ash / touch / touch_transformer_controller.cc
blobb99cb5a0571a804b3c6db8a302c4f08a94b9b080
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/chromeos/display_snapshot.h"
15 #include "ui/events/device_data_manager.h"
16 #include "ui/events/x/device_data_manager_x11.h"
18 namespace ash {
20 namespace {
22 DisplayManager* GetDisplayManager() {
23 return Shell::GetInstance()->display_manager();
26 } // namespace
29 // This is to compute the scale ratio for the TouchEvent's radius. The
30 // configured resolution of the display is not always the same as the touch
31 // screen's reporting resolution, e.g. the display could be set as
32 // 1920x1080 while the touchscreen is reporting touch position range at
33 // 32767x32767. Touch radius is reported in the units the same as touch position
34 // so we need to scale the touch radius to be compatible with the display's
35 // resolution. We compute the scale as
36 // sqrt of (display_area / touchscreen_area)
37 double TouchTransformerController::GetTouchResolutionScale(
38 const DisplayInfo& touch_display) const {
39 if (touch_display.touch_device_id() == 0)
40 return 1.0;
42 double min_x, max_x;
43 double min_y, max_y;
44 if (!ui::DeviceDataManagerX11::GetInstance()->GetDataRange(
45 touch_display.touch_device_id(),
46 ui::DeviceDataManagerX11::DT_TOUCH_POSITION_X,
47 &min_x, &max_x) ||
48 !ui::DeviceDataManagerX11::GetInstance()->GetDataRange(
49 touch_display.touch_device_id(),
50 ui::DeviceDataManagerX11::DT_TOUCH_POSITION_Y,
51 &min_y, &max_y)) {
52 return 1.0;
55 double width = touch_display.bounds_in_native().width();
56 double height = touch_display.bounds_in_native().height();
58 if (max_x == 0.0 || max_y == 0.0 || width == 0.0 || height == 0.0)
59 return 1.0;
61 // [0, max_x] -> touchscreen width = max_x + 1
62 // [0, max_y] -> touchscreen height = max_y + 1
63 max_x += 1.0;
64 max_y += 1.0;
66 double ratio = std::sqrt((width * height) / (max_x * max_y));
68 VLOG(2) << "Screen width/height: " << width << "/" << height
69 << ", Touchscreen width/height: " << max_x << "/" << max_y
70 << ", Touch radius scale ratio: " << ratio;
71 return ratio;
74 // This function computes the extended mode TouchTransformer for
75 // |touch_display|. The TouchTransformer maps the touch event position
76 // from framebuffer size to the display size.
77 gfx::Transform
78 TouchTransformerController::GetExtendedModeTouchTransformer(
79 const DisplayInfo& touch_display, const gfx::Size& fb_size) const {
80 gfx::Transform ctm;
81 if (touch_display.touch_device_id() == 0 ||
82 fb_size.width() == 0.0 ||
83 fb_size.height() == 0.0)
84 return ctm;
85 float width = touch_display.bounds_in_native().width();
86 float height = touch_display.bounds_in_native().height();
87 ctm.Scale(width / fb_size.width(), height / fb_size.height());
88 return ctm;
91 bool TouchTransformerController::ShouldComputeMirrorModeTouchTransformer(
92 const DisplayInfo& touch_display) const {
93 if (force_compute_mirror_mode_touch_transformer_)
94 return true;
96 if (touch_display.touch_device_id() == 0)
97 return false;
99 const ui::DisplayConfigurator::DisplayState* state = NULL;
100 const std::vector<ui::DisplayConfigurator::DisplayState>& cached_displays =
101 Shell::GetInstance()->display_configurator()->cached_displays();
102 for (size_t i = 0; i < cached_displays.size(); i++) {
103 if (cached_displays[i].touch_device_id == touch_display.touch_device_id()) {
104 state = &cached_displays[i];
105 break;
109 if (!state || state->mirror_mode == state->display->native_mode() ||
110 !state->display->is_aspect_preserving_scaling()) {
111 return false;
113 return true;
116 // This function computes the mirror mode TouchTransformer for |touch_display|.
117 // When internal monitor is applied a resolution that does not have
118 // the same aspect ratio as its native resolution, there would be
119 // blank regions in the letterboxing/pillarboxing mode.
120 // The TouchTransformer will make sure the touch events on the blank region
121 // have negative coordinates and touch events within the chrome region
122 // have the correct positive coordinates.
123 gfx::Transform TouchTransformerController::GetMirrorModeTouchTransformer(
124 const DisplayInfo& touch_display) const {
125 gfx::Transform ctm;
126 if (!ShouldComputeMirrorModeTouchTransformer(touch_display))
127 return ctm;
129 float mirror_width = touch_display.bounds_in_native().width();
130 float mirror_height = touch_display.bounds_in_native().height();
131 float native_width = 0;
132 float native_height = 0;
134 std::vector<DisplayMode> modes = touch_display.display_modes();
135 for (size_t i = 0; i < modes.size(); i++) {
136 if (modes[i].native) {
137 native_width = modes[i].size.width();
138 native_height = modes[i].size.height();
139 break;
143 if (native_height == 0.0 || mirror_height == 0.0 ||
144 native_width == 0.0 || mirror_width == 0.0)
145 return ctm;
147 float native_ar = static_cast<float>(native_width) /
148 static_cast<float>(native_height);
149 float mirror_ar = static_cast<float>(mirror_width) /
150 static_cast<float>(mirror_height);
152 if (mirror_ar > native_ar) { // Letterboxing
153 // Translate before scale.
154 ctm.Translate(0.0, (1.0 - mirror_ar / native_ar) * 0.5 * mirror_height);
155 ctm.Scale(1.0, mirror_ar / native_ar);
156 return ctm;
159 if (native_ar > mirror_ar) { // Pillarboxing
160 // Translate before scale.
161 ctm.Translate((1.0 - native_ar / mirror_ar) * 0.5 * mirror_width, 0.0);
162 ctm.Scale(native_ar / mirror_ar, 1.0);
163 return ctm;
166 return ctm; // Same aspect ratio - return identity
169 TouchTransformerController::TouchTransformerController() :
170 force_compute_mirror_mode_touch_transformer_ (false) {
171 Shell::GetInstance()->display_controller()->AddObserver(this);
174 TouchTransformerController::~TouchTransformerController() {
175 Shell::GetInstance()->display_controller()->RemoveObserver(this);
178 void TouchTransformerController::UpdateTouchTransformer() const {
179 ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance();
180 device_manager->ClearTouchTransformerRecord();
182 // Display IDs and DisplayInfo for mirror or extended mode.
183 int64 display1_id = gfx::Display::kInvalidDisplayID;
184 int64 display2_id = gfx::Display::kInvalidDisplayID;
185 DisplayInfo display1;
186 DisplayInfo display2;
187 // Display ID and DisplayInfo for single display mode.
188 int64 single_display_id = gfx::Display::kInvalidDisplayID;
189 DisplayInfo single_display;
191 DisplayController* display_controller =
192 Shell::GetInstance()->display_controller();
193 ui::MultipleDisplayState display_state =
194 Shell::GetInstance()->display_configurator()->display_state();
195 if (display_state == ui::MULTIPLE_DISPLAY_STATE_INVALID ||
196 display_state == ui::MULTIPLE_DISPLAY_STATE_HEADLESS) {
197 return;
198 } else if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR ||
199 display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) {
200 // TODO(miletus) : Handle DUAL_EXTENDED with software mirroring.
201 DisplayIdPair id_pair = GetDisplayManager()->GetCurrentDisplayIdPair();
202 display1_id = id_pair.first;
203 display2_id = id_pair.second;
204 DCHECK(display1_id != gfx::Display::kInvalidDisplayID &&
205 display2_id != gfx::Display::kInvalidDisplayID);
206 display1 = GetDisplayManager()->GetDisplayInfo(display1_id);
207 display2 = GetDisplayManager()->GetDisplayInfo(display2_id);
208 device_manager->UpdateTouchRadiusScale(display1.touch_device_id(),
209 GetTouchResolutionScale(display1));
210 device_manager->UpdateTouchRadiusScale(display2.touch_device_id(),
211 GetTouchResolutionScale(display2));
212 } else {
213 single_display_id = GetDisplayManager()->first_display_id();
214 DCHECK(single_display_id != gfx::Display::kInvalidDisplayID);
215 single_display = GetDisplayManager()->GetDisplayInfo(single_display_id);
216 device_manager->UpdateTouchRadiusScale(
217 single_display.touch_device_id(),
218 GetTouchResolutionScale(single_display));
221 if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR) {
222 // In mirror mode, both displays share the same root window so
223 // both display ids are associated with the root window.
224 aura::Window* root = display_controller->GetPrimaryRootWindow();
225 RootWindowController::ForWindow(root)->ash_host()->UpdateDisplayID(
226 display1_id, display2_id);
227 device_manager->UpdateTouchInfoForDisplay(
228 display1_id,
229 display1.touch_device_id(),
230 GetMirrorModeTouchTransformer(display1));
231 device_manager->UpdateTouchInfoForDisplay(
232 display2_id,
233 display2.touch_device_id(),
234 GetMirrorModeTouchTransformer(display2));
235 return;
238 if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) {
239 // TODO(miletus) : Handle the case the state is DUAL_EXTENDED but it
240 // is actually doing software mirroring.
241 if (GetDisplayManager()->software_mirroring_enabled())
242 return;
243 // In extended mode, each display is associated with one root window.
244 aura::Window* root1 =
245 display_controller->GetRootWindowForDisplayId(display1_id);
246 aura::Window* root2 =
247 display_controller->GetRootWindowForDisplayId(display2_id);
248 RootWindowController::ForWindow(root1)->ash_host()->UpdateDisplayID(
249 display1_id, gfx::Display::kInvalidDisplayID);
250 RootWindowController::ForWindow(root2)->ash_host()->UpdateDisplayID(
251 display2_id, gfx::Display::kInvalidDisplayID);
252 gfx::Size fb_size =
253 Shell::GetInstance()->display_configurator()->framebuffer_size();
254 device_manager->UpdateTouchInfoForDisplay(
255 display1_id,
256 display1.touch_device_id(),
257 GetExtendedModeTouchTransformer(display1, fb_size));
258 device_manager->UpdateTouchInfoForDisplay(
259 display2_id,
260 display2.touch_device_id(),
261 GetExtendedModeTouchTransformer(display2, fb_size));
262 return;
265 // Single display mode. The root window has one associated display id.
266 aura::Window* root =
267 display_controller->GetRootWindowForDisplayId(single_display.id());
268 RootWindowController::ForWindow(root)->ash_host()->UpdateDisplayID(
269 single_display.id(), gfx::Display::kInvalidDisplayID);
270 device_manager->UpdateTouchInfoForDisplay(single_display_id,
271 single_display.touch_device_id(),
272 gfx::Transform());
275 void TouchTransformerController::OnDisplaysInitialized() {
276 UpdateTouchTransformer();
279 void TouchTransformerController::OnDisplayConfigurationChanged() {
280 UpdateTouchTransformer();
283 } // namespace ash