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