fast_ink_points_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. // Copyright 2016 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. #include "ash/fast_ink/fast_ink_points.h"
  5. #include "base/time/time.h"
  6. #include "testing/gtest/include/gtest/gtest.h"
  7. #include "ui/events/test/event_generator.h"
  8. namespace fast_ink {
  9. namespace {
  10. const int kTestPointsLifetimeSeconds = 5;
  11. class FastInkPointsTest : public testing::Test {
  12. public:
  13. FastInkPointsTest()
  14. : points_(base::Seconds(kTestPointsLifetimeSeconds)),
  15. predicted_(base::Seconds(kTestPointsLifetimeSeconds)),
  16. event_time_(base::TimeTicks()),
  17. screen_size_(1000, 1000) {}
  18. FastInkPointsTest(const FastInkPointsTest&) = delete;
  19. FastInkPointsTest& operator=(const FastInkPointsTest&) = delete;
  20. ~FastInkPointsTest() override = default;
  21. protected:
  22. FastInkPoints points_;
  23. FastInkPoints predicted_;
  24. base::TimeTicks event_time_;
  25. const gfx::Size screen_size_;
  26. base::TimeDelta prediction_duration_;
  27. void AddPoint(const gfx::PointF& point, base::TimeDelta interval) {
  28. event_time_ += interval;
  29. points_.AddPoint(point, event_time_);
  30. predicted_.Predict(points_, event_time_, prediction_duration_,
  31. screen_size_);
  32. const base::TimeTicks presentation_time =
  33. event_time_ + prediction_duration_;
  34. points_.MoveForwardToTime(presentation_time);
  35. predicted_.MoveForwardToTime(presentation_time);
  36. }
  37. void AddStroke(int points,
  38. base::TimeDelta interval,
  39. const gfx::PointF& position,
  40. const gfx::Vector2dF& velocity,
  41. const gfx::Vector2dF& acceleration) {
  42. points_.Clear();
  43. gfx::PointF p = position;
  44. gfx::Vector2dF v = velocity;
  45. for (int i = 0; i < points; ++i) {
  46. AddPoint(p, interval);
  47. p += v;
  48. v += acceleration;
  49. }
  50. }
  51. void Diff(std::vector<gfx::Vector2dF>& dst,
  52. const std::vector<gfx::Vector2dF>& src) {
  53. dst.clear();
  54. if (src.size() < 2)
  55. return;
  56. for (size_t i = 1; i < src.size(); ++i)
  57. dst.push_back(src[i] - src[i - 1]);
  58. }
  59. void ComputeDeltas(std::vector<gfx::Vector2dF>& velocity,
  60. std::vector<gfx::Vector2dF>& acceleration) {
  61. std::vector<gfx::Vector2dF> position;
  62. for (auto p : points_.points())
  63. position.push_back(p.location.OffsetFromOrigin());
  64. for (auto p : predicted_.points())
  65. position.push_back(p.location.OffsetFromOrigin());
  66. Diff(velocity, position);
  67. Diff(acceleration, velocity);
  68. }
  69. };
  70. } // namespace
  71. // Tests that the fast ink points internal collection handles receiving points
  72. // and that the functions are returning the expected output.
  73. TEST_F(FastInkPointsTest, FastInkPointsInternalCollection) {
  74. EXPECT_TRUE(points_.IsEmpty());
  75. EXPECT_EQ(gfx::Rect(), points_.GetBoundingBox());
  76. const gfx::PointF left(1, 1);
  77. const gfx::PointF bottom(1, 9);
  78. const gfx::PointF top_right(30, 0);
  79. const gfx::PointF last(2, 2);
  80. points_.AddPoint(left, base::TimeTicks());
  81. EXPECT_EQ(gfx::Rect(1, 1, 0, 0), points_.GetBoundingBox());
  82. // Should be the new bottom of the bounding box.
  83. points_.AddPoint(bottom, base::TimeTicks());
  84. EXPECT_EQ(gfx::Rect(1, 1, 0, bottom.y() - 1), points_.GetBoundingBox());
  85. // Should be the new top and right of the bounding box.
  86. points_.AddPoint(top_right, base::TimeTicks());
  87. EXPECT_EQ(3, points_.GetNumberOfPoints());
  88. EXPECT_FALSE(points_.IsEmpty());
  89. EXPECT_EQ(gfx::Rect(left.x(), top_right.y(), top_right.x() - left.x(),
  90. bottom.y() - top_right.y()),
  91. points_.GetBoundingBox());
  92. // Should not expand bounding box.
  93. points_.AddPoint(last, base::TimeTicks());
  94. EXPECT_EQ(gfx::Rect(left.x(), top_right.y(), top_right.x() - left.x(),
  95. bottom.y() - top_right.y()),
  96. points_.GetBoundingBox());
  97. // Points should be sorted in the order they are added.
  98. EXPECT_EQ(left, points_.GetOldest().location);
  99. EXPECT_EQ(last, points_.GetNewest().location);
  100. // Add a new point which will expand the bounding box.
  101. gfx::PointF new_left_bottom(0, 40);
  102. points_.AddPoint(new_left_bottom, base::TimeTicks());
  103. EXPECT_EQ(5, points_.GetNumberOfPoints());
  104. EXPECT_EQ(gfx::Rect(new_left_bottom.x(), top_right.y(),
  105. top_right.x() - new_left_bottom.x(),
  106. new_left_bottom.y() - top_right.y()),
  107. points_.GetBoundingBox());
  108. // Verify clearing works.
  109. points_.Clear();
  110. EXPECT_TRUE(points_.IsEmpty());
  111. }
  112. // Test the fast ink points collection to verify that old points are
  113. // removed.
  114. TEST_F(FastInkPointsTest, FastInkPointsInternalCollectionDeletion) {
  115. EXPECT_EQ(1, prediction_duration_.is_zero());
  116. // When a point older than kTestPointsLifetimeSeconds (5 sec) is added, it
  117. // should get removed. The age of the point is a number between 0.0 and 1.0,
  118. // with 0.0 specifying a newly added point and 1.0 specifying the age of a
  119. // point added |kTestPointsLifetimeSeconds| ago.
  120. AddPoint(gfx::PointF(), base::Seconds(1));
  121. EXPECT_EQ(1, points_.GetNumberOfPoints());
  122. EXPECT_FLOAT_EQ(0.0, points_.GetFadeoutFactor(0));
  123. // Verify when we move forward in time by one second, the age of the last
  124. // point, added one second ago is 1 / |kTestPointsLifetimeSeconds|.
  125. AddPoint(gfx::PointF(), base::Seconds(1));
  126. EXPECT_EQ(2, points_.GetNumberOfPoints());
  127. EXPECT_FLOAT_EQ(0.2, points_.GetFadeoutFactor(0));
  128. EXPECT_FLOAT_EQ(0.0, points_.GetFadeoutFactor(1));
  129. // Verify adding a point 10 seconds later will clear all other points, since
  130. // they are older than 5 seconds.
  131. AddPoint(gfx::PointF(), base::Seconds(10));
  132. EXPECT_EQ(1, points_.GetNumberOfPoints());
  133. // Verify adding 3 points one second apart each will add 3 points to the
  134. // collection, since all 4 points are younger than 5 seconds. All 4 points are
  135. // added 1 second apart so their age should be 0.2 apart.
  136. AddPoint(gfx::PointF(), base::Seconds(1));
  137. AddPoint(gfx::PointF(), base::Seconds(1));
  138. AddPoint(gfx::PointF(), base::Seconds(1));
  139. EXPECT_EQ(4, points_.GetNumberOfPoints());
  140. EXPECT_FLOAT_EQ(0.6, points_.GetFadeoutFactor(0));
  141. EXPECT_FLOAT_EQ(0.4, points_.GetFadeoutFactor(1));
  142. EXPECT_FLOAT_EQ(0.2, points_.GetFadeoutFactor(2));
  143. EXPECT_FLOAT_EQ(0.0, points_.GetFadeoutFactor(3));
  144. // Verify adding 1 point three seconds later will remove 2 points which are
  145. // older than 5 seconds.
  146. AddPoint(gfx::PointF(), base::Seconds(3));
  147. EXPECT_EQ(3, points_.GetNumberOfPoints());
  148. }
  149. // Test the fast ink prediction.
  150. TEST_F(FastInkPointsTest, FastInkPointsPrediction) {
  151. prediction_duration_ = base::Milliseconds(18);
  152. const base::TimeDelta kTraceInterval = base::Milliseconds(5);
  153. const int kExpectedPredictionDepth = 3;
  154. // Using fairly generous error margin to allow for the accumulation
  155. // of rounding errors.
  156. const float kMaxPredictionError = 1e-4;
  157. std::vector<gfx::Vector2dF> computed_velocity;
  158. std::vector<gfx::Vector2dF> computed_acceleration;
  159. const gfx::Vector2dF zero;
  160. const gfx::PointF position(0, 0);
  161. // 0 points, no prediction.
  162. AddStroke(0, kTraceInterval, position, zero, zero);
  163. EXPECT_EQ(0, predicted_.GetNumberOfPoints());
  164. // 1 point, no prediction.
  165. AddStroke(1, kTraceInterval, position, zero, zero);
  166. EXPECT_EQ(0, predicted_.GetNumberOfPoints());
  167. // Fixed position, no prediction.
  168. for (int points = 2; points <= 4; ++points) {
  169. SCOPED_TRACE(points);
  170. AddStroke(points, kTraceInterval, position, zero, zero);
  171. EXPECT_EQ(0, predicted_.GetNumberOfPoints());
  172. }
  173. // Constant velocity, the predicted trajectory should maintain it.
  174. const gfx::Vector2dF velocity(10, 5);
  175. for (int points = 2; points <= 4; ++points) {
  176. SCOPED_TRACE(points);
  177. AddStroke(points, kTraceInterval, position, velocity, zero);
  178. EXPECT_EQ(kExpectedPredictionDepth, predicted_.GetNumberOfPoints());
  179. ComputeDeltas(computed_velocity, computed_acceleration);
  180. for (auto v : computed_velocity) {
  181. EXPECT_GT(kMaxPredictionError, (velocity - v).Length());
  182. }
  183. }
  184. // Constant acceleration, the predicted trajectory should maintain it.
  185. const gfx::Vector2dF acceleration(4, 2);
  186. for (int points = 3; points <= 4; ++points) {
  187. SCOPED_TRACE(points);
  188. AddStroke(points, kTraceInterval, position, velocity, acceleration);
  189. EXPECT_EQ(kExpectedPredictionDepth, predicted_.GetNumberOfPoints());
  190. ComputeDeltas(computed_velocity, computed_acceleration);
  191. for (auto a : computed_acceleration) {
  192. EXPECT_GT(kMaxPredictionError, (acceleration - a).Length());
  193. }
  194. }
  195. // Not testing with non-zero jerk, as the current prediction implementation
  196. // is not maintaining constant jerk on purpose.
  197. }
  198. // Test the interrupted stroke support.
  199. TEST_F(FastInkPointsTest, AddGap) {
  200. points_.AddPoint(gfx::PointF(0, 0), base::TimeTicks());
  201. points_.AddPoint(gfx::PointF(1, 1), base::TimeTicks());
  202. points_.AddGap();
  203. points_.AddPoint(gfx::PointF(2, 2), base::TimeTicks());
  204. points_.AddPoint(gfx::PointF(3, 3), base::TimeTicks());
  205. points_.AddPoint(gfx::PointF(4, 4), base::TimeTicks());
  206. points_.AddGap();
  207. points_.AddPoint(gfx::PointF(5, 5), base::TimeTicks());
  208. auto points = points_.points();
  209. EXPECT_FALSE(points[0].gap_after);
  210. EXPECT_TRUE(points[1].gap_after);
  211. EXPECT_FALSE(points[2].gap_after);
  212. EXPECT_FALSE(points[3].gap_after);
  213. EXPECT_TRUE(points[4].gap_after);
  214. EXPECT_FALSE(points[5].gap_after);
  215. }
  216. // Tests deleting points from the last stroke.
  217. TEST_F(FastInkPointsTest, UndoLastStroke) {
  218. // Calling undo with no points should not crash.
  219. gfx::Rect bounding_box = points_.UndoLastStroke();
  220. EXPECT_EQ(bounding_box, gfx::Rect());
  221. points_.AddPoint(gfx::PointF(0, 0), base::TimeTicks());
  222. points_.AddPoint(gfx::PointF(1, 1), base::TimeTicks());
  223. points_.AddGap();
  224. // Calling undo should clear all points.
  225. bounding_box = points_.UndoLastStroke();
  226. EXPECT_TRUE(points_.IsEmpty());
  227. EXPECT_EQ(bounding_box, gfx::Rect(0, 0, 1, 1));
  228. points_.AddPoint(gfx::PointF(0, 0), base::TimeTicks());
  229. points_.AddPoint(gfx::PointF(1, 1), base::TimeTicks());
  230. points_.AddGap();
  231. points_.AddPoint(gfx::PointF(2, 2), base::TimeTicks());
  232. points_.AddPoint(gfx::PointF(3, 3), base::TimeTicks());
  233. points_.AddPoint(gfx::PointF(4, 4), base::TimeTicks());
  234. points_.AddGap();
  235. // Calling undo should clear the second stroke only.
  236. bounding_box = points_.UndoLastStroke();
  237. EXPECT_EQ(points_.GetNumberOfPoints(), 2);
  238. EXPECT_TRUE(points_.GetNewest().gap_after);
  239. EXPECT_EQ(bounding_box, gfx::Rect(2, 2, 2, 2));
  240. points_.AddPoint(gfx::PointF(0, 0), base::TimeTicks());
  241. points_.AddPoint(gfx::PointF(1, 1), base::TimeTicks());
  242. points_.AddGap();
  243. points_.AddPoint(gfx::PointF(2, 2), base::TimeTicks());
  244. points_.AddPoint(gfx::PointF(3, 3), base::TimeTicks());
  245. points_.AddPoint(gfx::PointF(4, 4), base::TimeTicks());
  246. points_.AddGap();
  247. points_.AddPoint(gfx::PointF(5, 5), base::TimeTicks());
  248. // Calling undo twice should clear the third and second strokes.
  249. bounding_box = points_.UndoLastStroke();
  250. EXPECT_EQ(bounding_box, gfx::Rect(5, 5, 0, 0));
  251. bounding_box = points_.UndoLastStroke();
  252. EXPECT_EQ(bounding_box, gfx::Rect(2, 2, 2, 2));
  253. EXPECT_EQ(points_.GetNumberOfPoints(), 4);
  254. EXPECT_TRUE(points_.GetNewest().gap_after);
  255. }
  256. } // namespace fast_ink