xref: /aosp_15_r20/external/libchrome-gestures/src/scaling_filter_interpreter_unittest.cc (revision aed3e5085e770be5b69ce25295ecf6ddf906af95)
1 // Copyright 2011 The ChromiumOS Authors
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 <deque>
6 #include <math.h>
7 #include <memory>
8 #include <vector>
9 #include <utility>
10 
11 #include <gtest/gtest.h>
12 
13 #include "include/gestures.h"
14 #include "include/scaling_filter_interpreter.h"
15 #include "include/unittest_util.h"
16 #include "include/util.h"
17 
18 using std::deque;
19 using std::make_pair;
20 using std::pair;
21 
22 namespace gestures {
23 
24 class ScalingFilterInterpreterTest : public ::testing::Test {};
25 
26 class ScalingFilterInterpreterTestInterpreter : public Interpreter {
27  public:
ScalingFilterInterpreterTestInterpreter()28   ScalingFilterInterpreterTestInterpreter()
29       : Interpreter(nullptr, nullptr, false), initialize_called_(false) {}
30 
SyncInterpret(HardwareState & hwstate,stime_t * timeout)31   virtual void SyncInterpret(HardwareState& hwstate, stime_t* timeout) {
32     if (!expected_coordinates_.empty()) {
33       std::vector<pair<float, float> >& expected =
34           expected_coordinates_.front();
35       for (unsigned short i = 0; i < hwstate.finger_cnt; i++) {
36         EXPECT_FLOAT_EQ(expected[i].first, hwstate.fingers[i].position_x)
37             << "i = " << i;
38         EXPECT_FLOAT_EQ(expected[i].second, hwstate.fingers[i].position_y)
39             << "i = " << i;
40       }
41       expected_coordinates_.pop_front();
42     }
43     if (!expected_orientation_.empty()) {
44       const std::vector<float>& expected = expected_orientation_.front();
45       EXPECT_EQ(expected.size(), hwstate.finger_cnt);
46       for (size_t i = 0; i < hwstate.finger_cnt; i++)
47         EXPECT_FLOAT_EQ(expected[i], hwstate.fingers[i].orientation)
48             << "i=" << i;
49       expected_orientation_.pop_front();
50     }
51     if (!expected_touch_major_.empty()) {
52       const std::vector<float>& expected = expected_touch_major_.front();
53       EXPECT_EQ(expected.size(), hwstate.finger_cnt);
54       for (size_t i = 0; i < hwstate.finger_cnt; i++)
55         EXPECT_FLOAT_EQ(expected[i], hwstate.fingers[i].touch_major)
56             << "i=" << i;
57       expected_touch_major_.pop_front();
58     }
59     if (!expected_touch_minor_.empty()) {
60       const std::vector<float>& expected = expected_touch_minor_.front();
61       EXPECT_EQ(expected.size(), hwstate.finger_cnt);
62       for (size_t i = 0; i < hwstate.finger_cnt; i++)
63         EXPECT_FLOAT_EQ(expected[i], hwstate.fingers[i].touch_minor)
64             << "i=" << i;
65       expected_touch_minor_.pop_front();
66     }
67     if (!expected_pressures_.empty() && hwstate.finger_cnt > 0) {
68       EXPECT_FLOAT_EQ(expected_pressures_.front(),
69                       hwstate.fingers[0].pressure);
70       expected_pressures_.pop_front();
71     } else if (!expected_finger_cnt_.empty() && !expected_touch_cnt_.empty()) {
72       // Test if the low pressure event is dropped
73       EXPECT_EQ(expected_finger_cnt_.front(), hwstate.finger_cnt);
74       expected_finger_cnt_.pop_front();
75       EXPECT_EQ(expected_touch_cnt_.front(), hwstate.touch_cnt);
76       expected_touch_cnt_.pop_front();
77     }
78     if (return_values_.empty())
79       return;
80     return_value_ = return_values_.front();
81     return_values_.pop_front();
82     if (return_value_.type == kGestureTypeNull)
83       return;
84     ProduceGesture(return_value_);
85   }
86 
HandleTimer(stime_t now,stime_t * timeout)87   virtual void HandleTimer(stime_t now, stime_t* timeout) {
88     EXPECT_TRUE(false);
89   }
90 
Initialize(const HardwareProperties * hw_props,Metrics * metrics,MetricsProperties * mprops,GestureConsumer * consumer)91   virtual void Initialize(const HardwareProperties* hw_props,
92                           Metrics* metrics,
93                           MetricsProperties* mprops,
94                           GestureConsumer* consumer) {
95     EXPECT_FLOAT_EQ(expected_hwprops_.left, hw_props->left);
96     EXPECT_FLOAT_EQ(expected_hwprops_.top, hw_props->top);
97     EXPECT_FLOAT_EQ(expected_hwprops_.right, hw_props->right);
98     EXPECT_FLOAT_EQ(expected_hwprops_.bottom, hw_props->bottom);
99     EXPECT_FLOAT_EQ(expected_hwprops_.res_x, hw_props->res_x);
100     EXPECT_FLOAT_EQ(expected_hwprops_.res_y, hw_props->res_y);
101     EXPECT_FLOAT_EQ(expected_hwprops_.orientation_minimum,
102                     hw_props->orientation_minimum);
103     EXPECT_FLOAT_EQ(expected_hwprops_.orientation_maximum,
104                     hw_props->orientation_maximum);
105     EXPECT_EQ(expected_hwprops_.max_finger_cnt, hw_props->max_finger_cnt);
106     EXPECT_EQ(expected_hwprops_.max_touch_cnt, hw_props->max_touch_cnt);
107     EXPECT_EQ(expected_hwprops_.supports_t5r2, hw_props->supports_t5r2);
108     EXPECT_EQ(expected_hwprops_.support_semi_mt, hw_props->support_semi_mt);
109     EXPECT_EQ(expected_hwprops_.is_button_pad, hw_props->is_button_pad);
110     initialize_called_ = true;
111     Interpreter::Initialize(hw_props, metrics, mprops, consumer);
112   };
113 
114   Gesture return_value_;
115   deque<Gesture> return_values_;
116   deque<std::vector<pair<float, float> > > expected_coordinates_;
117   deque<std::vector<float> > expected_orientation_;
118   deque<std::vector<float> > expected_touch_major_;
119   deque<std::vector<float> > expected_touch_minor_;
120   deque<float> expected_pressures_;
121   deque<int> expected_finger_cnt_;
122   deque<int> expected_touch_cnt_;
123   HardwareProperties expected_hwprops_;
124   bool initialize_called_;
125 };
126 
TEST(ScalingFilterInterpreterTest,SimpleTest)127 TEST(ScalingFilterInterpreterTest, SimpleTest) {
128   ScalingFilterInterpreterTestInterpreter* base_interpreter =
129       new ScalingFilterInterpreterTestInterpreter;
130   ScalingFilterInterpreter interpreter(nullptr, base_interpreter, nullptr,
131                                        GESTURES_DEVCLASS_TOUCHPAD);
132   HardwareProperties initial_hwprops = {
133     .left = 133, .top = 728, .right = 10279, .bottom = 5822,
134     .res_x = (10279.0 - 133.0) / 100.0,
135     .res_y = (5822.0 - 728.0) / 60,
136     .orientation_minimum = -1,
137     .orientation_maximum = 2,
138     .max_finger_cnt = 2, .max_touch_cnt = 5,
139     .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0,
140     .has_wheel = 0, .wheel_is_hi_res = 0,
141     .is_haptic_pad = 0,
142   };
143   HardwareProperties expected_hwprops = {
144     .right = 100, .bottom = 60,
145     .res_x = 1.0,
146     .res_y = 1.0,
147     .orientation_minimum = -M_PI_4,  // (1 tick above X-axis)
148     .orientation_maximum = M_PI_2,
149     .max_finger_cnt = 2, .max_touch_cnt = 5,
150     .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0,
151     .has_wheel = 0, .wheel_is_hi_res = 0,
152     .is_haptic_pad = 0,
153   };
154   base_interpreter->expected_hwprops_ = expected_hwprops;
155 
156   TestInterpreterWrapper wrapper(&interpreter, &initial_hwprops);
157   EXPECT_TRUE(base_interpreter->initialize_called_);
158   const float kPressureScale = 2.0;
159   const float kPressureTranslate = 3.0;
160   const float kPressureThreshold = 10.0;
161   interpreter.pressure_scale_.val_ = kPressureScale;
162   interpreter.pressure_translate_.val_ = kPressureTranslate;
163   const float kTpYBias = -2.8;
164   interpreter.tp_y_bias_.val_ = kTpYBias;
165 
166   FingerState fs[] = {
167     { 1, 0, 0, 0, 1, 0, 150, 4000, 1, 0 },
168     { 0, 0, 0, 0, 2, 0, 550, 2000, 1, 0 },
169     { 0, 0, 0, 0, 3, 0, 250, 3000, 1, 0 },
170     { 0, 0, 0, 0, 3, 0, 250, 3000, 1, 0 }
171   };
172   HardwareState hs[] = {
173     make_hwstate(10000, 0, 1, 1, &fs[0]),
174     make_hwstate(54000, 0, 1, 1, &fs[1]),
175     make_hwstate(98000, 0, 1, 1, &fs[2]),
176     make_hwstate(99000, 0, 1, 1, &fs[3]),
177   };
178 
179   // Set up expected translated coordinates
180   base_interpreter->expected_coordinates_.push_back(
181       std::vector<pair<float, float> >(1, make_pair(
182           static_cast<float>(100.0 * (150.0 - 133.0) / (10279.0 - 133.0)),
183           static_cast<float>(60.0 * (4000.0 - 728.0) / (5822.0 - 728.0)))));
184   base_interpreter->expected_coordinates_.push_back(
185       std::vector<pair<float, float> >(1, make_pair(
186           static_cast<float>(100.0 * (550.0 - 133.0) / (10279.0 - 133.0)),
187           static_cast<float>(60.0 * (2000.0 - 728.0) / (5822.0 - 728.0)))));
188   base_interpreter->expected_coordinates_.push_back(
189       std::vector<pair<float, float> >(1, make_pair(
190           static_cast<float>(100.0 * (250.0 - 133.0) / (10279.0 - 133.0)),
191           static_cast<float>(60.0 * (3000.0 - 728.0) / (5822.0 - 728.0)))));
192   base_interpreter->expected_coordinates_.push_back(
193       std::vector<pair<float, float> >(1, make_pair(
194           static_cast<float>(100.0 * (250.0 - 133.0) / (10279.0 - 133.0)),
195           static_cast<float>(60.0 * (3000.0 - 728.0) / (5822.0 - 728.0)))));
196 
197   base_interpreter->expected_pressures_.push_back(
198       fs[0].pressure * kPressureScale + kPressureTranslate);
199   base_interpreter->expected_pressures_.push_back(
200       fs[1].pressure * kPressureScale + kPressureTranslate);
201   base_interpreter->expected_pressures_.push_back(
202       fs[2].pressure * kPressureScale + kPressureTranslate);
203   base_interpreter->expected_pressures_.push_back(
204       fs[3].pressure * kPressureScale + kPressureTranslate);
205 
206   base_interpreter->expected_touch_major_.push_back(
207       std::vector<float>(1, interpreter.tp_y_scale_ *
208                        (fs[0].touch_major - kTpYBias)));
209 
210   // Set up gestures to return
211   base_interpreter->return_values_.push_back(Gesture());  // Null type
212   base_interpreter->return_values_.push_back(Gesture(kGestureMove,
213                                                      0,  // start time
214                                                      0,  // end time
215                                                      -4,  // dx
216                                                      2.8));  // dy
217   base_interpreter->return_values_.push_back(Gesture(kGestureScroll,
218                                                      0,  // start time
219                                                      0,  // end time
220                                                      4.1,  // dx
221                                                      -10.3));  // dy
222   base_interpreter->return_values_.push_back(Gesture(kGestureFling,
223                                                      0,  // start time
224                                                      0,  // end time
225                                                      201.8,  // dx
226                                                      -112.4,  // dy
227                                                      GESTURES_FLING_START));
228   base_interpreter->return_values_.push_back(Gesture());  // Null type
229 
230   Gesture* out = wrapper.SyncInterpret(hs[0], nullptr);
231   ASSERT_EQ(nullptr, out);
232   out = wrapper.SyncInterpret(hs[1], nullptr);
233   ASSERT_NE(nullptr, out);
234   EXPECT_EQ(kGestureTypeMove, out->type);
235   EXPECT_FLOAT_EQ(-4.0 * 133.0 / 25.4, out->details.move.dx);
236   EXPECT_FLOAT_EQ(2.8 * 133.0 / 25.4, out->details.move.dy);
237   out = wrapper.SyncInterpret(hs[2], nullptr);
238   ASSERT_NE(nullptr, out);
239   EXPECT_EQ(kGestureTypeScroll, out->type);
240   EXPECT_FLOAT_EQ(-4.1 * 133.0 / 25.4, out->details.scroll.dx);
241   EXPECT_FLOAT_EQ(10.3 * 133.0 / 25.4, out->details.scroll.dy);
242   out = wrapper.SyncInterpret(hs[3], nullptr);
243   ASSERT_NE(nullptr, out);
244   EXPECT_EQ(kGestureTypeFling, out->type);
245   EXPECT_FLOAT_EQ(-201.8 * 133.0 / 25.4, out->details.fling.vx);
246   EXPECT_FLOAT_EQ(112.4 * 133.0 / 25.4, out->details.fling.vy);
247   EXPECT_EQ(GESTURES_FLING_START, out->details.fling.fling_state);
248 
249   // Test if we will drop the low pressure event.
250   FingerState fs2[] = {
251     { 0, 0, 0, 0, 1, 0, 150, 4000, 2, 0 },
252     { 0, 0, 0, 0, 4, 0, 550, 2000, 2, 0 },
253     { 0, 0, 0, 0, 1, 0, 560, 2000, 2, 0 },
254   };
255   HardwareState hs2[] = {
256     make_hwstate(110000, 0, 1, 2, &fs2[0]),
257     make_hwstate(154000, 0, 1, 1, &fs2[1]),
258     make_hwstate(184000, 0, 1, 0, &fs2[2]),
259   };
260   interpreter.pressure_threshold_.val_ = kPressureThreshold;
261   base_interpreter->expected_finger_cnt_.push_back(0);
262   base_interpreter->expected_touch_cnt_.push_back(1);
263   out = wrapper.SyncInterpret(hs2[0], nullptr);
264 
265   base_interpreter->expected_pressures_.push_back(
266       fs2[1].pressure * kPressureScale + kPressureTranslate);
267   out = wrapper.SyncInterpret(hs2[1], nullptr);
268 
269   base_interpreter->expected_finger_cnt_.push_back(0);
270   base_interpreter->expected_touch_cnt_.push_back(0);
271   out = wrapper.SyncInterpret(hs2[2], nullptr);
272 }
273 
TEST(ScalingFilterInterpreterTest,ResolutionFallback)274 TEST(ScalingFilterInterpreterTest, ResolutionFallback) {
275   ScalingFilterInterpreterTestInterpreter* base_interpreter =
276       new ScalingFilterInterpreterTestInterpreter;
277   ScalingFilterInterpreter interpreter(nullptr, base_interpreter, nullptr,
278                                        GESTURES_DEVCLASS_TOUCHPAD);
279   HardwareProperties initial_hwprops = {
280     .right = 2000, .bottom = 1000,
281     .res_x = 0, .res_y = 0,
282     .orientation_minimum = -1,
283     .orientation_maximum = 2,
284     .max_finger_cnt = 2, .max_touch_cnt = 5,
285     .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0,
286     .has_wheel = 0, .wheel_is_hi_res = 0,
287     .is_haptic_pad = 0,
288   };
289   HardwareProperties expected_hwprops = {
290     .right = 2000 / 32.0, .bottom = 1000 / 32.0,
291     .res_x = 1, .res_y = 1,
292     .orientation_minimum = -M_PI_4,  // (1 tick above X-axis)
293     .orientation_maximum = M_PI_2,
294     .max_finger_cnt = 2, .max_touch_cnt = 5,
295     .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0,
296     .has_wheel = 0, .wheel_is_hi_res = 0,
297     .is_haptic_pad = 0,
298   };
299   base_interpreter->expected_hwprops_ = expected_hwprops;
300 
301   TestInterpreterWrapper wrapper(&interpreter, &initial_hwprops);
302   EXPECT_TRUE(base_interpreter->initialize_called_);
303 
304   FingerState fs = { 1, 0, 0, 0, 1, 0, 1000, 500, 1, 0 };
305   HardwareState hs = make_hwstate(10000, 0, 1, 1, &fs);
306 
307   base_interpreter->expected_coordinates_.push_back(
308       std::vector<pair<float, float>>(1, make_pair(
309           static_cast<float>(1000 / 32.0), static_cast<float>(500 / 32.0))));
310 
311   wrapper.SyncInterpret(hs, nullptr);
312 }
313 
RunTouchMajorAndMinorTest(ScalingFilterInterpreterTestInterpreter * base_interpreter,ScalingFilterInterpreter * interpreter,HardwareProperties * hwprops,HardwareProperties * expected_hwprops,FingerState * fs,size_t n_fs,float e_x,float e_y)314 static void RunTouchMajorAndMinorTest(
315     ScalingFilterInterpreterTestInterpreter* base_interpreter,
316     ScalingFilterInterpreter* interpreter,
317     HardwareProperties *hwprops,
318     HardwareProperties *expected_hwprops,
319     FingerState *fs,
320     size_t n_fs,
321     float e_x,
322     float e_y) {
323 
324   const float r_x_2 = 1.0 / hwprops->res_x / hwprops->res_x;
325   const float r_y_2 = 1.0 / hwprops->res_y / hwprops->res_y;
326 
327   float orientation, touch_major, touch_minor, pressure;
328 
329   std::unique_ptr<bool[]> has_zero_area(new bool[n_fs]);
330 
331   for (size_t i = 0; i < n_fs; i++) {
332     bool no_orientation = hwprops->orientation_maximum == 0;
333     float cos_2, sin_2, touch_major_bias, touch_minor_bias;
334     if (no_orientation)
335       orientation = 0;
336     else
337       orientation = M_PI * fs[i].orientation /
338           (hwprops->orientation_maximum - hwprops->orientation_minimum + 1);
339     cos_2 = cosf(orientation) * cosf(orientation);
340     sin_2 = sinf(orientation) * sinf(orientation);
341     touch_major_bias = e_x * sin_2 + e_y * cos_2;
342     touch_minor_bias = e_x * cos_2 + e_y * sin_2;
343     if (fs[i].touch_major)
344       touch_major = fabsf(fs[i].touch_major - touch_major_bias) *
345                     sqrtf(r_x_2 * sin_2 + r_y_2 * cos_2);
346     else
347       touch_major = 0.0;
348     if (fs[i].touch_minor)
349       touch_minor = fabsf(fs[i].touch_minor - touch_minor_bias) *
350                     sqrtf(r_x_2 * cos_2 + r_y_2 * sin_2);
351     else
352       touch_minor = 0.0;
353     if (!no_orientation && touch_major < touch_minor) {
354       std::swap(touch_major, touch_minor);
355       if (orientation > 0.0)
356         orientation -= M_PI_2;
357       else
358         orientation += M_PI_2;
359     }
360     if (touch_major && touch_minor)
361       pressure = M_PI_4 * touch_major * touch_minor;
362     else if (touch_major)
363       pressure = M_PI_4 * touch_major * touch_major;
364     else
365       pressure = 0;
366 
367     has_zero_area[i] = pressure == 0.0;
368 
369     pressure = std::max(pressure , 1.0f);
370 
371     if (has_zero_area[i]) {
372       base_interpreter->expected_orientation_.push_back(
373           std::vector<float>(0));
374       base_interpreter->expected_touch_major_.push_back(
375           std::vector<float>(0));
376       base_interpreter->expected_touch_minor_.push_back(
377           std::vector<float>(0));
378       base_interpreter->expected_finger_cnt_.push_back(0);
379       base_interpreter->expected_touch_cnt_.push_back(0);
380     } else {
381       base_interpreter->expected_orientation_.push_back(
382           std::vector<float>(1, orientation));
383       base_interpreter->expected_touch_major_.push_back(
384           std::vector<float>(1, touch_major));
385       base_interpreter->expected_touch_minor_.push_back(
386           std::vector<float>(1, touch_minor));
387       base_interpreter->expected_pressures_.push_back(pressure);
388     }
389   }
390 
391   base_interpreter->expected_hwprops_ = *expected_hwprops;
392   interpreter->Initialize(hwprops, nullptr, nullptr, nullptr);
393   EXPECT_TRUE(base_interpreter->initialize_called_);
394 
395   for (size_t i = 0; i < n_fs; i++) {
396     HardwareState hs;
397     memset(&hs, 0x0, sizeof(hs));
398     hs.timestamp = (i + 1) * 1000;
399     if (has_zero_area[i]) {
400       hs.finger_cnt = 0;
401       hs.touch_cnt = 0;
402     } else {
403       hs.finger_cnt = 1;
404       hs.touch_cnt = 1;
405     }
406     hs.fingers = fs + i;
407     interpreter->SyncInterpret(hs, nullptr);
408   }
409 
410   // Tear down state
411   base_interpreter->initialize_called_ = false;
412 }
413 
TEST(ScalingFilterInterpreterTest,TouchMajorAndMinorTest)414 TEST(ScalingFilterInterpreterTest, TouchMajorAndMinorTest) {
415   ScalingFilterInterpreterTestInterpreter* base_interpreter =
416       new ScalingFilterInterpreterTestInterpreter;
417   ScalingFilterInterpreter interpreter(nullptr, base_interpreter, nullptr,
418                                        GESTURES_DEVCLASS_TOUCHPAD);
419 
420   const float e_x = 17;
421   const float e_y = 71;
422   const bool kFilterLowPressure = 1;
423 
424   interpreter.surface_area_from_pressure_.val_ = false;
425   interpreter.filter_low_pressure_.val_ = kFilterLowPressure;
426   interpreter.tp_x_bias_.val_ = e_x;
427   interpreter.tp_y_bias_.val_ = e_y;
428 
429   HardwareProperties hwprops = {
430     .right = 500, .bottom = 1000,
431     .res_x = 5,
432     .res_y = 10,
433     .orientation_minimum = -31,
434     .orientation_maximum = 32,
435     .max_finger_cnt = 2, .max_touch_cnt = 5,
436     .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0,
437     .has_wheel = 1, .wheel_is_hi_res = 0,
438     .is_haptic_pad = 0,
439   };
440   HardwareProperties expected_hwprops = {
441     .right = 100, .bottom = 100,
442     .res_x = 1.0, .res_y = 1.0,
443     .orientation_minimum = -M_PI * 31 / 64,  // (1 tick above X-axis)
444     .orientation_maximum = M_PI_2,
445     .max_finger_cnt = 2, .max_touch_cnt = 5,
446     .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0,
447     .has_wheel = 1, .wheel_is_hi_res = 0,
448     .is_haptic_pad = 0,
449   };
450 
451   // Test 1: Touch major and touch minor scaling with orientation
452   // range [-31, 32].
453 
454   hwprops.orientation_minimum = -31;
455   hwprops.orientation_maximum = 32;
456   expected_hwprops.orientation_minimum =
457       M_PI * hwprops.orientation_minimum /
458       (hwprops.orientation_maximum - hwprops.orientation_minimum + 1);
459   expected_hwprops.orientation_maximum =
460       M_PI * hwprops.orientation_maximum /
461       (hwprops.orientation_maximum - hwprops.orientation_minimum + 1);
462 
463   FingerState test_1_fs[] = {
464     {  0.0,  0.0, 0, 0, 0,   0.0, 0, 0, 1, 0 },
465 
466     { 79.0, 99.0, 0, 0, 0,  16.0, 0, 0, 1, 0 },
467 
468     { 79.0, 31.0, 0, 0, 0, -16.0, 0, 0, 1, 0 },
469     { 79.0, 31.0, 0, 0, 0,   0.0, 0, 0, 1, 0 },
470     { 79.0, 31.0, 0, 0, 0,  16.0, 0, 0, 1, 0 },
471     { 79.0, 31.0, 0, 0, 0,  32.0, 0, 0, 1, 0 },
472 
473     { 79.0,  0.0, 0, 0, 0, -16.0, 0, 0, 1, 0 },
474     { 79.0,  0.0, 0, 0, 0,   0.0, 0, 0, 1, 0 },
475     { 79.0,  0.0, 0, 0, 0,  16.0, 0, 0, 1, 0 },
476     { 79.0,  0.0, 0, 0, 0,  32.0, 0, 0, 1, 0 },
477   };
478 
479   RunTouchMajorAndMinorTest(base_interpreter,
480                             &interpreter,
481                             &hwprops,
482                             &expected_hwprops,
483                             test_1_fs,
484                             arraysize(test_1_fs),
485                             e_x,
486                             e_y);
487 
488   // Test 2: Touch major and touch minor scaling with orientation
489   // range [0, 1].
490 
491   hwprops.orientation_minimum = 0;
492   hwprops.orientation_maximum = 1;
493   expected_hwprops.orientation_minimum = 0;
494   expected_hwprops.orientation_maximum = M_PI_2;
495 
496   FingerState test_2_fs[] = {
497     {  0.0,  0.0, 0, 0, 0, 0.0, 0, 0, 1, 0 },
498 
499     { 79.0, 31.0, 0, 0, 0, 0.0, 0, 0, 1, 0 },
500     { 79.0, 31.0, 0, 0, 0, 1.0, 0, 0, 1, 0 },
501 
502     { 79.0,  0.0, 0, 0, 0, 0.0, 0, 0, 1, 0 },
503     { 79.0,  0.0, 0, 0, 0, 1.0, 0, 0, 1, 0 },
504   };
505 
506   RunTouchMajorAndMinorTest(base_interpreter,
507                             &interpreter,
508                             &hwprops,
509                             &expected_hwprops,
510                             test_2_fs,
511                             arraysize(test_2_fs),
512                             e_x,
513                             e_y);
514 
515   // Test 3: Touch major and touch minor scaling with no orientation
516   // provided.
517 
518   hwprops.orientation_minimum = 0;
519   hwprops.orientation_maximum = 0;
520   expected_hwprops.orientation_minimum = 0;
521   expected_hwprops.orientation_maximum = 0;
522 
523   FingerState test_3_fs[] = {
524     {  0.0,  0.0, 0, 0, 0, 0.0, 0, 0, 1, 0 },
525 
526     { 79.0, 31.0, 0, 0, 0, 0.0, 0, 0, 1, 0 },
527 
528     { 79.0,  0.0, 0, 0, 0, 0.0, 0, 0, 1, 0 },
529   };
530 
531   RunTouchMajorAndMinorTest(base_interpreter,
532                             &interpreter,
533                             &hwprops,
534                             &expected_hwprops,
535                             test_3_fs,
536                             arraysize(test_3_fs),
537                             e_x,
538                             e_y);
539 }
540 
541 }  // namespace gestures
542