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

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: Added link to crbug in code 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 and returns A, B, C, D, E and F as a pair of
46 // SkVector4.
47 // See http://crbug.com/672293
48 std::pair<SkVector4, SkVector4> SolveCalibrationEquation(
49 std::array<std::pair<gfx::Point, gfx::Point>, 4> touch_point_pairs,
50 const gfx::Transform& pre_calibration_tm) {
51 // If {(xt_1, yt_1), (xt_2, yt_2), (xt_3, yt_3)....} are a set of touch points
52 // received during calibration, then the |touch_point_matrix| would be defined
53 // as:
54 // |xt_1 yt_1 1 0|
55 // |xt_2 yt_2 1 0|
56 // |xt_3 yt_3 1 0|
57 // |xt_4 yt_4 1 0|
58 SkMatrix44 touch_point_matrix;
kylechar 2016/12/19 20:00:21 Can you move variables closer to where they are fi
malaykeshav 2016/12/20 09:56:04 Done
59 SkMatrix44 touch_point_matrix_transpose;
60
61 SkMatrix44 product_matrix;
62 SkMatrix44 product_matrix_inverse;
63
64 // Transform the display points before solving the equation.
65 // If the calibration was performed at a resolution that is 0.5 times the
66 // current resolution, then the display points (x, y) for a given touch point
67 // now represents a display point at (2 * x, 2 * y). This and other kinds of
68 // similar tranforms can be applied using |pre_calibration_tm|.
69 for (int row = 0; row < 4; row++)
70 pre_calibration_tm.TransformPoint(&touch_point_pairs[row].first);
71
72 // Vector of the X-coordinate of display points corresponding to each of the
73 // touch points.
74 SkVector4 display_points_x(
75 touch_point_pairs[0].first.x(), touch_point_pairs[1].first.x(),
76 touch_point_pairs[2].first.x(), touch_point_pairs[3].first.x());
77 // Vector of the Y-coordinate of display points corresponding to each of the
78 // touch points.
79 SkVector4 display_points_y(
80 touch_point_pairs[0].first.y(), touch_point_pairs[1].first.y(),
81 touch_point_pairs[2].first.y(), touch_point_pairs[3].first.y());
82
83 SkVector4 result_constants_x, result_constants_y;
84
85 // Initialize |touch_point_matrix|
86 for (int row = 0; row < 4; row++) {
87 touch_point_matrix.set(row, 0, touch_point_pairs[row].second.x());
88 touch_point_matrix.set(row, 1, touch_point_pairs[row].second.y());
89 touch_point_matrix.set(row, 2, 1);
90 touch_point_matrix.set(row, 3, 0);
91 }
92 touch_point_matrix_transpose = touch_point_matrix;
93 touch_point_matrix_transpose.transpose();
94
95 product_matrix = touch_point_matrix_transpose * touch_point_matrix;
96
97 // Set (3, 3) = 1 so that |determinent| of the matrix is != 0 and the inverse
98 // can be calculated.
99 product_matrix.set(3, 3, 1);
100
101 // #NOTE: If the determinent is zero then the inverse cannot be computed. The
102 // only solution is to restart touch calibration and get new points from user.
103 CHECK(product_matrix.invert(&product_matrix_inverse));
kylechar 2016/12/19 20:00:21 Is crashing the correct thing to do if the inverse
malaykeshav 2016/12/20 09:56:04 This is an extremely rare case since we are using
104
105 product_matrix_inverse.set(3, 3, 0);
106
107 product_matrix = product_matrix_inverse * touch_point_matrix_transpose;
108
109 // Vector containing the constants [A, B, C, 0]
110 result_constants_x = product_matrix * display_points_x;
111 // Vector containing the constants [D, E, F, 0]
112 result_constants_y = product_matrix * display_points_y;
113
114 return std::make_pair(result_constants_x, result_constants_y);
kylechar 2016/12/19 20:00:21 Why doesn't this just return the gfx::Transform yo
malaykeshav 2016/12/20 09:56:04 Done.
115 }
116
38 } // namespace 117 } // namespace
39 118
40 // This is to compute the scale ratio for the TouchEvent's radius. The 119 // 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 120 // 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 121 // screen's reporting resolution, e.g. the display could be set as
43 // 1920x1080 while the touchscreen is reporting touch position range at 122 // 1920x1080 while the touchscreen is reporting touch position range at
44 // 32767x32767. Touch radius is reported in the units the same as touch position 123 // 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 124 // so we need to scale the touch radius to be compatible with the display's
46 // resolution. We compute the scale as 125 // resolution. We compute the scale as
47 // sqrt of (display_area / touchscreen_area) 126 // sqrt of (display_area / touchscreen_area)
(...skipping 24 matching lines...) Expand all
72 auto current_size = gfx::SizeF(display.bounds_in_native().size()); 151 auto current_size = gfx::SizeF(display.bounds_in_native().size());
73 auto touch_native_size = gfx::SizeF(touch_display.GetNativeModeSize()); 152 auto touch_native_size = gfx::SizeF(touch_display.GetNativeModeSize());
74 #if defined(USE_OZONE) 153 #if defined(USE_OZONE)
75 auto touch_area = gfx::SizeF(touchscreen.size); 154 auto touch_area = gfx::SizeF(touchscreen.size);
76 #elif defined(USE_X11) 155 #elif defined(USE_X11)
77 // On X11 touches are reported in the framebuffer coordinate space. 156 // On X11 touches are reported in the framebuffer coordinate space.
78 auto touch_area = gfx::SizeF(framebuffer_size); 157 auto touch_area = gfx::SizeF(framebuffer_size);
79 #endif 158 #endif
80 159
81 gfx::Transform ctm; 160 gfx::Transform ctm;
161 gfx::Transform stored_ctm;
kylechar 2016/12/19 20:00:21 Define variable where you're going to use it.
malaykeshav 2016/12/20 09:56:04 Done.
82 162
83 if (current_size.IsEmpty() || touch_native_size.IsEmpty() || 163 if (current_size.IsEmpty() || touch_native_size.IsEmpty() ||
84 touch_area.IsEmpty() || touchscreen.id == ui::InputDevice::kInvalidId) 164 touch_area.IsEmpty() || touchscreen.id == ui::InputDevice::kInvalidId)
85 return ctm; 165 return ctm;
86 166
87 #if defined(USE_OZONE) 167 #if defined(USE_OZONE)
88 // Translate the touch so that it falls within the display bounds. 168 // Translate the touch so that it falls within the display bounds. This should
89 ctm.Translate(display.bounds_in_native().x(), display.bounds_in_native().y()); 169 // not be performed if the displays are mirrored.
170 if (display.id() == touch_display.id())
171 ctm.Translate(display.bounds_in_native().x(),
172 display.bounds_in_native().y());
90 #endif 173 #endif
91 174
92 // Take care of panel fitting only if supported. Panel fitting is emulated in 175 // If the device is currently under calibration, then do not return any
93 // software mirroring mode (display != touch_display). 176 // transform as we want to use the raw native touch input data for calibration
94 // If panel fitting is enabled then the aspect ratio is preserved and the 177 if (is_calibrating_)
95 // display is scaled acordingly. In this case blank regions would be present 178 return ctm;
96 // in order to center the displayed area. 179 // If touch calibration data is unavailable, use naive approach.
97 if (display.is_aspect_preserving_scaling() || 180 if (!touch_display.has_touch_calibration_data()) {
kylechar 2016/12/19 20:00:21 Could you split this function into something like
malaykeshav 2016/12/20 09:56:04 Splitting the uncalibrated transform and moving to
98 display.id() != touch_display.id()) { 181 // Take care of panel fitting only if supported. Panel fitting is emulated
99 float touch_native_ar = 182 // in software mirroring mode (display != touch_display).
100 touch_native_size.width() / touch_native_size.height(); 183 // If panel fitting is enabled then the aspect ratio is preserved and the
184 // display is scaled acordingly. In this case blank regions would be present
185 // in order to center the displayed area.
186 if (display.is_aspect_preserving_scaling() ||
187 display.id() != touch_display.id()) {
188 float touch_calib_ar =
189 touch_native_size.width() / touch_native_size.height();
190 float current_ar = current_size.width() / current_size.height();
191
192 if (current_ar > touch_calib_ar) { // Letterboxing
193 ctm.Translate(
194 0, (1 - current_ar / touch_calib_ar) * 0.5 * current_size.height());
195 ctm.Scale(1, current_ar / touch_calib_ar);
196 } else if (touch_calib_ar > current_ar) { // Pillarboxing
197 ctm.Translate(
198 (1 - touch_calib_ar / current_ar) * 0.5 * current_size.width(), 0);
199 ctm.Scale(touch_calib_ar / current_ar, 1);
200 }
201 }
202 // Take care of scaling between touchscreen area and display resolution.
203 ctm.Scale(current_size.width() / touch_area.width(),
204 current_size.height() / touch_area.height());
205 return ctm;
206 }
207 // The resolution at which the touch calibration was performed.
208 auto touch_calib_size =
kylechar 2016/12/19 20:00:21 gfx::SizeF touch_calib_size(...)
malaykeshav 2016/12/20 09:56:04 Done
209 gfx::SizeF(touch_display.GetTouchCalibrationData().bounds);
210
211 // Any additional tranfomration that needs to be applied to the display
kylechar 2016/12/19 20:00:21 transformation
malaykeshav 2016/12/20 09:56:04 done
212 // points, before we solve for the final transform.
213 gfx::Transform pre_transform;
214
215 if (display.id() != touch_display.id() ||
216 display.is_aspect_preserving_scaling()) {
217 // Case of displays being mirrored or in panel fitting mode.
218 // Aspect ratio of the touch display's resolution during calibration.
219 float calib_ar = touch_calib_size.width() / touch_calib_size.height();
220 // Aspect ratio of the display that is being mirrored.
101 float current_ar = current_size.width() / current_size.height(); 221 float current_ar = current_size.width() / current_size.height();
102 222
103 if (current_ar > touch_native_ar) { // Letterboxing 223 if (current_ar < calib_ar) {
104 ctm.Translate( 224 pre_transform.Scale(current_size.height() / touch_calib_size.height(),
105 0, (1 - current_ar / touch_native_ar) * 0.5 * current_size.height()); 225 current_size.height() / touch_calib_size.height());
106 ctm.Scale(1, current_ar / touch_native_ar); 226 pre_transform.Translate(
107 } else if (touch_native_ar > current_ar) { // Pillarboxing 227 (current_ar / calib_ar - 1.f) * touch_calib_size.width() * 0.5f, 0);
108 ctm.Translate( 228 } else {
109 (1 - touch_native_ar / current_ar) * 0.5 * current_size.width(), 0); 229 pre_transform.Scale(current_size.width() / touch_calib_size.width(),
110 ctm.Scale(touch_native_ar / current_ar, 1); 230 current_size.width() / touch_calib_size.width());
231 pre_transform.Translate(
232 0, (calib_ar / current_ar - 1.f) * touch_calib_size.height() * 0.5f);
111 } 233 }
234 } else {
235 // Case of current resolution being different from the resolution when the
236 // touch calibration was performed.
237 pre_transform.Scale(current_size.width() / touch_calib_size.width(),
238 current_size.height() / touch_calib_size.height());
112 } 239 }
240 // Calibrate using the calibration data associated with the display.
241 std::pair<SkVector4, SkVector4> result = SolveCalibrationEquation(
kylechar 2016/12/19 20:00:21 Same as above, if this returned the gfx::Transform
malaykeshav 2016/12/20 09:56:04 done
242 touch_display.GetTouchCalibrationData().point_pairs, pre_transform);
113 243
114 // Take care of scaling between touchscreen area and display resolution. 244 // Constants [A, B, C, 0] used to calibrate the x-coordinate of touch input.
115 ctm.Scale(current_size.width() / touch_area.width(), 245 // x_new = x_old * A + y_old * B + C;
116 current_size.height() / touch_area.height()); 246 const SkVector4& x_constants = result.first;
117 return ctm; 247 // Constants [D, E, F, 0] used to calibrate the y-coordinate of touch input.
248 // y_new = x_old * D + y_old * E + F;
249 const SkVector4& y_constants = result.second;
250
251 // Create a transform matrix using the touch calibration data.
252 stored_ctm = gfx::Transform(x_constants.fData[0], x_constants.fData[1], 0,
253 x_constants.fData[2], y_constants.fData[0],
254 y_constants.fData[1], 0, y_constants.fData[2], 0,
255 0, 1, 0, 0, 0, 0, 1);
256 stored_ctm.ConcatTransform(ctm);
257 return stored_ctm;
118 } 258 }
119 259
120 TouchTransformerController::TouchTransformerController() { 260 TouchTransformerController::TouchTransformerController() {
121 Shell::GetInstance()->window_tree_host_manager()->AddObserver(this); 261 Shell::GetInstance()->window_tree_host_manager()->AddObserver(this);
122 } 262 }
123 263
124 TouchTransformerController::~TouchTransformerController() { 264 TouchTransformerController::~TouchTransformerController() {
125 Shell::GetInstance()->window_tree_host_manager()->RemoveObserver(this); 265 Shell::GetInstance()->window_tree_host_manager()->RemoveObserver(this);
126 } 266 }
127 267
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 } 359 }
220 360
221 void TouchTransformerController::OnDisplaysInitialized() { 361 void TouchTransformerController::OnDisplaysInitialized() {
222 UpdateTouchTransformer(); 362 UpdateTouchTransformer();
223 } 363 }
224 364
225 void TouchTransformerController::OnDisplayConfigurationChanged() { 365 void TouchTransformerController::OnDisplayConfigurationChanged() {
226 UpdateTouchTransformer(); 366 UpdateTouchTransformer();
227 } 367 }
228 368
369 void TouchTransformerController::SetForCalibration(bool is_calibrating) {
370 is_calibrating_ = is_calibrating;
371 UpdateTouchTransformer();
372 }
373
229 } // namespace ash 374 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698