1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef UI_EVENTS_OZONE_EVDEV_TOUCH_FILTER_NEURAL_STYLUS_PALM_DETECTION_FILTER_UTIL_H_
6 #define UI_EVENTS_OZONE_EVDEV_TOUCH_FILTER_NEURAL_STYLUS_PALM_DETECTION_FILTER_UTIL_H_
7
8 #include <cstdint>
9 #include <deque>
10 #include <vector>
11
12 #if defined(__ANDROID__) || defined(__ANDROID_HOST__)
13 #undef LOG_INFO
14 #undef LOG_WARNING
15 #include <chrome_to_android_compatibility.h>
16 #endif
17 #include "base/time/time.h"
18 #if !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
19 #include "ui/events/ozone/evdev/event_device_info.h"
20 #endif
21 #include "ui/events/ozone/evdev/touch_evdev_types.h"
22 #include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter_model.h"
23 #include "ui/gfx/geometry/point_f.h"
24
25 namespace ui {
26
COMPONENT_EXPORT(EVDEV)27 struct COMPONENT_EXPORT(EVDEV) PalmFilterDeviceInfo {
28 float max_x = 0.f;
29 float max_y = 0.f;
30 float x_res = 1.f;
31 float y_res = 1.f;
32 float major_radius_res = 1.f;
33 float minor_radius_res = 1.f;
34 bool minor_radius_supported = false;
35 #if defined(__ANDROID__) || defined(__ANDROID_HOST__)
36 auto operator<=>(const PalmFilterDeviceInfo&) const = default;
37 #endif
38 };
39
40 std::ostream& operator<<(std::ostream& out, const PalmFilterDeviceInfo& info);
41
42 #if !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
43 COMPONENT_EXPORT(EVDEV)
44 PalmFilterDeviceInfo CreatePalmFilterDeviceInfo(const EventDeviceInfo& devinfo);
45 #endif
46
47 // Data for a single touch event.
COMPONENT_EXPORT(EVDEV)48 struct COMPONENT_EXPORT(EVDEV) PalmFilterSample {
49 float major_radius = 0;
50 float minor_radius = 0;
51 float pressure = 0;
52 float edge = 0;
53 int tracking_id = 0;
54 gfx::PointF point;
55 base::TimeTicks time;
56
57 bool operator==(const PalmFilterSample& other) const {
58 return major_radius == other.major_radius &&
59 minor_radius == other.minor_radius && pressure == other.pressure &&
60 edge == other.edge && tracking_id == other.tracking_id &&
61 point == other.point && time == other.time;
62 }
63 };
64
65 std::ostream& operator<<(std::ostream& out, const PalmFilterSample& sample);
66
67 COMPONENT_EXPORT(EVDEV)
68 PalmFilterSample CreatePalmFilterSample(
69 const InProgressTouchEvdev& touch,
70 const base::TimeTicks& time,
71 const NeuralStylusPalmDetectionFilterModelConfig& model_config,
72 const PalmFilterDeviceInfo& dev_info);
73
COMPONENT_EXPORT(EVDEV)74 class COMPONENT_EXPORT(EVDEV) PalmFilterStroke {
75 public:
76 explicit PalmFilterStroke(
77 const NeuralStylusPalmDetectionFilterModelConfig& model_config,
78 int tracking_id);
79 PalmFilterStroke(const PalmFilterStroke& other);
80 PalmFilterStroke(PalmFilterStroke&& other);
81 ~PalmFilterStroke();
82
83 void ProcessSample(const PalmFilterSample& sample);
84 gfx::PointF GetCentroid() const;
85 float BiggestSize() const;
86 // If no elements in stroke, returns 0.0;
87 float MaxMajorRadius() const;
88 /**
89 * Return the time duration of this stroke.
90 */
91 base::TimeDelta Duration() const;
92 /**
93 * Provide a (potentially resampled) sample at the requested time.
94 * Only interpolation is allowed.
95 * The requested time must be within the window at which the gesture occurred.
96 */
97 PalmFilterSample GetSampleAt(base::TimeTicks time) const;
98
99 /**
100 * Return true if the provided duration is between the duration of the
101 * previous sample and the current sample. In other words, if the addition of
102 * the last sample caused the total stroke duration to exceed the provided
103 * duration. Return false otherwise.
104 */
105 bool LastSampleCrossed(base::TimeDelta duration) const;
106
107 const std::deque<PalmFilterSample>& samples() const;
108 uint64_t samples_seen() const;
109 int tracking_id() const;
110
111 private:
112 void AddToUnscaledCentroid(const gfx::Vector2dF point);
113 void AddSample(const PalmFilterSample& sample);
114
115 base::TimeDelta PreviousDuration() const;
116
117 std::deque<PalmFilterSample> samples_;
118 const int tracking_id_;
119 /**
120 * How many total samples have been reported for this stroke. This is
121 * different from samples_.size() because samples_ will get pruned to only
122 * keep a certain number of last samples.
123 * When resampling is enabled, this value will be equal to the number of
124 * resampled values that this stroke has received. It may not be equal to the
125 * number of times 'AddSample' has been called.
126 */
127 uint64_t samples_seen_ = 0;
128
129 const uint64_t max_sample_count_;
130 base::TimeTicks first_sample_time_;
131 const base::Optional<base::TimeDelta> resample_period_;
132
133 gfx::PointF unscaled_centroid_ = gfx::PointF(0., 0.);
134 // Used in part of the kahan summation.
135 gfx::Vector2dF unscaled_centroid_sum_error_ =
136 gfx::PointF(0., 0.).OffsetFromOrigin();
137 friend std::ostream& operator<<(std::ostream& out,
138 const PalmFilterStroke& stroke);
139 };
140
141 template <typename T>
142 std::ostream& operator<<(std::ostream& out, const std::deque<T>& queue) {
143 for (const auto& entry : queue) {
144 out << entry << "\n";
145 }
146 return out;
147 }
148
149 std::ostream& operator<<(std::ostream& out, const PalmFilterStroke& filter);
150
151 } // namespace ui
152
153 #endif // UI_EVENTS_OZONE_EVDEV_TOUCH_FILTER_NEURAL_STYLUS_PALM_DETECTION_FILTER_UTIL_H_
154