Upstream version 10.38.220.0
[platform/framework/web/crosswalk.git] / src / ash / touch / touch_transformer_controller.cc
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.
4
5 #include "ash/touch/touch_transformer_controller.h"
6
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"
17
18 namespace ash {
19
20 namespace {
21
22 DisplayManager* GetDisplayManager() {
23   return Shell::GetInstance()->display_manager();
24 }
25
26 }  // namespace
27
28
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;
41
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;
53   }
54
55   double width = touch_display.bounds_in_native().width();
56   double height = touch_display.bounds_in_native().height();
57
58   if (max_x == 0.0 || max_y == 0.0 || width == 0.0 || height == 0.0)
59     return 1.0;
60
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;
65
66   double ratio = std::sqrt((width * height) / (max_x * max_y));
67
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;
72 }
73
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;
89 }
90
91 bool TouchTransformerController::ShouldComputeMirrorModeTouchTransformer(
92     const DisplayInfo& touch_display) const {
93   if (force_compute_mirror_mode_touch_transformer_)
94     return true;
95
96   if (touch_display.touch_device_id() == 0)
97     return false;
98
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;
106     }
107   }
108
109   if (!state || state->mirror_mode == state->display->native_mode() ||
110       !state->display->is_aspect_preserving_scaling()) {
111     return false;
112   }
113   return true;
114 }
115
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;
128
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;
133
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;
140        }
141   }
142
143   if (native_height == 0.0 || mirror_height == 0.0 ||
144       native_width == 0.0 || mirror_width == 0.0)
145     return ctm;
146
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);
151
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;
157   }
158
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;
164   }
165
166   return ctm;  // Same aspect ratio - return identity
167 }
168
169 TouchTransformerController::TouchTransformerController() :
170     force_compute_mirror_mode_touch_transformer_ (false) {
171   Shell::GetInstance()->display_controller()->AddObserver(this);
172 }
173
174 TouchTransformerController::~TouchTransformerController() {
175   Shell::GetInstance()->display_controller()->RemoveObserver(this);
176 }
177
178 void TouchTransformerController::UpdateTouchTransformer() const {
179   ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance();
180   device_manager->ClearTouchTransformerRecord();
181
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;
190
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     DisplayIdPair id_pair = GetDisplayManager()->GetCurrentDisplayIdPair();
201     display1_id = id_pair.first;
202     display2_id = id_pair.second;
203     DCHECK(display1_id != gfx::Display::kInvalidDisplayID &&
204            display2_id != gfx::Display::kInvalidDisplayID);
205     display1 = GetDisplayManager()->GetDisplayInfo(display1_id);
206     display2 = GetDisplayManager()->GetDisplayInfo(display2_id);
207     device_manager->UpdateTouchRadiusScale(display1.touch_device_id(),
208                                            GetTouchResolutionScale(display1));
209     device_manager->UpdateTouchRadiusScale(display2.touch_device_id(),
210                                            GetTouchResolutionScale(display2));
211   } else {
212     single_display_id = GetDisplayManager()->first_display_id();
213     DCHECK(single_display_id != gfx::Display::kInvalidDisplayID);
214     single_display = GetDisplayManager()->GetDisplayInfo(single_display_id);
215     device_manager->UpdateTouchRadiusScale(
216         single_display.touch_device_id(),
217         GetTouchResolutionScale(single_display));
218   }
219
220   if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR) {
221     // In mirror mode, both displays share the same root window so
222     // both display ids are associated with the root window.
223     aura::Window* root = display_controller->GetPrimaryRootWindow();
224     RootWindowController::ForWindow(root)->ash_host()->UpdateDisplayID(
225         display1_id, display2_id);
226     device_manager->UpdateTouchInfoForDisplay(
227         display1_id,
228         display1.touch_device_id(),
229         GetMirrorModeTouchTransformer(display1));
230     device_manager->UpdateTouchInfoForDisplay(
231         display2_id,
232         display2.touch_device_id(),
233         GetMirrorModeTouchTransformer(display2));
234     return;
235   }
236
237   if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) {
238     gfx::Size fb_size =
239         Shell::GetInstance()->display_configurator()->framebuffer_size();
240     // In extended but software mirroring mode, ther is only one X root window
241     // that associates with both displays.
242     if (GetDisplayManager()->software_mirroring_enabled())  {
243       aura::Window* root = display_controller->GetPrimaryRootWindow();
244       RootWindowController::ForWindow(root)->ash_host()->UpdateDisplayID(
245           display1_id, display2_id);
246       DisplayInfo source_display =
247           gfx::Display::InternalDisplayId() == display1_id ?
248           display1 : display2;
249       // Mapping from framebuffer size to the source display's native
250       // resolution.
251       device_manager->UpdateTouchInfoForDisplay(
252           display1_id,
253           display1.touch_device_id(),
254           GetExtendedModeTouchTransformer(source_display, fb_size));
255       device_manager->UpdateTouchInfoForDisplay(
256           display2_id,
257           display2.touch_device_id(),
258           GetExtendedModeTouchTransformer(source_display, fb_size));
259     } else {
260       // In actual extended mode, each display is associated with one root
261       // window.
262       aura::Window* root1 =
263           display_controller->GetRootWindowForDisplayId(display1_id);
264       aura::Window* root2 =
265           display_controller->GetRootWindowForDisplayId(display2_id);
266       RootWindowController::ForWindow(root1)->ash_host()->UpdateDisplayID(
267           display1_id, gfx::Display::kInvalidDisplayID);
268       RootWindowController::ForWindow(root2)->ash_host()->UpdateDisplayID(
269           display2_id, gfx::Display::kInvalidDisplayID);
270       // Mapping from framebuffer size to each display's native resolution.
271       device_manager->UpdateTouchInfoForDisplay(
272           display1_id,
273           display1.touch_device_id(),
274           GetExtendedModeTouchTransformer(display1, fb_size));
275       device_manager->UpdateTouchInfoForDisplay(
276           display2_id,
277           display2.touch_device_id(),
278           GetExtendedModeTouchTransformer(display2, fb_size));
279     }
280     return;
281   }
282
283   // Single display mode. The root window has one associated display id.
284   aura::Window* root =
285       display_controller->GetRootWindowForDisplayId(single_display.id());
286   RootWindowController::ForWindow(root)->ash_host()->UpdateDisplayID(
287       single_display.id(), gfx::Display::kInvalidDisplayID);
288   device_manager->UpdateTouchInfoForDisplay(single_display_id,
289                                             single_display.touch_device_id(),
290                                             gfx::Transform());
291 }
292
293 void TouchTransformerController::OnDisplaysInitialized() {
294   UpdateTouchTransformer();
295 }
296
297 void TouchTransformerController::OnDisplayConfigurationChanged() {
298   UpdateTouchTransformer();
299 }
300
301 }  // namespace ash