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

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: Sync with ToT Created 3 years, 12 months 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,
sadrul 2016/12/20 17:31:05 const&
malaykeshav 2016/12/20 19:16:56 They are being modified on line #57
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
sadrul 2016/12/20 17:31:05 Just // NOTE:
malaykeshav 2016/12/20 19:16:56 Done
96 // only solution is to restart touch calibration and get new points from user.
97 CHECK(product_matrix.invert(&product_matrix_inverse));
sadrul 2016/12/20 17:31:05 How does a user recover from this error? i.e. how
malaykeshav 2016/12/20 19:16:56 The user has to go to settings>display>touch calib
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 gfx::Transform ctm,
sadrul 2016/12/20 17:31:05 const & Make a copy in the function body that you
malaykeshav 2016/12/20 19:16:56 Done
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 auto current_size = gfx::SizeF(display.bounds_in_native().size());
sadrul 2016/12/20 17:31:05 gfx::SizeF current_size(display.bounds_in_native()
malaykeshav 2016/12/20 19:16:56 done
125
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 should
89 ctm.Translate(display.bounds_in_native().x(), display.bounds_in_native().y()); 204 // 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());
sadrul 2016/12/20 17:31:05 {}
malaykeshav 2016/12/20 19:16:56 done
90 #endif 208 #endif
91 209
92 // Take care of panel fitting only if supported. Panel fitting is emulated in 210 // If the device is currently under calibration, then do not return any
93 // software mirroring mode (display != touch_display). 211 // 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 212 if (is_calibrating_)
95 // display is scaled acordingly. In this case blank regions would be present 213 return ctm;
96 // in order to center the displayed area. 214
97 if (display.is_aspect_preserving_scaling() || 215 // If touch calibration data is unavailable, use naive approach.
98 display.id() != touch_display.id()) { 216 if (!touch_display.has_touch_calibration_data()) {
99 float touch_native_ar = 217 return GetUncalibratedTransform(ctm, display, touch_display, touch_area,
100 touch_native_size.width() / touch_native_size.height(); 218 touch_native_size);
219 }
220
221 // The resolution at which the touch calibration was performed.
222 gfx::SizeF touch_calib_size(touch_display.GetTouchCalibrationData().bounds);
223
224 // Any additional transfomration that needs to be applied to the display
225 // points, before we solve for the final transform.
226 gfx::Transform pre_transform;
227
228 if (display.id() != touch_display.id() ||
229 display.is_aspect_preserving_scaling()) {
230 // Case of displays being mirrored or in panel fitting mode.
231 // Aspect ratio of the touch display's resolution during calibration.
232 float calib_ar = touch_calib_size.width() / touch_calib_size.height();
233 // Aspect ratio of the display that is being mirrored.
101 float current_ar = current_size.width() / current_size.height(); 234 float current_ar = current_size.width() / current_size.height();
102 235
103 if (current_ar > touch_native_ar) { // Letterboxing 236 if (current_ar < calib_ar) {
104 ctm.Translate( 237 pre_transform.Scale(current_size.height() / touch_calib_size.height(),
105 0, (1 - current_ar / touch_native_ar) * 0.5 * current_size.height()); 238 current_size.height() / touch_calib_size.height());
106 ctm.Scale(1, current_ar / touch_native_ar); 239 pre_transform.Translate(
107 } else if (touch_native_ar > current_ar) { // Pillarboxing 240 (current_ar / calib_ar - 1.f) * touch_calib_size.width() * 0.5f, 0);
108 ctm.Translate( 241 } else {
109 (1 - touch_native_ar / current_ar) * 0.5 * current_size.width(), 0); 242 pre_transform.Scale(current_size.width() / touch_calib_size.width(),
110 ctm.Scale(touch_native_ar / current_ar, 1); 243 current_size.width() / touch_calib_size.width());
244 pre_transform.Translate(
245 0, (calib_ar / current_ar - 1.f) * touch_calib_size.height() * 0.5f);
111 } 246 }
247 } else {
248 // Case of current resolution being different from the resolution when the
249 // touch calibration was performed.
250 pre_transform.Scale(current_size.width() / touch_calib_size.width(),
251 current_size.height() / touch_calib_size.height());
112 } 252 }
253 // Solve for coefficients and compute transform matrix.
254 gfx::Transform stored_ctm = GetCalibratedTransform(
255 touch_display.GetTouchCalibrationData().point_pairs, pre_transform);
113 256
114 // Take care of scaling between touchscreen area and display resolution. 257 stored_ctm.ConcatTransform(ctm);
115 ctm.Scale(current_size.width() / touch_area.width(), 258 return stored_ctm;
116 current_size.height() / touch_area.height());
117 return ctm;
118 } 259 }
119 260
120 TouchTransformerController::TouchTransformerController() { 261 TouchTransformerController::TouchTransformerController() {
121 Shell::GetInstance()->window_tree_host_manager()->AddObserver(this); 262 Shell::GetInstance()->window_tree_host_manager()->AddObserver(this);
122 } 263 }
123 264
124 TouchTransformerController::~TouchTransformerController() { 265 TouchTransformerController::~TouchTransformerController() {
125 Shell::GetInstance()->window_tree_host_manager()->RemoveObserver(this); 266 Shell::GetInstance()->window_tree_host_manager()->RemoveObserver(this);
126 } 267 }
127 268
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 } 360 }
220 361
221 void TouchTransformerController::OnDisplaysInitialized() { 362 void TouchTransformerController::OnDisplaysInitialized() {
222 UpdateTouchTransformer(); 363 UpdateTouchTransformer();
223 } 364 }
224 365
225 void TouchTransformerController::OnDisplayConfigurationChanged() { 366 void TouchTransformerController::OnDisplayConfigurationChanged() {
226 UpdateTouchTransformer(); 367 UpdateTouchTransformer();
227 } 368 }
228 369
370 void TouchTransformerController::SetForCalibration(bool is_calibrating) {
371 is_calibrating_ = is_calibrating;
372 UpdateTouchTransformer();
373 }
374
229 } // namespace ash 375 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698