Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
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
6#include "gtest/gtest.h"
7
13
14namespace impeller {
15namespace testing {
16
17TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) {
18 // Zero points.
19 {
23 .TakePath();
25 path, 1.0f,
26 [](const float* vertices, size_t vertices_count,
27 const uint16_t* indices, size_t indices_count) { return true; });
28
30 }
31
32 // One point.
33 {
36 .LineTo({0, 0})
37 .SetFillType(FillType::kOdd)
38 .TakePath();
40 path, 1.0f,
41 [](const float* vertices, size_t vertices_count,
42 const uint16_t* indices, size_t indices_count) { return true; });
43
44 ASSERT_EQ(result, TessellatorLibtess::Result::kSuccess);
45 }
46
47 // Two points.
48 {
51 .MoveTo({0, 0})
52 .LineTo({0, 1})
53 .SetFillType(FillType::kOdd)
54 .TakePath();
56 path, 1.0f,
57 [](const float* vertices, size_t vertices_count,
58 const uint16_t* indices, size_t indices_count) { return true; });
59
60 ASSERT_EQ(result, TessellatorLibtess::Result::kSuccess);
61 }
62
63 // Many points.
64 {
67 for (int i = 0; i < 1000; i++) {
68 auto coord = i * 1.0f;
69 builder.MoveTo({coord, coord}).LineTo({coord + 1, coord + 1});
70 }
71 auto path = builder.SetFillType(FillType::kOdd).TakePath();
73 path, 1.0f,
74 [](const float* vertices, size_t vertices_count,
75 const uint16_t* indices, size_t indices_count) { return true; });
76
77 ASSERT_EQ(result, TessellatorLibtess::Result::kSuccess);
78 }
79
80 // Closure fails.
81 {
84 .MoveTo({0, 0})
85 .LineTo({0, 1})
86 .SetFillType(FillType::kOdd)
87 .TakePath();
89 path, 1.0f,
90 [](const float* vertices, size_t vertices_count,
91 const uint16_t* indices, size_t indices_count) { return false; });
92
94 }
95}
96
97TEST(TessellatorTest, TessellateConvex) {
98 {
99 std::vector<Point> points;
100 std::vector<uint16_t> indices;
101 // Sanity check simple rectangle.
104 indices, 1.0);
105
106 // Note: the origin point is repeated but not referenced in the indices
107 // below
108 std::vector<Point> expected = {{0, 0}, {10, 0}, {10, 10}, {0, 10}, {0, 0}};
109 std::vector<uint16_t> expected_indices = {0, 1, 3, 2};
110 EXPECT_EQ(points, expected);
111 EXPECT_EQ(indices, expected_indices);
112 }
113
114 {
115 std::vector<Point> points;
116 std::vector<uint16_t> indices;
119 .AddRect(Rect::MakeLTRB(0, 0, 10, 10))
120 .AddRect(Rect::MakeLTRB(20, 20, 30, 30))
121 .TakePath()),
122 points, indices, 1.0);
123
124 std::vector<Point> expected = {{0, 0}, {10, 0}, {10, 10}, {0, 10},
125 {0, 0}, {20, 20}, {30, 20}, {30, 30},
126 {20, 30}, {20, 20}};
127 std::vector<uint16_t> expected_indices = {0, 1, 3, 2, 2, 5, 5, 6, 8, 7};
128 EXPECT_EQ(points, expected);
129 EXPECT_EQ(indices, expected_indices);
130 }
131}
132
133// Filled Paths without an explicit close should still be closed implicitly
134TEST(TessellatorTest, TessellateConvexUnclosedPath) {
135 std::vector<Point> points;
136 std::vector<uint16_t> indices;
137
138 // Create a rectangle that lacks an explicit close.
140 .LineTo({100, 0})
141 .LineTo({100, 100})
142 .LineTo({0, 100})
143 .TakePath();
145 1.0);
146
147 std::vector<Point> expected = {
148 {0, 0}, {100, 0}, {100, 100}, {0, 100}, {0, 0}};
149 std::vector<uint16_t> expected_indices = {0, 1, 3, 2};
150 EXPECT_EQ(points, expected);
151 EXPECT_EQ(indices, expected_indices);
152}
153
154TEST(TessellatorTest, CircleVertexCounts) {
155 Tessellator tessellator;
156
157 auto test = [&tessellator](const Matrix& transform, Scalar radius) {
158 auto generator = tessellator.FilledCircle(transform, {}, radius);
159 size_t quadrant_divisions = generator.GetVertexCount() / 4;
160
161 // Confirm the approximation error is within the currently accepted
162 // |kCircleTolerance| value advertised by |CircleTessellator|.
163 // (With an additional 1% tolerance for floating point rounding.)
164 double angle = kPiOver2 / quadrant_divisions;
165 Point first = {radius, 0};
166 Point next = {static_cast<Scalar>(cos(angle) * radius),
167 static_cast<Scalar>(sin(angle) * radius)};
168 Point midpoint = (first + next) * 0.5;
169 EXPECT_GE(midpoint.GetLength(),
170 radius - Tessellator::kCircleTolerance * 1.01)
171 << ", transform = " << transform << ", radius = " << radius
172 << ", divisions = " << quadrant_divisions;
173 };
174
175 test({}, 0.0);
176 test({}, 0.9);
177 test({}, 1.0);
178 test({}, 1.9);
179 test(Matrix::MakeScale(Vector2(2.0, 2.0)), 0.95);
180 test({}, 2.0);
181 test(Matrix::MakeScale(Vector2(2.0, 2.0)), 1.0);
182 test({}, 11.9);
183 test({}, 12.0);
184 test({}, 35.9);
185 for (int i = 36; i < 10000; i += 4) {
186 test({}, i);
187 }
188}
189
190TEST(TessellatorTest, FilledCircleTessellationVertices) {
191 Tessellator tessellator;
192
193 auto test = [&tessellator](const Matrix& transform, const Point& center,
194 Scalar radius) {
195 auto generator = tessellator.FilledCircle(transform, center, radius);
196 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
197
198 auto vertex_count = generator.GetVertexCount();
199 auto vertices = std::vector<Point>();
200 generator.GenerateVertices([&vertices](const Point& p) { //
201 vertices.push_back(p);
202 });
203 EXPECT_EQ(vertices.size(), vertex_count);
204 ASSERT_EQ(vertex_count % 4, 0u);
205
206 auto quadrant_count = vertex_count / 4;
207 for (size_t i = 0; i < quadrant_count; i++) {
208 double angle = kPiOver2 * i / (quadrant_count - 1);
209 double degrees = angle * 180.0 / kPi;
210 double rsin = sin(angle) * radius;
211 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
212 double rcos = (i == quadrant_count - 1) ? 0.0f : cos(angle) * radius;
213 EXPECT_POINT_NEAR(vertices[i * 2],
214 Point(center.x - rcos, center.y + rsin))
215 << "vertex " << i << ", angle = " << degrees << std::endl;
216 EXPECT_POINT_NEAR(vertices[i * 2 + 1],
217 Point(center.x - rcos, center.y - rsin))
218 << "vertex " << i << ", angle = " << degrees << std::endl;
219 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 1],
220 Point(center.x + rcos, center.y - rsin))
221 << "vertex " << i << ", angle = " << degrees << std::endl;
222 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 2],
223 Point(center.x + rcos, center.y + rsin))
224 << "vertex " << i << ", angle = " << degrees << std::endl;
225 }
226 };
227
228 test({}, {}, 2.0);
229 test({}, {10, 10}, 2.0);
230 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {}, 2.0);
231 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {}, 1000.0);
232}
233
234TEST(TessellatorTest, StrokedCircleTessellationVertices) {
235 Tessellator tessellator;
236
237 auto test = [&tessellator](const Matrix& transform, const Point& center,
238 Scalar radius, Scalar half_width) {
239 ASSERT_GT(radius, half_width);
240 auto generator =
241 tessellator.StrokedCircle(transform, center, radius, half_width);
242 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
243
244 auto vertex_count = generator.GetVertexCount();
245 auto vertices = std::vector<Point>();
246 generator.GenerateVertices([&vertices](const Point& p) { //
247 vertices.push_back(p);
248 });
249 EXPECT_EQ(vertices.size(), vertex_count);
250 ASSERT_EQ(vertex_count % 4, 0u);
251
252 auto quadrant_count = vertex_count / 8;
253
254 // Test outer points first
255 for (size_t i = 0; i < quadrant_count; i++) {
256 double angle = kPiOver2 * i / (quadrant_count - 1);
257 double degrees = angle * 180.0 / kPi;
258 double rsin = sin(angle) * (radius + half_width);
259 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
260 double rcos =
261 (i == quadrant_count - 1) ? 0.0f : cos(angle) * (radius + half_width);
262 EXPECT_POINT_NEAR(vertices[i * 2],
263 Point(center.x - rcos, center.y - rsin))
264 << "vertex " << i << ", angle = " << degrees << std::endl;
265 EXPECT_POINT_NEAR(vertices[quadrant_count * 2 + i * 2],
266 Point(center.x + rsin, center.y - rcos))
267 << "vertex " << i << ", angle = " << degrees << std::endl;
268 EXPECT_POINT_NEAR(vertices[quadrant_count * 4 + i * 2],
269 Point(center.x + rcos, center.y + rsin))
270 << "vertex " << i << ", angle = " << degrees << std::endl;
271 EXPECT_POINT_NEAR(vertices[quadrant_count * 6 + i * 2],
272 Point(center.x - rsin, center.y + rcos))
273 << "vertex " << i << ", angle = " << degrees << std::endl;
274 }
275
276 // Then test innerer points
277 for (size_t i = 0; i < quadrant_count; i++) {
278 double angle = kPiOver2 * i / (quadrant_count - 1);
279 double degrees = angle * 180.0 / kPi;
280 double rsin = sin(angle) * (radius - half_width);
281 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
282 double rcos =
283 (i == quadrant_count - 1) ? 0.0f : cos(angle) * (radius - half_width);
284 EXPECT_POINT_NEAR(vertices[i * 2 + 1],
285 Point(center.x - rcos, center.y - rsin))
286 << "vertex " << i << ", angle = " << degrees << std::endl;
287 EXPECT_POINT_NEAR(vertices[quadrant_count * 2 + i * 2 + 1],
288 Point(center.x + rsin, center.y - rcos))
289 << "vertex " << i << ", angle = " << degrees << std::endl;
290 EXPECT_POINT_NEAR(vertices[quadrant_count * 4 + i * 2 + 1],
291 Point(center.x + rcos, center.y + rsin))
292 << "vertex " << i << ", angle = " << degrees << std::endl;
293 EXPECT_POINT_NEAR(vertices[quadrant_count * 6 + i * 2 + 1],
294 Point(center.x - rsin, center.y + rcos))
295 << "vertex " << i << ", angle = " << degrees << std::endl;
296 }
297 };
298
299 test({}, {}, 2.0, 1.0);
300 test({}, {}, 2.0, 0.5);
301 test({}, {10, 10}, 2.0, 1.0);
302 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {}, 2.0, 1.0);
303 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {}, 1000.0, 10.0);
304}
305
306TEST(TessellatorTest, FilledArcStripTessellationVertices) {
307 Tessellator tessellator;
308
309 auto test = [&tessellator](const Matrix& transform, const Arc& arc) {
310 auto generator = tessellator.FilledArc(transform, arc,
311 /*supports_triangle_fans=*/false);
312 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
313
314 auto vertex_count = generator.GetVertexCount();
315 auto vertices = std::vector<Point>();
316 generator.GenerateVertices([&vertices](const Point& p) { //
317 vertices.push_back(p);
318 });
319 EXPECT_EQ(vertices.size(), vertex_count);
320
321 auto center = arc.GetOvalBounds().GetCenter();
322 auto radius = arc.GetOvalSize().width * 0.5;
323
324 // Test position of first point
326 vertices[0],
327 Point(center.x + cos(Radians(arc.GetStart()).radians) * radius,
328 center.y + sin(Radians(arc.GetStart()).radians) * radius));
329
330 // Test position of last point
331 auto last_angle = arc.GetStart() + arc.GetSweep();
333 vertices[vertex_count - 1],
334 Point(center.x + cos(Radians(last_angle).radians) * radius,
335 center.y + sin(Radians(last_angle).radians) * radius));
336
337 // Test odd-indexed points. These are all the origin.
338 Point origin = arc.IncludeCenter()
339 ? center
340 : (vertices[0] + vertices[vertex_count - 1]) * 0.5f;
341 for (size_t i = 1; i < vertex_count; i += 2) {
342 EXPECT_POINT_NEAR(vertices[i], origin);
343 }
344
345 // Test even-indexed points. These are points on the outer edge of the arc.
346 auto previous_outer_point = vertices[0];
347 auto outer_increment_distance = (vertices[4] - vertices[2]).GetLength();
348 for (size_t i = 2; i < vertex_count; i += 2) {
349 // Each is |radius| from the center.
350 EXPECT_NEAR((vertices[i] - center).GetLength(), radius, kEhCloseEnough);
351
352 // Each is within |outer_increment_distance| from the previous
353 if (i == 2 || i == vertex_count - 1) {
354 // The very first and last points may be closer than
355 // |outer_increment_distance| to their adjacent outer points
356 EXPECT_LE((vertices[i] - previous_outer_point).GetLength(),
357 outer_increment_distance + kEhCloseEnough);
358 } else {
359 // Other outer points are |outer_increment_distance| apart
360 EXPECT_NEAR((vertices[i] - previous_outer_point).GetLength(),
361 outer_increment_distance, kEhCloseEnough);
362 }
363
364 previous_outer_point = vertices[i];
365 }
366 };
367
368 test({}, Arc(Rect::MakeXYWH(0, 0, 100, 100), Degrees(0), Degrees(90), false));
369 test({}, Arc(Rect::MakeXYWH(0, 0, 100, 100), Degrees(0), Degrees(90), true));
370
371 test({},
372 Arc(Rect::MakeXYWH(0, 0, 100, 100), Degrees(0), Degrees(-270), false));
373 test({},
374 Arc(Rect::MakeXYWH(0, 0, 100, 100), Degrees(0), Degrees(-270), true));
375
376 test({},
377 Arc(Rect::MakeXYWH(0, 0, 100, 100), Degrees(94), Degrees(322), false));
378 test({},
379 Arc(Rect::MakeXYWH(0, 0, 100, 100), Degrees(94), Degrees(322), true));
380}
381
382TEST(TessellatorTest, RoundCapLineTessellationVertices) {
383 Tessellator tessellator;
384
385 auto test = [&tessellator](const Matrix& transform, const Point& p0,
386 const Point& p1, Scalar radius) {
387 auto generator = tessellator.RoundCapLine(transform, p0, p1, radius);
388 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
389
390 auto vertex_count = generator.GetVertexCount();
391 auto vertices = std::vector<Point>();
392 generator.GenerateVertices([&vertices](const Point& p) { //
393 vertices.push_back(p);
394 });
395 EXPECT_EQ(vertices.size(), vertex_count);
396 ASSERT_EQ(vertex_count % 4, 0u);
397
398 Point along = p1 - p0;
399 Scalar length = along.GetLength();
400 if (length > 0) {
401 along *= radius / length;
402 } else {
403 along = {radius, 0};
404 }
405 Point across = {-along.y, along.x};
406
407 auto quadrant_count = vertex_count / 4;
408 for (size_t i = 0; i < quadrant_count; i++) {
409 double angle = kPiOver2 * i / (quadrant_count - 1);
410 double degrees = angle * 180.0 / kPi;
411 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
412 Point relative_along =
413 along * ((i == quadrant_count - 1) ? 0.0f : cos(angle));
414 Point relative_across = across * sin(angle);
415 EXPECT_POINT_NEAR(vertices[i * 2], //
416 p0 - relative_along + relative_across)
417 << "vertex " << i << ", angle = " << degrees << ", " //
418 << "line = " << p0 << " => " << p1 << ", " //
419 << "radius = " << radius << std::endl;
420 EXPECT_POINT_NEAR(vertices[i * 2 + 1], //
421 p0 - relative_along - relative_across)
422 << "vertex " << i << ", angle = " << degrees << ", " //
423 << "line = " << p0 << " => " << p1 << ", " //
424 << "radius = " << radius << std::endl;
425 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 1], //
426 p1 + relative_along - relative_across)
427 << "vertex " << i << ", angle = " << degrees << ", " //
428 << "line = " << p0 << " => " << p1 << ", " //
429 << "radius = " << radius << std::endl;
430 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 2], //
431 p1 + relative_along + relative_across)
432 << "vertex " << i << ", angle = " << degrees << ", " //
433 << "line = " << p0 << " => " << p1 << ", " //
434 << "radius = " << radius << std::endl;
435 }
436 };
437
438 // Empty line should actually use the circle generator, but its
439 // results should match the same math as the round cap generator.
440 test({}, {0, 0}, {0, 0}, 10);
441
442 test({}, {0, 0}, {10, 0}, 2);
443 test({}, {10, 0}, {0, 0}, 2);
444 test({}, {0, 0}, {10, 10}, 2);
445
446 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {0, 0}, {10, 0}, 2);
447 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {10, 0}, {0, 0}, 2);
448 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {0, 0}, {10, 10}, 2);
449
450 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {0, 0}, {10, 0}, 2);
451 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {10, 0}, {0, 0}, 2);
452 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {0, 0}, {10, 10}, 2);
453}
454
455TEST(TessellatorTest, FilledEllipseTessellationVertices) {
456 Tessellator tessellator;
457
458 auto test = [&tessellator](const Matrix& transform, const Rect& bounds) {
459 auto center = bounds.GetCenter();
460 auto half_size = bounds.GetSize() * 0.5f;
461
462 auto generator = tessellator.FilledEllipse(transform, bounds);
463 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
464
465 auto vertex_count = generator.GetVertexCount();
466 auto vertices = std::vector<Point>();
467 generator.GenerateVertices([&vertices](const Point& p) { //
468 vertices.push_back(p);
469 });
470 EXPECT_EQ(vertices.size(), vertex_count);
471 ASSERT_EQ(vertex_count % 4, 0u);
472
473 auto quadrant_count = vertex_count / 4;
474 for (size_t i = 0; i < quadrant_count; i++) {
475 double angle = kPiOver2 * i / (quadrant_count - 1);
476 double degrees = angle * 180.0 / kPi;
477 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
478 double rcos =
479 (i == quadrant_count - 1) ? 0.0f : cos(angle) * half_size.width;
480 double rsin = sin(angle) * half_size.height;
481 EXPECT_POINT_NEAR(vertices[i * 2],
482 Point(center.x - rcos, center.y + rsin))
483 << "vertex " << i << ", angle = " << degrees << ", " //
484 << "bounds = " << bounds << std::endl;
485 EXPECT_POINT_NEAR(vertices[i * 2 + 1],
486 Point(center.x - rcos, center.y - rsin))
487 << "vertex " << i << ", angle = " << degrees << ", " //
488 << "bounds = " << bounds << std::endl;
489 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 1],
490 Point(center.x + rcos, center.y - rsin))
491 << "vertex " << i << ", angle = " << degrees << ", " //
492 << "bounds = " << bounds << std::endl;
493 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 2],
494 Point(center.x + rcos, center.y + rsin))
495 << "vertex " << i << ", angle = " << degrees << ", " //
496 << "bounds = " << bounds << std::endl;
497 }
498 };
499
500 // Square bounds should actually use the circle generator, but its
501 // results should match the same math as the ellipse generator.
502 test({}, Rect::MakeXYWH(0, 0, 2, 2));
503
504 test({}, Rect::MakeXYWH(0, 0, 2, 3));
505 test({}, Rect::MakeXYWH(0, 0, 3, 2));
506 test({}, Rect::MakeXYWH(5, 10, 2, 3));
507 test({}, Rect::MakeXYWH(16, 7, 3, 2));
508 test(Matrix::MakeScale({500.0, 500.0, 0.0}), Rect::MakeXYWH(5, 10, 3, 2));
509 test(Matrix::MakeScale({500.0, 500.0, 0.0}), Rect::MakeXYWH(5, 10, 2, 3));
510 test(Matrix::MakeScale({0.002, 0.002, 0.0}),
511 Rect::MakeXYWH(5000, 10000, 3000, 2000));
512 test(Matrix::MakeScale({0.002, 0.002, 0.0}),
513 Rect::MakeXYWH(5000, 10000, 2000, 3000));
514}
515
516TEST(TessellatorTest, FilledRoundRectTessellationVertices) {
517 Tessellator tessellator;
518
519 auto test = [&tessellator](const Matrix& transform, const Rect& bounds,
520 const Size& radii) {
521 FML_DCHECK(radii.width * 2 <= bounds.GetWidth()) << radii << bounds;
522 FML_DCHECK(radii.height * 2 <= bounds.GetHeight()) << radii << bounds;
523
524 Scalar middle_left = bounds.GetX() + radii.width;
525 Scalar middle_top = bounds.GetY() + radii.height;
526 Scalar middle_right = bounds.GetX() + bounds.GetWidth() - radii.width;
527 Scalar middle_bottom = bounds.GetY() + bounds.GetHeight() - radii.height;
528
529 auto generator = tessellator.FilledRoundRect(transform, bounds, radii);
530 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
531
532 auto vertex_count = generator.GetVertexCount();
533 auto vertices = std::vector<Point>();
534 generator.GenerateVertices([&vertices](const Point& p) { //
535 vertices.push_back(p);
536 });
537 EXPECT_EQ(vertices.size(), vertex_count);
538 ASSERT_EQ(vertex_count % 4, 0u);
539
540 auto quadrant_count = vertex_count / 4;
541 for (size_t i = 0; i < quadrant_count; i++) {
542 double angle = kPiOver2 * i / (quadrant_count - 1);
543 double degrees = angle * 180.0 / kPi;
544 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
545 double rcos = (i == quadrant_count - 1) ? 0.0f : cos(angle) * radii.width;
546 double rsin = sin(angle) * radii.height;
547 EXPECT_POINT_NEAR(vertices[i * 2],
548 Point(middle_left - rcos, middle_bottom + rsin))
549 << "vertex " << i << ", angle = " << degrees << ", " //
550 << "bounds = " << bounds << std::endl;
551 EXPECT_POINT_NEAR(vertices[i * 2 + 1],
552 Point(middle_left - rcos, middle_top - rsin))
553 << "vertex " << i << ", angle = " << degrees << ", " //
554 << "bounds = " << bounds << std::endl;
555 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 1],
556 Point(middle_right + rcos, middle_top - rsin))
557 << "vertex " << i << ", angle = " << degrees << ", " //
558 << "bounds = " << bounds << std::endl;
559 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 2],
560 Point(middle_right + rcos, middle_bottom + rsin))
561 << "vertex " << i << ", angle = " << degrees << ", " //
562 << "bounds = " << bounds << std::endl;
563 }
564 };
565
566 // Both radii spanning the bounds should actually use the circle/ellipse
567 // generator, but their results should match the same math as the round
568 // rect generator.
569 test({}, Rect::MakeXYWH(0, 0, 20, 20), {10, 10});
570
571 // One radius spanning the bounds, but not the other will not match the
572 // round rect math if the generator transfers to circle/ellipse
573 test({}, Rect::MakeXYWH(0, 0, 20, 20), {10, 5});
574 test({}, Rect::MakeXYWH(0, 0, 20, 20), {5, 10});
575
576 test({}, Rect::MakeXYWH(0, 0, 20, 30), {2, 2});
577 test({}, Rect::MakeXYWH(0, 0, 30, 20), {2, 2});
578 test({}, Rect::MakeXYWH(5, 10, 20, 30), {2, 3});
579 test({}, Rect::MakeXYWH(16, 7, 30, 20), {2, 3});
580 test(Matrix::MakeScale({500.0, 500.0, 0.0}), Rect::MakeXYWH(5, 10, 30, 20),
581 {2, 3});
582 test(Matrix::MakeScale({500.0, 500.0, 0.0}), Rect::MakeXYWH(5, 10, 20, 30),
583 {2, 3});
584 test(Matrix::MakeScale({0.002, 0.002, 0.0}),
585 Rect::MakeXYWH(5000, 10000, 3000, 2000), {50, 70});
586 test(Matrix::MakeScale({0.002, 0.002, 0.0}),
587 Rect::MakeXYWH(5000, 10000, 2000, 3000), {50, 70});
588}
589
590TEST(TessellatorTest, EarlyReturnEmptyConvexShape) {
591 // This path is not technically empty (it has a size in one dimension), but
592 // it contains only move commands and no actual path segment definitions.
594 builder.MoveTo({0, 0});
595 builder.MoveTo({10, 10});
596
597 std::vector<Point> points;
598 std::vector<uint16_t> indices;
600 3.0f);
601
602 EXPECT_TRUE(points.empty());
603 EXPECT_TRUE(indices.empty());
604}
605
606} // namespace testing
607} // namespace impeller
DlPathBuilder & LineTo(DlPoint p2)
Draw a line from the current point to the indicated point p2.
DlPathBuilder & MoveTo(DlPoint p2)
Start a new contour that will originate at the indicated point p2.
DlPathBuilder & SetFillType(DlPathFillType fill_type)
Set the fill type that should be used to determine the interior of this path to the indicated |fill_t...
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & AddRect(const DlRect &rect)
Append a closed rectangular contour to the path.
static DlPath MakeRect(const DlRect &rect)
Definition dl_path.cc:39
double x() const
Definition geometry.h:22
double y() const
Definition geometry.h:23
size_t GetVertexCount() const override
|VertexGenerator|
A utility that generates triangles of the specified fill type given a polyline. This happens on the C...
Definition tessellator.h:37
EllipticalVertexGenerator RoundCapLine(const Matrix &view_transform, const Point &p0, const Point &p1, Scalar radius)
Create a |VertexGenerator| that can produce vertices for a line with round end caps of the given radi...
EllipticalVertexGenerator FilledRoundRect(const Matrix &view_transform, const Rect &bounds, const Size &radii)
Create a |VertexGenerator| that can produce vertices for a filled round rect within the given bounds ...
static constexpr Scalar kCircleTolerance
The pixel tolerance used by the algorighm to determine how many divisions to create for a circle.
EllipticalVertexGenerator FilledCircle(const Matrix &view_transform, const Point &center, Scalar radius)
Create a |VertexGenerator| that can produce vertices for a filled circle of the given radius around t...
static void TessellateConvexInternal(const PathSource &path, std::vector< Point > &point_buffer, std::vector< uint16_t > &index_buffer, Scalar tolerance)
EllipticalVertexGenerator StrokedCircle(const Matrix &view_transform, const Point &center, Scalar radius, Scalar half_width)
Create a |VertexGenerator| that can produce vertices for a stroked circle of the given radius and hal...
EllipticalVertexGenerator FilledEllipse(const Matrix &view_transform, const Rect &bounds)
Create a |VertexGenerator| that can produce vertices for a filled ellipse inscribed within the given ...
ArcVertexGenerator FilledArc(const Matrix &view_transform, const Arc &arc, bool supports_triangle_fans)
Create a |VertexGenerator| that can produce vertices for a stroked arc inscribed within the given ova...
An extended tessellator that offers arbitrary/concave tessellation via the libtess2 library.
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.
#define FML_DCHECK(condition)
Definition logging.h:122
#define EXPECT_POINT_NEAR(a, b)
size_t length
TEST(FrameTimingsRecorderTest, RecordVsync)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switch_defs.h:52
static constexpr DlScalar kPi
static constexpr DlScalar kEhCloseEnough
Point Vector2
Definition point.h:429
float Scalar
Definition scalar.h:19
constexpr float kPiOver2
Definition constants.h:32
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
A 4x4 matrix using column-major storage.
Definition matrix.h:37
static constexpr Matrix MakeScale(const Vector3 &s)
Definition matrix.h:104
Scalar radians
Definition scalar.h:45
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129
std::vector< Point > points