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

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: Resolving comments 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 returns the corresponding
46 // transform matrix.
47 // See http://crbug.com/672293
48 gfx::Transform GetCalibratedTransform(
49 std::array<std::pair<gfx::Point, gfx::Point>, 4> touch_point_pairs,
50 const gfx::Transform& pre_calibration_tm) {
51 // Transform the display points before solving the equation.
52 // If the calibration was performed at a resolution that is 0.5 times the
53 // current resolution, then the display points (x, y) for a given touch point
54 // now represents a display point at (2 * x, 2 * y). This and other kinds of
55 // similar tranforms can be applied using |pre_calibration_tm|.
56 for (int row = 0; row < 4; row++)
57 pre_calibration_tm.TransformPoint(&touch_point_pairs[row].first);
58
59 // Vector of the X-coordinate of display points corresponding to each of the
60 // touch points.
61 SkVector4 display_points_x(
62 touch_point_pairs[0].first.x(), touch_point_pairs[1].first.x(),
63 touch_point_pairs[2].first.x(), touch_point_pairs[3].first.x());
64 // Vector of the Y-coordinate of display points corresponding to each of the
65 // touch points.
66 SkVector4 display_points_y(
67 touch_point_pairs[0].first.y(), touch_point_pairs[1].first.y(),
68 touch_point_pairs[2].first.y(), touch_point_pairs[3].first.y());
69
70 // Initialize |touch_point_matrix|
71 // If {(xt_1, yt_1), (xt_2, yt_2), (xt_3, yt_3)....} are a set of touch points
72 // received during calibration, then the |touch_point_matrix| would be defined
73 // as:
74 // |xt_1 yt_1 1 0|
75 // |xt_2 yt_2 1 0|
76 // |xt_3 yt_3 1 0|
77 // |xt_4 yt_4 1 0|
78 SkMatrix44 touch_point_matrix;
79 for (int row = 0; row < 4; row++) {
80 touch_point_matrix.set(row, 0, touch_point_pairs[row].second.x());
81 touch_point_matrix.set(row, 1, touch_point_pairs[row].second.y());
82 touch_point_matrix.set(row, 2, 1);
83 touch_point_matrix.set(row, 3, 0);
84 }
85 SkMatrix44 touch_point_matrix_transpose(touch_point_matrix);
86 touch_point_matrix_transpose.transpose();
87
88 SkMatrix44 product_matrix = touch_point_matrix_transpose * touch_point_matrix;
89
90 // Set (3, 3) = 1 so that |determinent| of the matrix is != 0 and the inverse
91 // can be calculated.
92 product_matrix.set(3, 3, 1);
93
94 SkMatrix44 product_matrix_inverse;
95 // NOTE: If the determinent is zero then the inverse cannot be computed. The
96 // only solution is to restart touch calibration and get new points from user.
97 CHECK(product_matrix.invert(&product_matrix_inverse));
malaykeshav 2016/12/20 19:34:56 A safer way to do this would be to add an if condi
sadrul 2016/12/21 02:09:50 My understanding is, if this CHECK does trigger, t
malaykeshav 2016/12/21 02:13:52 Yes there would be no way to recover for the user.
malaykeshav 2016/12/21 05:49:42 Done
98
99 product_matrix_inverse.set(3, 3, 0);
100
101 product_matrix = product_matrix_inverse * touch_point_matrix_transpose;
102
103 // Constants [A, B, C, 0] used to calibrate the x-coordinate of touch input.
104 // x_new = x_old * A + y_old * B + C;
105 SkVector4 x_constants = product_matrix * display_points_x;
106 // Constants [D, E, F, 0] used to calibrate the y-coordinate of touch input.
107 // y_new = x_old * D + y_old * E + F;
108 SkVector4 y_constants = product_matrix * display_points_y;
109
110 // Create a transform matrix using the touch calibration data.
111 return gfx::Transform(x_constants.fData[0], x_constants.fData[1], 0,
112 x_constants.fData[2], y_constants.fData[0],
113 y_constants.fData[1], 0, y_constants.fData[2], 0, 0, 1,
114 0, 0, 0, 0, 1);
115 }
116
117 // Returns an uncalibrated touch transform.
118 gfx::Transform GetUncalibratedTransform(
119 const gfx::Transform& tm,
120 const display::ManagedDisplayInfo& display,
121 const display::ManagedDisplayInfo& touch_display,
122 const gfx::SizeF& touch_area,
123 const gfx::SizeF& touch_native_size) {
124 gfx::SizeF current_size(display.bounds_in_native().size());
125 gfx::Transform ctm(tm);
126 // Take care of panel fitting only if supported. Panel fitting is emulated
127 // in software mirroring mode (display != touch_display).
128 // If panel fitting is enabled then the aspect ratio is preserved and the
129 // display is scaled acordingly. In this case blank regions would be present
130 // in order to center the displayed area.
131 if (display.is_aspect_preserving_scaling() ||
132 display.id() != touch_display.id()) {
133 float touch_calib_ar =
134 touch_native_size.width() / touch_native_size.height();
135 float current_ar = current_size.width() / current_size.height();
136
137 if (current_ar > touch_calib_ar) { // Letterboxing
138 ctm.Translate(
139 0, (1 - current_ar / touch_calib_ar) * 0.5 * current_size.height());
140 ctm.Scale(1, current_ar / touch_calib_ar);
141 } else if (touch_calib_ar > current_ar) { // Pillarboxing
142 ctm.Translate(
143 (1 - touch_calib_ar / current_ar) * 0.5 * current_size.width(), 0);
144 ctm.Scale(touch_calib_ar / current_ar, 1);
145 }
146 }
147 // Take care of scaling between touchscreen area and display resolution.
148 ctm.Scale(current_size.width() / touch_area.width(),
149 current_size.height() / touch_area.height());
150 return ctm;
151 }
152
38 } // namespace 153 } // namespace
39 154
40 // This is to compute the scale ratio for the TouchEvent's radius. The 155 // 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 156 // 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 157 // screen's reporting resolution, e.g. the display could be set as
43 // 1920x1080 while the touchscreen is reporting touch position range at 158 // 1920x1080 while the touchscreen is reporting touch position range at
44 // 32767x32767. Touch radius is reported in the units the same as touch position 159 // 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 160 // so we need to scale the touch radius to be compatible with the display's
46 // resolution. We compute the scale as 161 // resolution. We compute the scale as
47 // sqrt of (display_area / touchscreen_area) 162 // sqrt of (display_area / touchscreen_area)
(...skipping 30 matching lines...) Expand all
78 auto touch_area = gfx::SizeF(framebuffer_size); 193 auto touch_area = gfx::SizeF(framebuffer_size);
79 #endif 194 #endif
80 195
81 gfx::Transform ctm; 196 gfx::Transform ctm;
82 197
83 if (current_size.IsEmpty() || touch_native_size.IsEmpty() || 198 if (current_size.IsEmpty() || touch_native_size.IsEmpty() ||
84 touch_area.IsEmpty() || touchscreen.id == ui::InputDevice::kInvalidId) 199 touch_area.IsEmpty() || touchscreen.id == ui::InputDevice::kInvalidId)
85 return ctm; 200 return ctm;
86 201
87 #if defined(USE_OZONE) 202 #if defined(USE_OZONE)
88 // Translate the touch so that it falls within the display bounds. 203 // 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()); 204 // should not be performed if the displays are mirrored.
205 if (display.id() == touch_display.id()) {
206 ctm.Translate(display.bounds_in_native().x(),
207 display.bounds_in_native().y());
208 }
90 #endif 209 #endif
91 210
92 // Take care of panel fitting only if supported. Panel fitting is emulated in 211 // If the device is currently under calibration, then do not return any
93 // software mirroring mode (display != touch_display). 212 // 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 213 // calibration.
95 // display is scaled acordingly. In this case blank regions would be present 214 if (is_calibrating_)
96 // in order to center the displayed area. 215 return ctm;
97 if (display.is_aspect_preserving_scaling() || 216
98 display.id() != touch_display.id()) { 217 // If touch calibration data is unavailable, use naive approach.
99 float touch_native_ar = 218 if (!touch_display.has_touch_calibration_data()) {
100 touch_native_size.width() / touch_native_size.height(); 219 return GetUncalibratedTransform(ctm, display, touch_display, touch_area,
220 touch_native_size);
221 }
222
223 // The resolution at which the touch calibration was performed.
224 gfx::SizeF touch_calib_size(touch_display.GetTouchCalibrationData().bounds);
225
226 // Any additional transfomration that needs to be applied to the display
227 // points, before we solve for the final transform.
228 gfx::Transform pre_transform;
229
230 if (display.id() != touch_display.id() ||
231 display.is_aspect_preserving_scaling()) {
232 // Case of displays being mirrored or in panel fitting mode.
233 // Aspect ratio of the touch display's resolution during calibration.
234 float calib_ar = touch_calib_size.width() / touch_calib_size.height();
235 // Aspect ratio of the display that is being mirrored.
101 float current_ar = current_size.width() / current_size.height(); 236 float current_ar = current_size.width() / current_size.height();
102 237
103 if (current_ar > touch_native_ar) { // Letterboxing 238 if (current_ar < calib_ar) {
104 ctm.Translate( 239 pre_transform.Scale(current_size.height() / touch_calib_size.height(),
105 0, (1 - current_ar / touch_native_ar) * 0.5 * current_size.height()); 240 current_size.height() / touch_calib_size.height());
106 ctm.Scale(1, current_ar / touch_native_ar); 241 pre_transform.Translate(
107 } else if (touch_native_ar > current_ar) { // Pillarboxing 242 (current_ar / calib_ar - 1.f) * touch_calib_size.width() * 0.5f, 0);
108 ctm.Translate( 243 } else {
109 (1 - touch_native_ar / current_ar) * 0.5 * current_size.width(), 0); 244 pre_transform.Scale(current_size.width() / touch_calib_size.width(),
110 ctm.Scale(touch_native_ar / current_ar, 1); 245 current_size.width() / touch_calib_size.width());
246 pre_transform.Translate(
247 0, (calib_ar / current_ar - 1.f) * touch_calib_size.height() * 0.5f);
111 } 248 }
249 } else {
250 // Case of current resolution being different from the resolution when the
251 // touch calibration was performed.
252 pre_transform.Scale(current_size.width() / touch_calib_size.width(),
253 current_size.height() / touch_calib_size.height());
112 } 254 }
255 // Solve for coefficients and compute transform matrix.
256 gfx::Transform stored_ctm = GetCalibratedTransform(
257 touch_display.GetTouchCalibrationData().point_pairs, pre_transform);
113 258
114 // Take care of scaling between touchscreen area and display resolution. 259 stored_ctm.ConcatTransform(ctm);
115 ctm.Scale(current_size.width() / touch_area.width(), 260 return stored_ctm;
116 current_size.height() / touch_area.height());
117 return ctm;
118 } 261 }
119 262
120 TouchTransformerController::TouchTransformerController() { 263 TouchTransformerController::TouchTransformerController() {
121 Shell::GetInstance()->window_tree_host_manager()->AddObserver(this); 264 Shell::GetInstance()->window_tree_host_manager()->AddObserver(this);
122 } 265 }
123 266
124 TouchTransformerController::~TouchTransformerController() { 267 TouchTransformerController::~TouchTransformerController() {
125 Shell::GetInstance()->window_tree_host_manager()->RemoveObserver(this); 268 Shell::GetInstance()->window_tree_host_manager()->RemoveObserver(this);
126 } 269 }
127 270
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 } 362 }
220 363
221 void TouchTransformerController::OnDisplaysInitialized() { 364 void TouchTransformerController::OnDisplaysInitialized() {
222 UpdateTouchTransformer(); 365 UpdateTouchTransformer();
223 } 366 }
224 367
225 void TouchTransformerController::OnDisplayConfigurationChanged() { 368 void TouchTransformerController::OnDisplayConfigurationChanged() {
226 UpdateTouchTransformer(); 369 UpdateTouchTransformer();
227 } 370 }
228 371
372 void TouchTransformerController::SetForCalibration(bool is_calibrating) {
373 is_calibrating_ = is_calibrating;
374 UpdateTouchTransformer();
375 }
376
229 } // namespace ash 377 } // namespace ash
OLDNEW
« no previous file with comments | « ash/touch/touch_transformer_controller.h ('k') | ash/touch/touch_transformer_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698