| Flutter Impeller |

tessellator_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 "flutter/testing/testing.h"
6 #include "gtest/gtest.h"
7
8 #include "flutter/display_list/geometry/dl_path_builder.h"
9 #include "impeller/geometry/geometry_asserts.h"
10 #include "impeller/tessellator/tessellator.h"
11 #include "impeller/tessellator/tessellator_libtess.h"
12
13 namespace impeller {
14 namespace testing {
15
16 TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) {
17 // Zero points.
18 {
19 TessellatorLibtess t;
20 auto path = flutter::DlPathBuilder{} //
21 .SetFillType(FillType::kOdd)
22 .TakePath();
23 TessellatorLibtess::Result result = t.Tessellate(
24 path, 1.0f,
25 [](const float* vertices, size_t vertices_count,
26 const uint16_t* indices, size_t indices_count) { return true; });
27
28 ASSERT_EQ(result, TessellatorLibtess::Result::kInputError);
29 }
30
31 // One point.
32 {
33 TessellatorLibtess t;
34 auto path = flutter::DlPathBuilder{}
35 .LineTo({0, 0})
36 .SetFillType(FillType::kOdd)
37 .TakePath();
38 TessellatorLibtess::Result result = t.Tessellate(
39 path, 1.0f,
40 [](const float* vertices, size_t vertices_count,
41 const uint16_t* indices, size_t indices_count) { return true; });
42
43 ASSERT_EQ(result, TessellatorLibtess::Result::kSuccess);
44 }
45
46 // Two points.
47 {
48 TessellatorLibtess t;
49 auto path = flutter::DlPathBuilder{}
50 .MoveTo({0, 0})
51 .LineTo({0, 1})
52 .SetFillType(FillType::kOdd)
53 .TakePath();
54 TessellatorLibtess::Result result = t.Tessellate(
55 path, 1.0f,
56 [](const float* vertices, size_t vertices_count,
57 const uint16_t* indices, size_t indices_count) { return true; });
58
59 ASSERT_EQ(result, TessellatorLibtess::Result::kSuccess);
60 }
61
62 // Many points.
63 {
64 TessellatorLibtess t;
65 flutter::DlPathBuilder builder;
66 for (int i = 0; i < 1000; i++) {
67 auto coord = i * 1.0f;
68 builder.MoveTo({coord, coord}).LineTo({coord + 1, coord + 1});
69 }
70 auto path = builder.SetFillType(FillType::kOdd).TakePath();
71 TessellatorLibtess::Result result = t.Tessellate(
72 path, 1.0f,
73 [](const float* vertices, size_t vertices_count,
74 const uint16_t* indices, size_t indices_count) { return true; });
75
76 ASSERT_EQ(result, TessellatorLibtess::Result::kSuccess);
77 }
78
79 // Closure fails.
80 {
81 TessellatorLibtess t;
82 auto path = flutter::DlPathBuilder{}
83 .MoveTo({0, 0})
84 .LineTo({0, 1})
85 .SetFillType(FillType::kOdd)
86 .TakePath();
87 TessellatorLibtess::Result result = t.Tessellate(
88 path, 1.0f,
89 [](const float* vertices, size_t vertices_count,
90 const uint16_t* indices, size_t indices_count) { return false; });
91
92 ASSERT_EQ(result, TessellatorLibtess::Result::kInputError);
93 }
94 }
95
96 TEST(TessellatorTest, TessellateConvex) {
97 {
98 std::vector<Point> points;
99 std::vector<uint16_t> indices;
100 // Sanity check simple rectangle.
101 Tessellator::TessellateConvexInternal(
102 flutter::DlPath::MakeRect(Rect::MakeLTRB(0, 0, 10, 10)), points,
103 indices, 1.0);
104
105 // Note: the origin point is repeated but not referenced in the indices
106 // below
107 std::vector<Point> expected = {{0, 0}, {10, 0}, {10, 10}, {0, 10}, {0, 0}};
108 std::vector<uint16_t> expected_indices = {0, 1, 3, 2};
109 EXPECT_EQ(points, expected);
110 EXPECT_EQ(indices, expected_indices);
111 }
112
113 {
114 std::vector<Point> points;
115 std::vector<uint16_t> indices;
116 Tessellator::TessellateConvexInternal(
117 flutter::DlPath(flutter::DlPathBuilder{}
118 .AddRect(Rect::MakeLTRB(0, 0, 10, 10))
119 .AddRect(Rect::MakeLTRB(20, 20, 30, 30))
120 .TakePath()),
121 points, indices, 1.0);
122
123 std::vector<Point> expected = {{0, 0}, {10, 0}, {10, 10}, {0, 10},
124 {0, 0}, {20, 20}, {30, 20}, {30, 30},
125 {20, 30}, {20, 20}};
126 std::vector<uint16_t> expected_indices = {0, 1, 3, 2, 2, 5, 5, 6, 8, 7};
127 EXPECT_EQ(points, expected);
128 EXPECT_EQ(indices, expected_indices);
129 }
130 }
131
132 // Filled Paths without an explicit close should still be closed implicitly
133 TEST(TessellatorTest, TessellateConvexUnclosedPath) {
134 std::vector<Point> points;
135 std::vector<uint16_t> indices;
136
137 // Create a rectangle that lacks an explicit close.
138 flutter::DlPath path = flutter::DlPathBuilder{}
139 .LineTo({100, 0})
140 .LineTo({100, 100})
141 .LineTo({0, 100})
142 .TakePath();
143 Tessellator::TessellateConvexInternal(flutter::DlPath(path), points, indices,
144 1.0);
145
146 std::vector<Point> expected = {
147 {0, 0}, {100, 0}, {100, 100}, {0, 100}, {0, 0}};
148 std::vector<uint16_t> expected_indices = {0, 1, 3, 2};
149 EXPECT_EQ(points, expected);
150 EXPECT_EQ(indices, expected_indices);
151 }
152
153 TEST(TessellatorTest, CircleVertexCounts) {
154 auto tessellator = std::make_shared<Tessellator>();
155
156 auto test = [&tessellator](const Matrix& transform, Scalar radius) {
157 auto generator = tessellator->FilledCircle(transform, {}, radius);
158 size_t quadrant_divisions = generator.GetVertexCount() / 4;
159
160 // Confirm the approximation error is within the currently accepted
161 // |kCircleTolerance| value advertised by |CircleTessellator|.
162 // (With an additional 1% tolerance for floating point rounding.)
163 double angle = kPiOver2 / quadrant_divisions;
164 Point first = {radius, 0};
165 Point next = {static_cast<Scalar>(cos(angle) * radius),
166 static_cast<Scalar>(sin(angle) * radius)};
167 Point midpoint = (first + next) * 0.5;
168 EXPECT_GE(midpoint.GetLength(),
169 radius - Tessellator::kCircleTolerance * 1.01)
170 << ", transform = " << transform << ", radius = " << radius
171 << ", divisions = " << quadrant_divisions;
172 };
173
174 test({}, 0.0);
175 test({}, 0.9);
176 test({}, 1.0);
177 test({}, 1.9);
178 test(Matrix::MakeScale(Vector2(2.0, 2.0)), 0.95);
179 test({}, 2.0);
180 test(Matrix::MakeScale(Vector2(2.0, 2.0)), 1.0);
181 test({}, 11.9);
182 test({}, 12.0);
183 test({}, 35.9);
184 for (int i = 36; i < 10000; i += 4) {
185 test({}, i);
186 }
187 }
188
189 TEST(TessellatorTest, FilledCircleTessellationVertices) {
190 auto tessellator = std::make_shared<Tessellator>();
191
192 auto test = [&tessellator](const Matrix& transform, const Point& center,
193 Scalar radius) {
194 auto generator = tessellator->FilledCircle(transform, center, radius);
195 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
196
197 auto vertex_count = generator.GetVertexCount();
198 auto vertices = std::vector<Point>();
199 generator.GenerateVertices([&vertices](const Point& p) { //
200 vertices.push_back(p);
201 });
202 EXPECT_EQ(vertices.size(), vertex_count);
203 ASSERT_EQ(vertex_count % 4, 0u);
204
205 auto quadrant_count = vertex_count / 4;
206 for (size_t i = 0; i < quadrant_count; i++) {
207 double angle = kPiOver2 * i / (quadrant_count - 1);
208 double degrees = angle * 180.0 / kPi;
209 double rsin = sin(angle) * radius;
210 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
211 double rcos = (i == quadrant_count - 1) ? 0.0f : cos(angle) * radius;
212 EXPECT_POINT_NEAR(vertices[i * 2],
213 Point(center.x - rcos, center.y + rsin))
214 << "vertex " << i << ", angle = " << degrees << std::endl;
215 EXPECT_POINT_NEAR(vertices[i * 2 + 1],
216 Point(center.x - rcos, center.y - rsin))
217 << "vertex " << i << ", angle = " << degrees << std::endl;
218 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 1],
219 Point(center.x + rcos, center.y - rsin))
220 << "vertex " << i << ", angle = " << degrees << std::endl;
221 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 2],
222 Point(center.x + rcos, center.y + rsin))
223 << "vertex " << i << ", angle = " << degrees << std::endl;
224 }
225 };
226
227 test({}, {}, 2.0);
228 test({}, {10, 10}, 2.0);
229 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {}, 2.0);
230 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {}, 1000.0);
231 }
232
233 TEST(TessellatorTest, StrokedCircleTessellationVertices) {
234 auto tessellator = std::make_shared<Tessellator>();
235
236 auto test = [&tessellator](const Matrix& transform, const Point& center,
237 Scalar radius, Scalar half_width) {
238 ASSERT_GT(radius, half_width);
239 auto generator =
240 tessellator->StrokedCircle(transform, center, radius, half_width);
241 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
242
243 auto vertex_count = generator.GetVertexCount();
244 auto vertices = std::vector<Point>();
245 generator.GenerateVertices([&vertices](const Point& p) { //
246 vertices.push_back(p);
247 });
248 EXPECT_EQ(vertices.size(), vertex_count);
249 ASSERT_EQ(vertex_count % 4, 0u);
250
251 auto quadrant_count = vertex_count / 8;
252
253 // Test outer points first
254 for (size_t i = 0; i < quadrant_count; i++) {
255 double angle = kPiOver2 * i / (quadrant_count - 1);
256 double degrees = angle * 180.0 / kPi;
257 double rsin = sin(angle) * (radius + half_width);
258 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
259 double rcos =
260 (i == quadrant_count - 1) ? 0.0f : cos(angle) * (radius + half_width);
261 EXPECT_POINT_NEAR(vertices[i * 2],
262 Point(center.x - rcos, center.y - rsin))
263 << "vertex " << i << ", angle = " << degrees << std::endl;
264 EXPECT_POINT_NEAR(vertices[quadrant_count * 2 + i * 2],
265 Point(center.x + rsin, center.y - rcos))
266 << "vertex " << i << ", angle = " << degrees << std::endl;
267 EXPECT_POINT_NEAR(vertices[quadrant_count * 4 + i * 2],
268 Point(center.x + rcos, center.y + rsin))
269 << "vertex " << i << ", angle = " << degrees << std::endl;
270 EXPECT_POINT_NEAR(vertices[quadrant_count * 6 + i * 2],
271 Point(center.x - rsin, center.y + rcos))
272 << "vertex " << i << ", angle = " << degrees << std::endl;
273 }
274
275 // Then test innerer points
276 for (size_t i = 0; i < quadrant_count; i++) {
277 double angle = kPiOver2 * i / (quadrant_count - 1);
278 double degrees = angle * 180.0 / kPi;
279 double rsin = sin(angle) * (radius - half_width);
280 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
281 double rcos =
282 (i == quadrant_count - 1) ? 0.0f : cos(angle) * (radius - half_width);
283 EXPECT_POINT_NEAR(vertices[i * 2 + 1],
284 Point(center.x - rcos, center.y - rsin))
285 << "vertex " << i << ", angle = " << degrees << std::endl;
286 EXPECT_POINT_NEAR(vertices[quadrant_count * 2 + i * 2 + 1],
287 Point(center.x + rsin, center.y - rcos))
288 << "vertex " << i << ", angle = " << degrees << std::endl;
289 EXPECT_POINT_NEAR(vertices[quadrant_count * 4 + i * 2 + 1],
290 Point(center.x + rcos, center.y + rsin))
291 << "vertex " << i << ", angle = " << degrees << std::endl;
292 EXPECT_POINT_NEAR(vertices[quadrant_count * 6 + i * 2 + 1],
293 Point(center.x - rsin, center.y + rcos))
294 << "vertex " << i << ", angle = " << degrees << std::endl;
295 }
296 };
297
298 test({}, {}, 2.0, 1.0);
299 test({}, {}, 2.0, 0.5);
300 test({}, {10, 10}, 2.0, 1.0);
301 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {}, 2.0, 1.0);
302 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {}, 1000.0, 10.0);
303 }
304
305 TEST(TessellatorTest, RoundCapLineTessellationVertices) {
306 auto tessellator = std::make_shared<Tessellator>();
307
308 auto test = [&tessellator](const Matrix& transform, const Point& p0,
309 const Point& p1, Scalar radius) {
310 auto generator = tessellator->RoundCapLine(transform, p0, p1, radius);
311 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
312
313 auto vertex_count = generator.GetVertexCount();
314 auto vertices = std::vector<Point>();
315 generator.GenerateVertices([&vertices](const Point& p) { //
316 vertices.push_back(p);
317 });
318 EXPECT_EQ(vertices.size(), vertex_count);
319 ASSERT_EQ(vertex_count % 4, 0u);
320
321 Point along = p1 - p0;
322 Scalar length = along.GetLength();
323 if (length > 0) {
324 along *= radius / length;
325 } else {
326 along = {radius, 0};
327 }
328 Point across = {-along.y, along.x};
329
330 auto quadrant_count = vertex_count / 4;
331 for (size_t i = 0; i < quadrant_count; i++) {
332 double angle = kPiOver2 * i / (quadrant_count - 1);
333 double degrees = angle * 180.0 / kPi;
334 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
335 Point relative_along =
336 along * ((i == quadrant_count - 1) ? 0.0f : cos(angle));
337 Point relative_across = across * sin(angle);
338 EXPECT_POINT_NEAR(vertices[i * 2], //
339 p0 - relative_along + relative_across)
340 << "vertex " << i << ", angle = " << degrees << ", " //
341 << "line = " << p0 << " => " << p1 << ", " //
342 << "radius = " << radius << std::endl;
343 EXPECT_POINT_NEAR(vertices[i * 2 + 1], //
344 p0 - relative_along - relative_across)
345 << "vertex " << i << ", angle = " << degrees << ", " //
346 << "line = " << p0 << " => " << p1 << ", " //
347 << "radius = " << radius << std::endl;
348 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 1], //
349 p1 + relative_along - relative_across)
350 << "vertex " << i << ", angle = " << degrees << ", " //
351 << "line = " << p0 << " => " << p1 << ", " //
352 << "radius = " << radius << std::endl;
353 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 2], //
354 p1 + relative_along + relative_across)
355 << "vertex " << i << ", angle = " << degrees << ", " //
356 << "line = " << p0 << " => " << p1 << ", " //
357 << "radius = " << radius << std::endl;
358 }
359 };
360
361 // Empty line should actually use the circle generator, but its
362 // results should match the same math as the round cap generator.
363 test({}, {0, 0}, {0, 0}, 10);
364
365 test({}, {0, 0}, {10, 0}, 2);
366 test({}, {10, 0}, {0, 0}, 2);
367 test({}, {0, 0}, {10, 10}, 2);
368
369 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {0, 0}, {10, 0}, 2);
370 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {10, 0}, {0, 0}, 2);
371 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {0, 0}, {10, 10}, 2);
372
373 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {0, 0}, {10, 0}, 2);
374 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {10, 0}, {0, 0}, 2);
375 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {0, 0}, {10, 10}, 2);
376 }
377
378 TEST(TessellatorTest, FilledEllipseTessellationVertices) {
379 auto tessellator = std::make_shared<Tessellator>();
380
381 auto test = [&tessellator](const Matrix& transform, const Rect& bounds) {
382 auto center = bounds.GetCenter();
383 auto half_size = bounds.GetSize() * 0.5f;
384
385 auto generator = tessellator->FilledEllipse(transform, bounds);
386 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
387
388 auto vertex_count = generator.GetVertexCount();
389 auto vertices = std::vector<Point>();
390 generator.GenerateVertices([&vertices](const Point& p) { //
391 vertices.push_back(p);
392 });
393 EXPECT_EQ(vertices.size(), vertex_count);
394 ASSERT_EQ(vertex_count % 4, 0u);
395
396 auto quadrant_count = vertex_count / 4;
397 for (size_t i = 0; i < quadrant_count; i++) {
398 double angle = kPiOver2 * i / (quadrant_count - 1);
399 double degrees = angle * 180.0 / kPi;
400 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
401 double rcos =
402 (i == quadrant_count - 1) ? 0.0f : cos(angle) * half_size.width;
403 double rsin = sin(angle) * half_size.height;
404 EXPECT_POINT_NEAR(vertices[i * 2],
405 Point(center.x - rcos, center.y + rsin))
406 << "vertex " << i << ", angle = " << degrees << ", " //
407 << "bounds = " << bounds << std::endl;
408 EXPECT_POINT_NEAR(vertices[i * 2 + 1],
409 Point(center.x - rcos, center.y - rsin))
410 << "vertex " << i << ", angle = " << degrees << ", " //
411 << "bounds = " << bounds << std::endl;
412 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 1],
413 Point(center.x + rcos, center.y - rsin))
414 << "vertex " << i << ", angle = " << degrees << ", " //
415 << "bounds = " << bounds << std::endl;
416 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 2],
417 Point(center.x + rcos, center.y + rsin))
418 << "vertex " << i << ", angle = " << degrees << ", " //
419 << "bounds = " << bounds << std::endl;
420 }
421 };
422
423 // Square bounds should actually use the circle generator, but its
424 // results should match the same math as the ellipse generator.
425 test({}, Rect::MakeXYWH(0, 0, 2, 2));
426
427 test({}, Rect::MakeXYWH(0, 0, 2, 3));
428 test({}, Rect::MakeXYWH(0, 0, 3, 2));
429 test({}, Rect::MakeXYWH(5, 10, 2, 3));
430 test({}, Rect::MakeXYWH(16, 7, 3, 2));
431 test(Matrix::MakeScale({500.0, 500.0, 0.0}), Rect::MakeXYWH(5, 10, 3, 2));
432 test(Matrix::MakeScale({500.0, 500.0, 0.0}), Rect::MakeXYWH(5, 10, 2, 3));
433 test(Matrix::MakeScale({0.002, 0.002, 0.0}),
434 Rect::MakeXYWH(5000, 10000, 3000, 2000));
435 test(Matrix::MakeScale({0.002, 0.002, 0.0}),
436 Rect::MakeXYWH(5000, 10000, 2000, 3000));
437 }
438
439 TEST(TessellatorTest, FilledRoundRectTessellationVertices) {
440 auto tessellator = std::make_shared<Tessellator>();
441
442 auto test = [&tessellator](const Matrix& transform, const Rect& bounds,
443 const Size& radii) {
444 FML_DCHECK(radii.width * 2 <= bounds.GetWidth()) << radii << bounds;
445 FML_DCHECK(radii.height * 2 <= bounds.GetHeight()) << radii << bounds;
446
447 Scalar middle_left = bounds.GetX() + radii.width;
448 Scalar middle_top = bounds.GetY() + radii.height;
449 Scalar middle_right = bounds.GetX() + bounds.GetWidth() - radii.width;
450 Scalar middle_bottom = bounds.GetY() + bounds.GetHeight() - radii.height;
451
452 auto generator = tessellator->FilledRoundRect(transform, bounds, radii);
453 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
454
455 auto vertex_count = generator.GetVertexCount();
456 auto vertices = std::vector<Point>();
457 generator.GenerateVertices([&vertices](const Point& p) { //
458 vertices.push_back(p);
459 });
460 EXPECT_EQ(vertices.size(), vertex_count);
461 ASSERT_EQ(vertex_count % 4, 0u);
462
463 auto quadrant_count = vertex_count / 4;
464 for (size_t i = 0; i < quadrant_count; i++) {
465 double angle = kPiOver2 * i / (quadrant_count - 1);
466 double degrees = angle * 180.0 / kPi;
467 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
468 double rcos = (i == quadrant_count - 1) ? 0.0f : cos(angle) * radii.width;
469 double rsin = sin(angle) * radii.height;
470 EXPECT_POINT_NEAR(vertices[i * 2],
471 Point(middle_left - rcos, middle_bottom + rsin))
472 << "vertex " << i << ", angle = " << degrees << ", " //
473 << "bounds = " << bounds << std::endl;
474 EXPECT_POINT_NEAR(vertices[i * 2 + 1],
475 Point(middle_left - rcos, middle_top - rsin))
476 << "vertex " << i << ", angle = " << degrees << ", " //
477 << "bounds = " << bounds << std::endl;
478 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 1],
479 Point(middle_right + rcos, middle_top - rsin))
480 << "vertex " << i << ", angle = " << degrees << ", " //
481 << "bounds = " << bounds << std::endl;
482 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 2],
483 Point(middle_right + rcos, middle_bottom + rsin))
484 << "vertex " << i << ", angle = " << degrees << ", " //
485 << "bounds = " << bounds << std::endl;
486 }
487 };
488
489 // Both radii spanning the bounds should actually use the circle/ellipse
490 // generator, but their results should match the same math as the round
491 // rect generator.
492 test({}, Rect::MakeXYWH(0, 0, 20, 20), {10, 10});
493
494 // One radius spanning the bounds, but not the other will not match the
495 // round rect math if the generator transfers to circle/ellipse
496 test({}, Rect::MakeXYWH(0, 0, 20, 20), {10, 5});
497 test({}, Rect::MakeXYWH(0, 0, 20, 20), {5, 10});
498
499 test({}, Rect::MakeXYWH(0, 0, 20, 30), {2, 2});
500 test({}, Rect::MakeXYWH(0, 0, 30, 20), {2, 2});
501 test({}, Rect::MakeXYWH(5, 10, 20, 30), {2, 3});
502 test({}, Rect::MakeXYWH(16, 7, 30, 20), {2, 3});
503 test(Matrix::MakeScale({500.0, 500.0, 0.0}), Rect::MakeXYWH(5, 10, 30, 20),
504 {2, 3});
505 test(Matrix::MakeScale({500.0, 500.0, 0.0}), Rect::MakeXYWH(5, 10, 20, 30),
506 {2, 3});
507 test(Matrix::MakeScale({0.002, 0.002, 0.0}),
508 Rect::MakeXYWH(5000, 10000, 3000, 2000), {50, 70});
509 test(Matrix::MakeScale({0.002, 0.002, 0.0}),
510 Rect::MakeXYWH(5000, 10000, 2000, 3000), {50, 70});
511 }
512
513 TEST(TessellatorTest, EarlyReturnEmptyConvexShape) {
514 // This path is not technically empty (it has a size in one dimension), but
515 // it contains only move commands and no actual path segment definitions.
516 flutter::DlPathBuilder builder;
517 builder.MoveTo({0, 0});
518 builder.MoveTo({10, 10});
519
520 std::vector<Point> points;
521 std::vector<uint16_t> indices;
522 Tessellator::TessellateConvexInternal(builder.TakePath(), points, indices,
523 3.0f);
524
525 EXPECT_TRUE(points.empty());
526 EXPECT_TRUE(indices.empty());
527 }
528
529 } // namespace testing
530 } // namespace impeller
impeller::Tessellator::kCircleTolerance
static constexpr Scalar kCircleTolerance
The pixel tolerance used by the algorighm to determine how many divisions to create for a circle.
Definition: tessellator.h:263
impeller::Tessellator::TessellateConvexInternal
static void TessellateConvexInternal(const PathSource &path, std::vector< Point > &point_buffer, std::vector< uint16_t > &index_buffer, Scalar tolerance)
Definition: tessellator.cc:399
impeller::TessellatorLibtess
An extended tessellator that offers arbitrary/concave tessellation via the libtess2 library.
Definition: tessellator_libtess.h:29
impeller::TessellatorLibtess::Result
Result
Definition: tessellator_libtess.h:35
impeller::TessellatorLibtess::Result::kSuccess
@ kSuccess
impeller::TessellatorLibtess::Result::kInputError
@ kInputError
impeller::TessellatorLibtess::Tessellate
TessellatorLibtess::Result Tessellate(const PathSource &source, Scalar tolerance, const BuilderCallback &callback)
Generates filled triangles from the path. A callback is invoked once for the entire tessellation.
Definition: tessellator_libtess.cc:85
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:214
geometry_asserts.h
EXPECT_POINT_NEAR
#define EXPECT_POINT_NEAR(a, b)
Definition: geometry_asserts.h:205
impeller::testing::TEST
TEST(AllocationSizeTest, CanCreateTypedAllocations)
Definition: allocation_size_unittests.cc:10
impeller
Definition: allocation.cc:12
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Vector2
Point Vector2
Definition: point.h:331
impeller::kPi
constexpr float kPi
Definition: constants.h:26
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::FillType::kOdd
@ kOdd
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::kPiOver2
constexpr float kPiOver2
Definition: constants.h:32
impeller::DlPath
flutter::DlPath DlPath
Definition: dl_dispatcher.h:29
impeller::LineTo
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
Definition: tessellator.cc:24
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::TPoint< Scalar >
impeller::TPoint::GetLength
constexpr Type GetLength() const
Definition: point.h:206
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::TRect< Scalar >
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller::TSize< Scalar >
tessellator.h
points
std::vector< Point > points
Definition: tessellator_libtess.cc:76
tessellator_libtess.h