Flutter Impeller
path_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter 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 #include "gtest/gtest.h"
6 
7 #include "flutter/testing/testing.h"
11 
12 namespace impeller {
13 namespace testing {
14 
15 TEST(PathTest, CubicPathComponentPolylineDoesNotIncludePointOne) {
16  CubicPathComponent component({10, 10}, {20, 35}, {35, 20}, {40, 40});
17  std::vector<Point> polyline;
18  component.AppendPolylinePoints(1.0f, polyline);
19  ASSERT_NE(polyline.front().x, 10);
20  ASSERT_NE(polyline.front().y, 10);
21  ASSERT_EQ(polyline.back().x, 40);
22  ASSERT_EQ(polyline.back().y, 40);
23 }
24 
25 TEST(PathTest, PathCreatePolyLineDoesNotDuplicatePoints) {
26  PathBuilder builder;
27  builder.MoveTo({10, 10});
28  builder.LineTo({20, 20});
29  builder.LineTo({30, 30});
30  builder.MoveTo({40, 40});
31  builder.LineTo({50, 50});
32 
33  auto polyline = builder.TakePath().CreatePolyline(1.0f);
34 
35  ASSERT_EQ(polyline.contours.size(), 2u);
36  ASSERT_EQ(polyline.points->size(), 5u);
37  ASSERT_EQ(polyline.GetPoint(0).x, 10);
38  ASSERT_EQ(polyline.GetPoint(1).x, 20);
39  ASSERT_EQ(polyline.GetPoint(2).x, 30);
40  ASSERT_EQ(polyline.GetPoint(3).x, 40);
41  ASSERT_EQ(polyline.GetPoint(4).x, 50);
42 }
43 
44 TEST(PathTest, PathBuilderSetsCorrectContourPropertiesForAddCommands) {
45  // Closed shapes.
46  {
47  Path path = PathBuilder{}.AddCircle({100, 100}, 50).TakePath();
48  ContourComponent contour;
49  path.GetContourComponentAtIndex(0, contour);
50  ASSERT_POINT_NEAR(contour.destination, Point(100, 50));
51  ASSERT_TRUE(contour.is_closed);
52  }
53 
54  {
55  Path path =
56  PathBuilder{}.AddOval(Rect::MakeXYWH(100, 100, 100, 100)).TakePath();
57  ContourComponent contour;
58  path.GetContourComponentAtIndex(0, contour);
59  ASSERT_POINT_NEAR(contour.destination, Point(150, 100));
60  ASSERT_TRUE(contour.is_closed);
61  }
62 
63  {
64  Path path =
65  PathBuilder{}.AddRect(Rect::MakeXYWH(100, 100, 100, 100)).TakePath();
66  ContourComponent contour;
67  path.GetContourComponentAtIndex(0, contour);
68  ASSERT_POINT_NEAR(contour.destination, Point(100, 100));
69  ASSERT_TRUE(contour.is_closed);
70  }
71 
72  {
73  Path path = PathBuilder{}
74  .AddRoundedRect(Rect::MakeXYWH(100, 100, 100, 100), 10)
75  .TakePath();
76  ContourComponent contour;
77  path.GetContourComponentAtIndex(0, contour);
78  ASSERT_POINT_NEAR(contour.destination, Point(110, 100));
79  ASSERT_TRUE(contour.is_closed);
80  }
81 
82  {
83  Path path =
84  PathBuilder{}
85  .AddRoundedRect(Rect::MakeXYWH(100, 100, 100, 100), Size(10, 20))
86  .TakePath();
87  ContourComponent contour;
88  path.GetContourComponentAtIndex(0, contour);
89  ASSERT_POINT_NEAR(contour.destination, Point(110, 100));
90  ASSERT_TRUE(contour.is_closed);
91  }
92 
93  // Open shapes.
94  {
95  Point p(100, 100);
96  Path path = PathBuilder{}.AddLine(p, {200, 100}).TakePath();
97  ContourComponent contour;
98  path.GetContourComponentAtIndex(0, contour);
99  ASSERT_POINT_NEAR(contour.destination, p);
100  ASSERT_FALSE(contour.is_closed);
101  }
102 
103  {
104  Path path =
105  PathBuilder{}
106  .AddCubicCurve({100, 100}, {100, 50}, {100, 150}, {200, 100})
107  .TakePath();
108  ContourComponent contour;
109  path.GetContourComponentAtIndex(0, contour);
110  ASSERT_POINT_NEAR(contour.destination, Point(100, 100));
111  ASSERT_FALSE(contour.is_closed);
112  }
113 
114  {
115  Path path = PathBuilder{}
116  .AddQuadraticCurve({100, 100}, {100, 50}, {200, 100})
117  .TakePath();
118  ContourComponent contour;
119  path.GetContourComponentAtIndex(0, contour);
120  ASSERT_POINT_NEAR(contour.destination, Point(100, 100));
121  ASSERT_FALSE(contour.is_closed);
122  }
123 }
124 
125 TEST(PathTest, PathCreatePolylineGeneratesCorrectContourData) {
127  .AddLine({100, 100}, {200, 100})
128  .MoveTo({100, 200})
129  .LineTo({150, 250})
130  .LineTo({200, 200})
131  .Close()
132  .TakePath()
133  .CreatePolyline(1.0f);
134  ASSERT_EQ(polyline.points->size(), 6u);
135  ASSERT_EQ(polyline.contours.size(), 2u);
136  ASSERT_EQ(polyline.contours[0].is_closed, false);
137  ASSERT_EQ(polyline.contours[0].start_index, 0u);
138  ASSERT_EQ(polyline.contours[1].is_closed, true);
139  ASSERT_EQ(polyline.contours[1].start_index, 2u);
140 }
141 
142 TEST(PathTest, PolylineGetContourPointBoundsReturnsCorrectRanges) {
144  .AddLine({100, 100}, {200, 100})
145  .MoveTo({100, 200})
146  .LineTo({150, 250})
147  .LineTo({200, 200})
148  .Close()
149  .TakePath()
150  .CreatePolyline(1.0f);
151  size_t a1, a2, b1, b2;
152  std::tie(a1, a2) = polyline.GetContourPointBounds(0);
153  std::tie(b1, b2) = polyline.GetContourPointBounds(1);
154  ASSERT_EQ(a1, 0u);
155  ASSERT_EQ(a2, 2u);
156  ASSERT_EQ(b1, 2u);
157  ASSERT_EQ(b2, 6u);
158 }
159 
160 TEST(PathTest, PathAddRectPolylineHasCorrectContourData) {
162  .AddRect(Rect::MakeLTRB(50, 60, 70, 80))
163  .TakePath()
164  .CreatePolyline(1.0f);
165  ASSERT_EQ(polyline.contours.size(), 1u);
166  ASSERT_TRUE(polyline.contours[0].is_closed);
167  ASSERT_EQ(polyline.contours[0].start_index, 0u);
168  ASSERT_EQ(polyline.points->size(), 5u);
169  ASSERT_EQ(polyline.GetPoint(0), Point(50, 60));
170  ASSERT_EQ(polyline.GetPoint(1), Point(70, 60));
171  ASSERT_EQ(polyline.GetPoint(2), Point(70, 80));
172  ASSERT_EQ(polyline.GetPoint(3), Point(50, 80));
173  ASSERT_EQ(polyline.GetPoint(4), Point(50, 60));
174 }
175 
176 TEST(PathTest, PathPolylineDuplicatesAreRemovedForSameContour) {
178  PathBuilder{}
179  .MoveTo({50, 50})
180  .LineTo({50, 50}) // Insert duplicate at beginning of contour.
181  .LineTo({100, 50})
182  .LineTo({100, 50}) // Insert duplicate at contour join.
183  .LineTo({100, 100})
184  .Close() // Implicitly insert duplicate {50, 50} across contours.
185  .LineTo({0, 50})
186  .LineTo({0, 100})
187  .LineTo({0, 100}) // Insert duplicate at end of contour.
188  .TakePath()
189  .CreatePolyline(1.0f);
190  ASSERT_EQ(polyline.contours.size(), 2u);
191  ASSERT_EQ(polyline.contours[0].start_index, 0u);
192  ASSERT_TRUE(polyline.contours[0].is_closed);
193  ASSERT_EQ(polyline.contours[1].start_index, 4u);
194  ASSERT_FALSE(polyline.contours[1].is_closed);
195  ASSERT_EQ(polyline.points->size(), 7u);
196  ASSERT_EQ(polyline.GetPoint(0), Point(50, 50));
197  ASSERT_EQ(polyline.GetPoint(1), Point(100, 50));
198  ASSERT_EQ(polyline.GetPoint(2), Point(100, 100));
199  ASSERT_EQ(polyline.GetPoint(3), Point(50, 50));
200  ASSERT_EQ(polyline.GetPoint(4), Point(50, 50));
201  ASSERT_EQ(polyline.GetPoint(5), Point(0, 50));
202  ASSERT_EQ(polyline.GetPoint(6), Point(0, 100));
203 }
204 
205 TEST(PathTest, PolylineBufferReuse) {
206  auto point_buffer = std::make_unique<std::vector<Point>>();
207  auto point_buffer_address = reinterpret_cast<uintptr_t>(point_buffer.get());
209  PathBuilder{}
210  .MoveTo({50, 50})
211  .LineTo({100, 100})
212  .TakePath()
213  .CreatePolyline(
214  1.0f, std::move(point_buffer),
215  [point_buffer_address](
216  Path::Polyline::PointBufferPtr point_buffer) {
217  ASSERT_EQ(point_buffer->size(), 0u);
218  ASSERT_EQ(point_buffer_address,
219  reinterpret_cast<uintptr_t>(point_buffer.get()));
220  });
221 }
222 
223 TEST(PathTest, PolylineFailsWithNullptrBuffer) {
224  EXPECT_DEATH_IF_SUPPORTED(PathBuilder{}
225  .MoveTo({50, 50})
226  .LineTo({100, 100})
227  .TakePath()
228  .CreatePolyline(1.0f, nullptr),
229  "");
230 }
231 
232 TEST(PathTest, PathShifting) {
233  PathBuilder builder{};
234  auto path =
235  builder.AddLine(Point(0, 0), Point(10, 10))
236  .AddQuadraticCurve(Point(10, 10), Point(15, 15), Point(20, 20))
237  .AddCubicCurve(Point(20, 20), Point(25, 25), Point(-5, -5),
238  Point(30, 30))
239  .Close()
240  .Shift(Point(1, 1))
241  .TakePath();
242 
243  ContourComponent contour;
244  LinearPathComponent linear;
246  CubicPathComponent cubic;
247 
248  ASSERT_TRUE(path.GetContourComponentAtIndex(0, contour));
249  ASSERT_TRUE(path.GetLinearComponentAtIndex(1, linear));
250  ASSERT_TRUE(path.GetQuadraticComponentAtIndex(3, quad));
251  ASSERT_TRUE(path.GetCubicComponentAtIndex(5, cubic));
252 
253  EXPECT_EQ(contour.destination, Point(1, 1));
254 
255  EXPECT_EQ(linear.p1, Point(1, 1));
256  EXPECT_EQ(linear.p2, Point(11, 11));
257 
258  EXPECT_EQ(quad.cp, Point(16, 16));
259  EXPECT_EQ(quad.p1, Point(11, 11));
260  EXPECT_EQ(quad.p2, Point(21, 21));
261 
262  EXPECT_EQ(cubic.cp1, Point(26, 26));
263  EXPECT_EQ(cubic.cp2, Point(-4, -4));
264  EXPECT_EQ(cubic.p1, Point(21, 21));
265  EXPECT_EQ(cubic.p2, Point(31, 31));
266 }
267 
268 TEST(PathTest, PathBuilderWillComputeBounds) {
269  PathBuilder builder;
270  auto path_1 = builder.AddLine({0, 0}, {1, 1}).TakePath();
271 
272  ASSERT_EQ(path_1.GetBoundingBox().value_or(Rect::MakeMaximum()),
273  Rect::MakeLTRB(0, 0, 1, 1));
274 
275  auto path_2 = builder.AddLine({-1, -1}, {1, 1}).TakePath();
276 
277  // Verify that PathBuilder recomputes the bounds.
278  ASSERT_EQ(path_2.GetBoundingBox().value_or(Rect::MakeMaximum()),
279  Rect::MakeLTRB(-1, -1, 1, 1));
280 
281  // PathBuilder can set the bounds to whatever it wants
282  auto path_3 = builder.AddLine({0, 0}, {1, 1})
283  .SetBounds(Rect::MakeLTRB(0, 0, 100, 100))
284  .TakePath();
285 
286  ASSERT_EQ(path_3.GetBoundingBox().value_or(Rect::MakeMaximum()),
287  Rect::MakeLTRB(0, 0, 100, 100));
288 }
289 
290 TEST(PathTest, PathHorizontalLine) {
291  PathBuilder builder;
292  auto path = builder.HorizontalLineTo(10).TakePath();
293 
294  LinearPathComponent linear;
295  path.GetLinearComponentAtIndex(1, linear);
296 
297  EXPECT_EQ(linear.p1, Point(0, 0));
298  EXPECT_EQ(linear.p2, Point(10, 0));
299 }
300 
301 TEST(PathTest, PathVerticalLine) {
302  PathBuilder builder;
303  auto path = builder.VerticalLineTo(10).TakePath();
304 
305  LinearPathComponent linear;
306  path.GetLinearComponentAtIndex(1, linear);
307 
308  EXPECT_EQ(linear.p1, Point(0, 0));
309  EXPECT_EQ(linear.p2, Point(0, 10));
310 }
311 
312 TEST(PathTest, QuadradicPath) {
313  PathBuilder builder;
314  auto path = builder.QuadraticCurveTo(Point(10, 10), Point(20, 20)).TakePath();
315 
317  path.GetQuadraticComponentAtIndex(1, quad);
318 
319  EXPECT_EQ(quad.p1, Point(0, 0));
320  EXPECT_EQ(quad.cp, Point(10, 10));
321  EXPECT_EQ(quad.p2, Point(20, 20));
322 }
323 
324 TEST(PathTest, CubicPath) {
325  PathBuilder builder;
326  auto path =
327  builder.CubicCurveTo(Point(10, 10), Point(-10, -10), Point(20, 20))
328  .TakePath();
329 
330  CubicPathComponent cubic;
331  path.GetCubicComponentAtIndex(1, cubic);
332 
333  EXPECT_EQ(cubic.p1, Point(0, 0));
334  EXPECT_EQ(cubic.cp1, Point(10, 10));
335  EXPECT_EQ(cubic.cp2, Point(-10, -10));
336  EXPECT_EQ(cubic.p2, Point(20, 20));
337 }
338 
339 TEST(PathTest, BoundingBoxCubic) {
340  PathBuilder builder;
341  auto path =
342  builder.AddCubicCurve({120, 160}, {25, 200}, {220, 260}, {220, 40})
343  .TakePath();
344  auto box = path.GetBoundingBox();
345  Rect expected = Rect::MakeXYWH(93.9101, 40, 126.09, 158.862);
346  ASSERT_TRUE(box.has_value());
347  ASSERT_RECT_NEAR(box.value_or(Rect::MakeMaximum()), expected);
348 }
349 
350 TEST(PathTest, BoundingBoxOfCompositePathIsCorrect) {
351  PathBuilder builder;
352  builder.AddRoundedRect(Rect::MakeXYWH(10, 10, 300, 300), {50, 50, 50, 50});
353  auto path = builder.TakePath();
354  auto actual = path.GetBoundingBox();
355  Rect expected = Rect::MakeXYWH(10, 10, 300, 300);
356 
357  ASSERT_TRUE(actual.has_value());
358  ASSERT_RECT_NEAR(actual.value_or(Rect::MakeMaximum()), expected);
359 }
360 
361 TEST(PathTest, ExtremaOfCubicPathComponentIsCorrect) {
362  CubicPathComponent cubic{{11.769268, 252.883148},
363  {-6.2857933, 204.356461},
364  {-4.53997231, 156.552902},
365  {17.0067291, 109.472488}};
366  auto points = cubic.Extrema();
367 
368  ASSERT_EQ(points.size(), static_cast<size_t>(3));
369  ASSERT_POINT_NEAR(points[2], cubic.Solve(0.455916));
370 }
371 
372 TEST(PathTest, PathGetBoundingBoxForCubicWithNoDerivativeRootsIsCorrect) {
373  PathBuilder builder;
374  // Straight diagonal line.
375  builder.AddCubicCurve({0, 1}, {2, 3}, {4, 5}, {6, 7});
376  auto path = builder.TakePath();
377  auto actual = path.GetBoundingBox();
378  auto expected = Rect::MakeLTRB(0, 1, 6, 7);
379 
380  ASSERT_TRUE(actual.has_value());
381  ASSERT_RECT_NEAR(actual.value_or(Rect::MakeMaximum()), expected);
382 }
383 
384 TEST(PathTest, EmptyPath) {
385  auto path = PathBuilder{}.TakePath();
386  ASSERT_EQ(path.GetComponentCount(), 1u);
387 
389  path.GetContourComponentAtIndex(0, c);
391 
392  Path::Polyline polyline = path.CreatePolyline(1.0f);
393  ASSERT_TRUE(polyline.points->empty());
394  ASSERT_TRUE(polyline.contours.empty());
395 }
396 
397 TEST(PathTest, SimplePath) {
398  PathBuilder builder;
399 
400  auto path = builder.AddLine({0, 0}, {100, 100})
401  .AddQuadraticCurve({100, 100}, {200, 200}, {300, 300})
402  .AddCubicCurve({300, 300}, {400, 400}, {500, 500}, {600, 600})
403  .TakePath();
404 
405  ASSERT_EQ(path.GetComponentCount(), 6u);
406  ASSERT_EQ(path.GetComponentCount(Path::ComponentType::kLinear), 1u);
407  ASSERT_EQ(path.GetComponentCount(Path::ComponentType::kQuadratic), 1u);
408  ASSERT_EQ(path.GetComponentCount(Path::ComponentType::kCubic), 1u);
409  ASSERT_EQ(path.GetComponentCount(Path::ComponentType::kContour), 3u);
410 
411  path.EnumerateComponents(
412  [](size_t index, const LinearPathComponent& linear) {
413  Point p1(0, 0);
414  Point p2(100, 100);
415  ASSERT_EQ(index, 1u);
416  ASSERT_EQ(linear.p1, p1);
417  ASSERT_EQ(linear.p2, p2);
418  },
419  [](size_t index, const QuadraticPathComponent& quad) {
420  Point p1(100, 100);
421  Point cp(200, 200);
422  Point p2(300, 300);
423  ASSERT_EQ(index, 3u);
424  ASSERT_EQ(quad.p1, p1);
425  ASSERT_EQ(quad.cp, cp);
426  ASSERT_EQ(quad.p2, p2);
427  },
428  [](size_t index, const CubicPathComponent& cubic) {
429  Point p1(300, 300);
430  Point cp1(400, 400);
431  Point cp2(500, 500);
432  Point p2(600, 600);
433  ASSERT_EQ(index, 5u);
434  ASSERT_EQ(cubic.p1, p1);
435  ASSERT_EQ(cubic.cp1, cp1);
436  ASSERT_EQ(cubic.cp2, cp2);
437  ASSERT_EQ(cubic.p2, p2);
438  },
439  [](size_t index, const ContourComponent& contour) {
440  // There is an initial countour added for each curve.
441  if (index == 0u) {
442  Point p1(0, 0);
443  ASSERT_EQ(contour.destination, p1);
444  } else if (index == 2u) {
445  Point p1(100, 100);
446  ASSERT_EQ(contour.destination, p1);
447  } else if (index == 4u) {
448  Point p1(300, 300);
449  ASSERT_EQ(contour.destination, p1);
450  } else {
451  ASSERT_FALSE(true);
452  }
453  ASSERT_FALSE(contour.is_closed);
454  });
455 }
456 
457 TEST(PathTest, CanBeCloned) {
458  PathBuilder builder;
459  builder.MoveTo({10, 10});
460  builder.LineTo({20, 20});
461  builder.SetBounds(Rect::MakeLTRB(0, 0, 100, 100));
463 
464  auto path_a = builder.TakePath(FillType::kOdd);
465  // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
466  auto path_b = path_a;
467 
468  EXPECT_EQ(path_a.GetBoundingBox(), path_b.GetBoundingBox());
469  EXPECT_EQ(path_a.GetFillType(), path_b.GetFillType());
470  EXPECT_EQ(path_a.IsConvex(), path_b.IsConvex());
471 
472  auto poly_a = path_a.CreatePolyline(1.0);
473  auto poly_b = path_b.CreatePolyline(1.0);
474 
475  ASSERT_EQ(poly_a.points->size(), poly_b.points->size());
476  ASSERT_EQ(poly_a.contours.size(), poly_b.contours.size());
477 
478  for (auto i = 0u; i < poly_a.points->size(); i++) {
479  EXPECT_EQ((*poly_a.points)[i], (*poly_b.points)[i]);
480  }
481 
482  for (auto i = 0u; i < poly_a.contours.size(); i++) {
483  EXPECT_EQ(poly_a.contours[i].start_index, poly_b.contours[i].start_index);
484  EXPECT_EQ(poly_a.contours[i].start_direction,
485  poly_b.contours[i].start_direction);
486  }
487 }
488 
489 TEST(PathTest, PathBuilderDoesNotMutateCopiedPaths) {
490  auto test_isolation =
491  [](const std::function<void(PathBuilder & builder)>& mutator,
492  bool will_close, Point mutation_offset, const std::string& label) {
493  PathBuilder builder;
494  builder.MoveTo({10, 10});
495  builder.LineTo({20, 20});
496  builder.LineTo({20, 10});
497 
498  auto verify_path = [](const Path& path, bool is_mutated, bool is_closed,
499  Point offset, const std::string& label) {
500  if (is_mutated) {
501  // We can only test the initial state before the mutator did
502  // its work. We have >= 3 components and the first 3 components
503  // will match what we saw before the mutation.
504  EXPECT_GE(path.GetComponentCount(), 3u) << label;
505  } else {
506  EXPECT_EQ(path.GetComponentCount(), 3u) << label;
507  }
508  {
509  ContourComponent contour;
510  EXPECT_TRUE(path.GetContourComponentAtIndex(0, contour)) << label;
511  EXPECT_EQ(contour.destination, offset + Point(10, 10)) << label;
512  EXPECT_EQ(contour.is_closed, is_closed) << label;
513  }
514  {
515  LinearPathComponent line;
516  EXPECT_TRUE(path.GetLinearComponentAtIndex(1, line)) << label;
517  EXPECT_EQ(line.p1, offset + Point(10, 10)) << label;
518  EXPECT_EQ(line.p2, offset + Point(20, 20)) << label;
519  }
520  {
521  LinearPathComponent line;
522  EXPECT_TRUE(path.GetLinearComponentAtIndex(2, line)) << label;
523  EXPECT_EQ(line.p1, offset + Point(20, 20)) << label;
524  EXPECT_EQ(line.p2, offset + Point(20, 10)) << label;
525  }
526  };
527 
528  auto path1 = builder.CopyPath();
529  verify_path(path1, false, false, {},
530  "Initial Path1 state before " + label);
531 
532  for (int i = 0; i < 10; i++) {
533  auto path = builder.CopyPath();
534  verify_path(
535  path, false, false, {},
536  "Extra CopyPath #" + std::to_string(i + 1) + " for " + label);
537  }
538  mutator(builder);
539  verify_path(path1, false, false, {},
540  "Path1 state after subsequent " + label);
541 
542  auto path2 = builder.CopyPath();
543  verify_path(path1, false, false, {},
544  "Path1 state after subsequent " + label + " and CopyPath");
545  verify_path(path2, true, will_close, mutation_offset,
546  "Initial Path2 state with subsequent " + label);
547  };
548 
549  test_isolation(
550  [](PathBuilder& builder) { //
552  },
553  false, {}, "SetConvex");
554 
555  test_isolation(
556  [](PathBuilder& builder) { //
558  },
559  false, {}, "SetUnknownConvex");
560 
561  test_isolation(
562  [](PathBuilder& builder) { //
563  builder.Close();
564  },
565  true, {}, "Close");
566 
567  test_isolation(
568  [](PathBuilder& builder) {
569  builder.MoveTo({20, 30}, false);
570  },
571  false, {}, "Absolute MoveTo");
572 
573  test_isolation(
574  [](PathBuilder& builder) {
575  builder.MoveTo({20, 30}, true);
576  },
577  false, {}, "Relative MoveTo");
578 
579  test_isolation(
580  [](PathBuilder& builder) {
581  builder.LineTo({20, 30}, false);
582  },
583  false, {}, "Absolute LineTo");
584 
585  test_isolation(
586  [](PathBuilder& builder) {
587  builder.LineTo({20, 30}, true);
588  },
589  false, {}, "Relative LineTo");
590 
591  test_isolation(
592  [](PathBuilder& builder) { //
593  builder.HorizontalLineTo(100, false);
594  },
595  false, {}, "Absolute HorizontalLineTo");
596 
597  test_isolation(
598  [](PathBuilder& builder) { //
599  builder.HorizontalLineTo(100, true);
600  },
601  false, {}, "Relative HorizontalLineTo");
602 
603  test_isolation(
604  [](PathBuilder& builder) { //
605  builder.VerticalLineTo(100, false);
606  },
607  false, {}, "Absolute VerticalLineTo");
608 
609  test_isolation(
610  [](PathBuilder& builder) { //
611  builder.VerticalLineTo(100, true);
612  },
613  false, {}, "Relative VerticalLineTo");
614 
615  test_isolation(
616  [](PathBuilder& builder) {
617  builder.QuadraticCurveTo({20, 30}, {30, 20}, false);
618  },
619  false, {}, "Absolute QuadraticCurveTo");
620 
621  test_isolation(
622  [](PathBuilder& builder) {
623  builder.QuadraticCurveTo({20, 30}, {30, 20}, true);
624  },
625  false, {}, "Relative QuadraticCurveTo");
626 
627  test_isolation(
628  [](PathBuilder& builder) {
629  builder.CubicCurveTo({20, 30}, {30, 20}, {30, 30}, false);
630  },
631  false, {}, "Absolute CubicCurveTo");
632 
633  test_isolation(
634  [](PathBuilder& builder) {
635  builder.CubicCurveTo({20, 30}, {30, 20}, {30, 30}, true);
636  },
637  false, {}, "Relative CubicCurveTo");
638 
639  test_isolation(
640  [](PathBuilder& builder) {
641  builder.AddLine({100, 100}, {150, 100});
642  },
643  false, {}, "AddLine");
644 
645  test_isolation(
646  [](PathBuilder& builder) {
647  builder.AddRect(Rect::MakeLTRB(100, 100, 120, 120));
648  },
649  false, {}, "AddRect");
650 
651  test_isolation(
652  [](PathBuilder& builder) {
653  builder.AddOval(Rect::MakeLTRB(100, 100, 120, 120));
654  },
655  false, {}, "AddOval");
656 
657  test_isolation(
658  [](PathBuilder& builder) {
659  builder.AddCircle({100, 100}, 20);
660  },
661  false, {}, "AddCircle");
662 
663  test_isolation(
664  [](PathBuilder& builder) {
665  builder.AddArc(Rect::MakeLTRB(100, 100, 120, 120), Degrees(10),
666  Degrees(170));
667  },
668  false, {}, "AddArc");
669 
670  test_isolation(
671  [](PathBuilder& builder) {
672  builder.AddQuadraticCurve({100, 100}, {150, 100}, {150, 150});
673  },
674  false, {}, "AddQuadraticCurve");
675 
676  test_isolation(
677  [](PathBuilder& builder) {
678  builder.AddCubicCurve({100, 100}, {150, 100}, {100, 150}, {150, 150});
679  },
680  false, {}, "AddCubicCurve");
681 
682  test_isolation(
683  [](PathBuilder& builder) {
684  builder.Shift({23, 42});
685  },
686  false, {23, 42}, "Shift");
687 }
688 
689 } // namespace testing
690 } // namespace impeller
path.h
impeller::PathBuilder::AddQuadraticCurve
PathBuilder & AddQuadraticCurve(Point p1, Point cp, Point p2)
Move to point p1, then insert a quadradic curve from p1 to p2 with the control point cp.
Definition: path_builder.cc:97
polyline
const Path::Polyline & polyline
Definition: stroke_path_geometry.cc:292
impeller::LinearPathComponent
Definition: path_component.h:29
geometry_asserts.h
impeller::CubicPathComponent::p1
Point p1
Definition: path_component.h:101
impeller::FillType::kOdd
@ kOdd
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
impeller::Path::ComponentType::kLinear
@ kLinear
impeller::PathBuilder::SetBounds
PathBuilder & SetBounds(Rect bounds)
Set the bounding box that will be used by Path.GetBoundingBox in place of performing the computation.
Definition: path_builder.cc:453
impeller::LinearPathComponent::p2
Point p2
Definition: path_component.h:31
impeller::QuadraticPathComponent::p1
Point p1
Definition: path_component.h:55
impeller::CubicPathComponent::cp2
Point cp2
Definition: path_component.h:105
impeller::PathBuilder::CubicCurveTo
PathBuilder & CubicCurveTo(Point controlPoint1, Point controlPoint2, Point point, bool relative=false)
Insert a cubic curve from the curren position to point using the control points controlPoint1 and con...
Definition: path_builder.cc:85
impeller::Path::ComponentType::kCubic
@ kCubic
impeller::PathBuilder
Definition: path_builder.h:14
impeller::QuadraticPathComponent::cp
Point cp
Definition: path_component.h:57
impeller::Path::GetBoundingBox
std::optional< Rect > GetBoundingBox() const
Definition: path.cc:339
impeller::Path::ComponentType::kQuadratic
@ kQuadratic
impeller::PathBuilder::AddRoundedRect
PathBuilder & AddRoundedRect(Rect rect, RoundingRadii radii)
Definition: path_builder.cc:145
impeller::PathBuilder::HorizontalLineTo
PathBuilder & HorizontalLineTo(Scalar x, bool relative=false)
Definition: path_builder.cc:54
impeller::Size
TSize< Scalar > Size
Definition: size.h:137
impeller::PathBuilder::SetConvexity
PathBuilder & SetConvexity(Convexity value)
Definition: path_builder.cc:80
ASSERT_POINT_NEAR
#define ASSERT_POINT_NEAR(a, b)
Definition: geometry_asserts.h:160
impeller::MoveTo
void MoveTo(PathBuilder *builder, Scalar x, Scalar y)
Definition: tessellator.cc:18
impeller::PathBuilder::AddRect
PathBuilder & AddRect(Rect rect)
Definition: path_builder.cc:112
ASSERT_RECT_NEAR
#define ASSERT_RECT_NEAR(a, b)
Definition: geometry_asserts.h:158
path_builder.h
impeller::Path::Polyline
Definition: path.h:94
impeller::Convexity::kUnknown
@ kUnknown
impeller::CubicPathComponent::cp1
Point cp1
Definition: path_component.h:103
impeller::Point
TPoint< Scalar > Point
Definition: point.h:316
impeller::LinearPathComponent::p1
Point p1
Definition: path_component.h:30
impeller::PathBuilder::Shift
PathBuilder & Shift(Point offset)
Transform the existing path segments and contours by the given offset.
Definition: path_builder.cc:442
impeller::PathBuilder::QuadraticCurveTo
PathBuilder & QuadraticCurveTo(Point controlPoint, Point point, bool relative=false)
Insert a quadradic curve from the current position to point using the control point controlPoint.
Definition: path_builder.cc:70
impeller::Path
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
Definition: path.h:51
impeller::PathBuilder::CopyPath
Path CopyPath(FillType fill=FillType::kNonZero)
Definition: path_builder.cc:17
impeller::ContourComponent::is_closed
bool is_closed
Definition: path_component.h:154
impeller::testing::TEST
TEST(CanvasRecorder, Save)
Definition: canvas_recorder_unittests.cc:65
impeller::PathBuilder::LineTo
PathBuilder & LineTo(Point point, bool relative=false)
Insert a line from the current position to point.
Definition: path_builder.cc:47
impeller::PathBuilder::AddCubicCurve
PathBuilder & AddCubicCurve(Point p1, Point cp1, Point cp2, Point p2)
Move to point p1, then insert a cubic curve from p1 to p2 with control points cp1 and cp2.
Definition: path_builder.cc:103
impeller::PathBuilder::AddLine
PathBuilder & AddLine(const Point &p1, const Point &p2)
Move to point p1, then insert a line from p1 to p2.
Definition: path_builder.cc:419
impeller::PathBuilder::TakePath
Path TakePath(FillType fill=FillType::kNonZero)
Definition: path_builder.cc:22
impeller::ContourComponent::destination
Point destination
Definition: path_component.h:153
impeller::Path::GetContourComponentAtIndex
bool GetContourComponentAtIndex(size_t index, ContourComponent &contour) const
Definition: path.cc:163
impeller::CubicPathComponent
Definition: path_component.h:99
impeller::Close
void Close(PathBuilder *builder)
Definition: tessellator.cc:36
impeller::PathBuilder::Close
PathBuilder & Close()
Definition: path_builder.cc:40
impeller::LineTo
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
Definition: tessellator.cc:22
impeller::QuadraticPathComponent::p2
Point p2
Definition: path_component.h:59
impeller::TPoint< Scalar >
impeller::TRect< Scalar >::MakeMaximum
constexpr static TRect MakeMaximum()
Definition: rect.h:174
impeller::Path::GetComponentCount
size_t GetComponentCount(std::optional< ComponentType > type={}) const
Definition: path.cc:34
impeller::PathBuilder::MoveTo
PathBuilder & MoveTo(Point point, bool relative=false)
Definition: path_builder.cc:33
impeller::PathBuilder::VerticalLineTo
PathBuilder & VerticalLineTo(Scalar y, bool relative=false)
Definition: path_builder.cc:62
impeller::Degrees
Definition: scalar.h:46
impeller::Path::Polyline::PointBufferPtr
std::unique_ptr< std::vector< Point > > PointBufferPtr
Definition: path.h:97
impeller::CubicPathComponent::p2
Point p2
Definition: path_component.h:107
impeller::PathBuilder::AddCircle
PathBuilder & AddCircle(const Point &center, Scalar radius)
Definition: path_builder.cc:130
impeller::CubicPathComponent::Extrema
std::vector< Point > Extrema() const
Definition: path_component.cc:312
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller::PathBuilder::AddOval
PathBuilder & AddOval(const Rect &rect)
Definition: path_builder.cc:371
offset
Point offset
Definition: stroke_path_geometry.cc:300
impeller::ContourComponent
Definition: path_component.h:152
impeller::Convexity::kConvex
@ kConvex
impeller
Definition: aiks_blur_unittests.cc:20
impeller::QuadraticPathComponent
Definition: path_component.h:53
impeller::Path::CreatePolyline
Polyline CreatePolyline(Scalar scale, Polyline::PointBufferPtr point_buffer=std::make_unique< std::vector< Point >>(), Polyline::ReclaimPointBufferCallback reclaim=nullptr) const
Definition: path.cc:198
impeller::Path::GetLinearComponentAtIndex
bool GetLinearComponentAtIndex(size_t index, LinearPathComponent &linear) const
Definition: path.cc:106
impeller::Path::ComponentType::kContour
@ kContour
impeller::TRect
Definition: rect.h:122
impeller::PathBuilder::AddArc
PathBuilder & AddArc(const Rect &oval_bounds, Radians start, Radians sweep, bool use_center=false)
Definition: path_builder.cc:313