Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(490)

Side by Side Diff: ash/touch/touch_transformer_controller.cc

Issue 2557163002: Implements computation of touch calibration transform using user provided data (Closed)
Patch Set: Removed CHECK() and added test as friend class Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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 "ash/touch/touch_transformer_controller.h" 5 #include "ash/touch/touch_transformer_controller.h"
6 6
7 #include "ash/display/window_tree_host_manager.h" 7 #include "ash/display/window_tree_host_manager.h"
8 #include "ash/host/ash_window_tree_host.h" 8 #include "ash/host/ash_window_tree_host.h"
9 #include "ash/root_window_controller.h" 9 #include "ash/root_window_controller.h"
10 #include "ash/shell.h" 10 #include "ash/shell.h"
11 #include "third_party/skia/include/core/SkMatrix44.h"
11 #include "ui/aura/window_tree_host.h" 12 #include "ui/aura/window_tree_host.h"
12 #include "ui/display/display_layout.h" 13 #include "ui/display/display_layout.h"
13 #include "ui/display/manager/chromeos/display_configurator.h" 14 #include "ui/display/manager/chromeos/display_configurator.h"
14 #include "ui/display/manager/display_manager.h" 15 #include "ui/display/manager/display_manager.h"
15 #include "ui/display/types/display_constants.h" 16 #include "ui/display/types/display_constants.h"
16 #include "ui/display/types/display_snapshot.h" 17 #include "ui/display/types/display_snapshot.h"
17 #include "ui/events/devices/device_data_manager.h" 18 #include "ui/events/devices/device_data_manager.h"
18 19
19 namespace ash { 20 namespace ash {
20 21
21 namespace { 22 namespace {
22 23
23 display::DisplayManager* GetDisplayManager() { 24 display::DisplayManager* GetDisplayManager() {
24 return Shell::GetInstance()->display_manager(); 25 return Shell::GetInstance()->display_manager();
25 } 26 }
26 27
27 ui::TouchscreenDevice FindTouchscreenById(int id) { 28 ui::TouchscreenDevice FindTouchscreenById(int id) {
28 const std::vector<ui::TouchscreenDevice>& touchscreens = 29 const std::vector<ui::TouchscreenDevice>& touchscreens =
29 ui::DeviceDataManager::GetInstance()->GetTouchscreenDevices(); 30 ui::DeviceDataManager::GetInstance()->GetTouchscreenDevices();
30 for (const auto& touchscreen : touchscreens) { 31 for (const auto& touchscreen : touchscreens) {
31 if (touchscreen.id == id) 32 if (touchscreen.id == id)
32 return touchscreen; 33 return touchscreen;
33 } 34 }
34 35
35 return ui::TouchscreenDevice(); 36 return ui::TouchscreenDevice();
36 } 37 }
37 38
39 // Given an array of touch point and display point pairs, this function computes
40 // and returns the constants(defined below) using a least fit algorithm.
41 // If (xt, yt) is a touch point then its corresponding (xd, yd) would be defined
42 // by the following 2 equations:
43 // xd = xt * A + yt * B + C
44 // yd = xt * D + yt * E + F
45 // This function computes A, B, C, D, E and F and sets |ctm| with the calibrated
46 // transform matrix. In case the computation fails, the function will return
47 // false.
48 // See http://crbug.com/672293
49 bool GetCalibratedTransform(
50 std::array<std::pair<gfx::Point, gfx::Point>, 4> touch_point_pairs,
sadrul 2016/12/22 02:25:43 Make this a const-ref. Make a copy in the function
malaykeshav 2016/12/22 09:04:33 If we are making a copy again, isn't it better to
51 const gfx::Transform& pre_calibration_tm,
52 gfx::Transform* ctm) {
53 // Transform the display points before solving the equation.
54 // If the calibration was performed at a resolution that is 0.5 times the
55 // current resolution, then the display points (x, y) for a given touch point
56 // now represents a display point at (2 * x, 2 * y). This and other kinds of
57 // similar tranforms can be applied using |pre_calibration_tm|.
58 for (int row = 0; row < 4; row++)
59 pre_calibration_tm.TransformPoint(&touch_point_pairs[row].first);
60
61 // Vector of the X-coordinate of display points corresponding to each of the
62 // touch points.
63 SkVector4 display_points_x(
64 touch_point_pairs[0].first.x(), touch_point_pairs[1].first.x(),
65 touch_point_pairs[2].first.x(), touch_point_pairs[3].first.x());
66 // Vector of the Y-coordinate of display points corresponding to each of the
67 // touch points.
68 SkVector4 display_points_y(
69 touch_point_pairs[0].first.y(), touch_point_pairs[1].first.y(),
70 touch_point_pairs[2].first.y(), touch_point_pairs[3].first.y());
71
72 // Initialize |touch_point_matrix|
73 // If {(xt_1, yt_1), (xt_2, yt_2), (xt_3, yt_3)....} are a set of touch points
74 // received during calibration, then the |touch_point_matrix| would be defined
75 // as:
76 // |xt_1 yt_1 1 0|
77 // |xt_2 yt_2 1 0|
78 // |xt_3 yt_3 1 0|
79 // |xt_4 yt_4 1 0|
80 SkMatrix44 touch_point_matrix;
81 for (int row = 0; row < 4; row++) {
82 touch_point_matrix.set(row, 0, touch_point_pairs[row].second.x());
83 touch_point_matrix.set(row, 1, touch_point_pairs[row].second.y());
84 touch_point_matrix.set(row, 2, 1);
85 touch_point_matrix.set(row, 3, 0);
86 }
87 SkMatrix44 touch_point_matrix_transpose(touch_point_matrix);
88 touch_point_matrix_transpose.transpose();
89
90 SkMatrix44 product_matrix = touch_point_matrix_transpose * touch_point_matrix;
91
92 // Set (3, 3) = 1 so that |determinent| of the matrix is != 0 and the inverse
93 // can be calculated.
94 product_matrix.set(3, 3, 1);
95
96 SkMatrix44 product_matrix_inverse;
97
98 // NOTE: If the determinent is zero then the inverse cannot be computed. The
99 // only solution is to restart touch calibration and get new points from user.
100 if (!product_matrix.invert(&product_matrix_inverse)) {
101 NOTREACHED() << "Touch Calibration failed. Determinent is zero.";
102 return false;
103 }
104
105 product_matrix_inverse.set(3, 3, 0);
106
107 product_matrix = product_matrix_inverse * touch_point_matrix_transpose;
108
109 // Constants [A, B, C, 0] used to calibrate the x-coordinate of touch input.
110 // x_new = x_old * A + y_old * B + C;
111 SkVector4 x_constants = product_matrix * display_points_x;
112 // Constants [D, E, F, 0] used to calibrate the y-coordinate of touch input.
113 // y_new = x_old * D + y_old * E + F;
114 SkVector4 y_constants = product_matrix * display_points_y;
115
116 // Create a transform matrix using the touch calibration data.
117 (*ctm).ConcatTransform(gfx::Transform(
118 x_constants.fData[0], x_constants.fData[1], 0, x_constants.fData[2],
119 y_constants.fData[0], y_constants.fData[1], 0, y_constants.fData[2], 0, 0,
120 1, 0, 0, 0, 0, 1));
121 return true;
122 }
123
124 // Returns an uncalibrated touch transform.
125 gfx::Transform GetUncalibratedTransform(
126 const gfx::Transform& tm,
127 const display::ManagedDisplayInfo& display,
128 const display::ManagedDisplayInfo& touch_display,
129 const gfx::SizeF& touch_area,
130 const gfx::SizeF& touch_native_size) {
131 gfx::SizeF current_size(display.bounds_in_native().size());
132 gfx::Transform ctm(tm);
133 // Take care of panel fitting only if supported. Panel fitting is emulated
134 // in software mirroring mode (display != touch_display).
135 // If panel fitting is enabled then the aspect ratio is preserved and the
136 // display is scaled acordingly. In this case blank regions would be present
137 // in order to center the displayed area.
138 if (display.is_aspect_preserving_scaling() ||
139 display.id() != touch_display.id()) {
140 float touch_calib_ar =
141 touch_native_size.width() / touch_native_size.height();
142 float current_ar = current_size.width() / current_size.height();
143
144 if (current_ar > touch_calib_ar) { // Letterboxing
145 ctm.Translate(
146 0, (1 - current_ar / touch_calib_ar) * 0.5 * current_size.height());
147 ctm.Scale(1, current_ar / touch_calib_ar);
148 } else if (touch_calib_ar > current_ar) { // Pillarboxing
149 ctm.Translate(
150 (1 - touch_calib_ar / current_ar) * 0.5 * current_size.width(), 0);
151 ctm.Scale(touch_calib_ar / current_ar, 1);
152 }
153 }
154 // Take care of scaling between touchscreen area and display resolution.
155 ctm.Scale(current_size.width() / touch_area.width(),
156 current_size.height() / touch_area.height());
157 return ctm;
158 }
159
38 } // namespace 160 } // namespace
39 161
40 // This is to compute the scale ratio for the TouchEvent's radius. The 162 // This is to compute the scale ratio for the TouchEvent's radius. The
41 // configured resolution of the display is not always the same as the touch 163 // configured resolution of the display is not always the same as the touch
42 // screen's reporting resolution, e.g. the display could be set as 164 // screen's reporting resolution, e.g. the display could be set as
43 // 1920x1080 while the touchscreen is reporting touch position range at 165 // 1920x1080 while the touchscreen is reporting touch position range at
44 // 32767x32767. Touch radius is reported in the units the same as touch position 166 // 32767x32767. Touch radius is reported in the units the same as touch position
45 // so we need to scale the touch radius to be compatible with the display's 167 // so we need to scale the touch radius to be compatible with the display's
46 // resolution. We compute the scale as 168 // resolution. We compute the scale as
47 // sqrt of (display_area / touchscreen_area) 169 // sqrt of (display_area / touchscreen_area)
(...skipping 30 matching lines...) Expand all
78 auto touch_area = gfx::SizeF(framebuffer_size); 200 auto touch_area = gfx::SizeF(framebuffer_size);
79 #endif 201 #endif
80 202
81 gfx::Transform ctm; 203 gfx::Transform ctm;
82 204
83 if (current_size.IsEmpty() || touch_native_size.IsEmpty() || 205 if (current_size.IsEmpty() || touch_native_size.IsEmpty() ||
84 touch_area.IsEmpty() || touchscreen.id == ui::InputDevice::kInvalidId) 206 touch_area.IsEmpty() || touchscreen.id == ui::InputDevice::kInvalidId)
85 return ctm; 207 return ctm;
86 208
87 #if defined(USE_OZONE) 209 #if defined(USE_OZONE)
88 // Translate the touch so that it falls within the display bounds. 210 // Translate the touch so that it falls within the display bounds. This
89 ctm.Translate(display.bounds_in_native().x(), display.bounds_in_native().y()); 211 // should not be performed if the displays are mirrored.
212 if (display.id() == touch_display.id()) {
213 ctm.Translate(display.bounds_in_native().x(),
214 display.bounds_in_native().y());
215 }
90 #endif 216 #endif
91 217
92 // Take care of panel fitting only if supported. Panel fitting is emulated in 218 // If the device is currently under calibration, then do not return any
93 // software mirroring mode (display != touch_display). 219 // transform as we want to use the raw native touch input data for
94 // If panel fitting is enabled then the aspect ratio is preserved and the 220 // calibration.
95 // display is scaled acordingly. In this case blank regions would be present 221 if (is_calibrating_)
96 // in order to center the displayed area. 222 return ctm;
97 if (display.is_aspect_preserving_scaling() || 223
98 display.id() != touch_display.id()) { 224 // If touch calibration data is unavailable, use naive approach.
99 float touch_native_ar = 225 if (!touch_display.has_touch_calibration_data()) {
100 touch_native_size.width() / touch_native_size.height(); 226 return GetUncalibratedTransform(ctm, display, touch_display, touch_area,
227 touch_native_size);
228 }
229
230 // The resolution at which the touch calibration was performed.
231 gfx::SizeF touch_calib_size(touch_display.GetTouchCalibrationData().bounds);
232
233 // Any additional transfomration that needs to be applied to the display
234 // points, before we solve for the final transform.
235 gfx::Transform pre_transform;
236
237 if (display.id() != touch_display.id() ||
238 display.is_aspect_preserving_scaling()) {
239 // Case of displays being mirrored or in panel fitting mode.
240 // Aspect ratio of the touch display's resolution during calibration.
241 float calib_ar = touch_calib_size.width() / touch_calib_size.height();
242 // Aspect ratio of the display that is being mirrored.
101 float current_ar = current_size.width() / current_size.height(); 243 float current_ar = current_size.width() / current_size.height();
102 244
103 if (current_ar > touch_native_ar) { // Letterboxing 245 if (current_ar < calib_ar) {
104 ctm.Translate( 246 pre_transform.Scale(current_size.height() / touch_calib_size.height(),
105 0, (1 - current_ar / touch_native_ar) * 0.5 * current_size.height()); 247 current_size.height() / touch_calib_size.height());
106 ctm.Scale(1, current_ar / touch_native_ar); 248 pre_transform.Translate(
107 } else if (touch_native_ar > current_ar) { // Pillarboxing 249 (current_ar / calib_ar - 1.f) * touch_calib_size.width() * 0.5f, 0);
108 ctm.Translate( 250 } else {
109 (1 - touch_native_ar / current_ar) * 0.5 * current_size.width(), 0); 251 pre_transform.Scale(current_size.width() / touch_calib_size.width(),
110 ctm.Scale(touch_native_ar / current_ar, 1); 252 current_size.width() / touch_calib_size.width());
253 pre_transform.Translate(
254 0, (calib_ar / current_ar - 1.f) * touch_calib_size.height() * 0.5f);
111 } 255 }
256 } else {
257 // Case of current resolution being different from the resolution when the
258 // touch calibration was performed.
259 pre_transform.Scale(current_size.width() / touch_calib_size.width(),
260 current_size.height() / touch_calib_size.height());
261 }
262 // Solve for coefficients and compute transform matrix.
263 gfx::Transform stored_ctm;
264 if (!GetCalibratedTransform(
265 touch_display.GetTouchCalibrationData().point_pairs, pre_transform,
266 &stored_ctm)) {
267 // TODO(malaykeshav): This can be checked at the calibration step before
268 // storing the calibration associated data. This will allow us to explicitly
269 // inform the user with proper UX.
270
271 // Clear stored calibration data.
272 GetDisplayManager()->ClearTouchCalibrationData(touch_display.id());
273
274 // Return uncalibrated transform.
275 return GetUncalibratedTransform(ctm, display, touch_display, touch_area,
276 touch_native_size);
112 } 277 }
113 278
114 // Take care of scaling between touchscreen area and display resolution. 279 stored_ctm.ConcatTransform(ctm);
115 ctm.Scale(current_size.width() / touch_area.width(), 280 return stored_ctm;
116 current_size.height() / touch_area.height());
117 return ctm;
118 } 281 }
119 282
120 TouchTransformerController::TouchTransformerController() { 283 TouchTransformerController::TouchTransformerController() {
121 Shell::GetInstance()->window_tree_host_manager()->AddObserver(this); 284 Shell::GetInstance()->window_tree_host_manager()->AddObserver(this);
122 } 285 }
123 286
124 TouchTransformerController::~TouchTransformerController() { 287 TouchTransformerController::~TouchTransformerController() {
125 Shell::GetInstance()->window_tree_host_manager()->RemoveObserver(this); 288 Shell::GetInstance()->window_tree_host_manager()->RemoveObserver(this);
126 } 289 }
127 290
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 } 382 }
220 383
221 void TouchTransformerController::OnDisplaysInitialized() { 384 void TouchTransformerController::OnDisplaysInitialized() {
222 UpdateTouchTransformer(); 385 UpdateTouchTransformer();
223 } 386 }
224 387
225 void TouchTransformerController::OnDisplayConfigurationChanged() { 388 void TouchTransformerController::OnDisplayConfigurationChanged() {
226 UpdateTouchTransformer(); 389 UpdateTouchTransformer();
227 } 390 }
228 391
392 void TouchTransformerController::SetForCalibration(bool is_calibrating) {
393 is_calibrating_ = is_calibrating;
394 UpdateTouchTransformer();
395 }
396
229 } // namespace ash 397 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698