AccelFilterInterpreter: New Smooth Acceleration Feature

With this feature, the acceleration multiplier is determined by
averaging the previous three motions that connect to the current
motion. I.e., each motion's end time must correspond to the next
motion's start time.

This is especially helpful for pads that sometimes have uneven motion
(ie, short moves then long moves), so that the acceleration doesn't
multiply the difference between short and long moves.

BUG=chromium:326647
TEST=Leon regression tests

Change-Id: I64d5a7abe3bb708b84c98d9bd5746b67012ba8b6
Reviewed-on: https://chromium-review.googlesource.com/179155
Reviewed-by: Charles Mooney <charliemooney@chromium.org>
Commit-Queue: Andrew de los Reyes <adlr@chromium.org>
Tested-by: Andrew de los Reyes <adlr@chromium.org>
diff --git a/include/accel_filter_interpreter.h b/include/accel_filter_interpreter.h
index 95678d6..36df4e1 100644
--- a/include/accel_filter_interpreter.h
+++ b/include/accel_filter_interpreter.h
@@ -84,6 +84,13 @@
   DoubleProperty min_reasonable_dt_;
   DoubleProperty max_reasonable_dt_;
   stime_t last_reasonable_dt_;
+
+  // If we enable smooth accel, the past few magnitudes are used to compute the
+  // multiplication factor.
+  BoolProperty smooth_accel_;
+  stime_t last_end_time_;
+  float last_mags_[2];
+  size_t last_mags_size_;
 };
 
 }  // namespace gestures
diff --git a/src/accel_filter_interpreter.cc b/src/accel_filter_interpreter.cc
index c55ff1b..450027b 100644
--- a/src/accel_filter_interpreter.cc
+++ b/src/accel_filter_interpreter.cc
@@ -35,7 +35,10 @@
       use_mouse_point_curves_(prop_reg, "Mouse Accel Curves", 0),
       min_reasonable_dt_(prop_reg, "Accel Min dt", 0.003),
       max_reasonable_dt_(prop_reg, "Accel Max dt", 0.050),
-      last_reasonable_dt_(0.05) {
+      last_reasonable_dt_(0.05),
+      smooth_accel_(prop_reg, "Smooth Accel", 0),
+      last_end_time_(0.0),
+      last_mags_size_(0) {
   InitName();
   // Set up default curves.
 
@@ -210,6 +213,27 @@
     ProduceGesture(gs);
     return;  // Avoid division by 0
   }
+
+  if (smooth_accel_.val_) {
+    if (last_end_time_ == gs.start_time) {
+      float new_mag = mag;
+      for (size_t i = last_mags_size_ - 1; i > 0; i--) {
+        new_mag += last_mags_[i];
+        last_mags_[i] = last_mags_[i - 1];
+      }
+      new_mag += last_mags_[0];
+      new_mag /= last_mags_size_ + 1;
+
+      last_mags_[0] = mag;
+      last_mags_size_ = std::min(arraysize(last_mags_), last_mags_size_ + 1);
+      mag = new_mag;
+    } else {
+      last_mags_size_ = 1;
+      last_mags_[0] = mag;
+    }
+    last_end_time_ = gs.end_time;
+  }
+
   for (size_t i = 0; i < max_segs; ++i) {
     if (mag > segs[i].x_)
       continue;