5 #include "flutter/testing/testing.h"
6 #include "gtest/gtest.h"
8 #include "flutter/display_list/geometry/dl_path_builder.h"
17 TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) {
21 auto path = flutter::DlPathBuilder{}
26 [](
const float* vertices,
size_t vertices_count,
27 const uint16_t* indices,
size_t indices_count) {
return true; });
35 auto path = flutter::DlPathBuilder{}
41 [](
const float* vertices,
size_t vertices_count,
42 const uint16_t* indices,
size_t indices_count) {
return true; });
50 auto path = flutter::DlPathBuilder{}
57 [](
const float* vertices,
size_t vertices_count,
58 const uint16_t* indices,
size_t indices_count) {
return true; });
66 flutter::DlPathBuilder builder;
67 for (
int i = 0; i < 1000; i++) {
68 auto coord = i * 1.0f;
69 builder.MoveTo({coord, coord}).
LineTo({coord + 1, coord + 1});
74 [](
const float* vertices,
size_t vertices_count,
75 const uint16_t* indices,
size_t indices_count) {
return true; });
83 auto path = flutter::DlPathBuilder{}
90 [](
const float* vertices,
size_t vertices_count,
91 const uint16_t* indices,
size_t indices_count) {
return false; });
97 TEST(TessellatorTest, TessellateConvex) {
100 std::vector<uint16_t> indices;
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);
115 std::vector<Point>
points;
116 std::vector<uint16_t> indices;
124 std::vector<Point> expected = {{0, 0}, {10, 0}, {10, 10}, {0, 10},
125 {0, 0}, {20, 20}, {30, 20}, {30, 30},
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);
134 TEST(TessellatorTest, TessellateConvexUnclosedPath) {
135 std::vector<Point>
points;
136 std::vector<uint16_t> indices;
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);
154 TEST(TessellatorTest, CircleVertexCounts) {
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;
171 <<
", transform = " <<
transform <<
", radius = " << radius
172 <<
", divisions = " << quadrant_divisions;
185 for (
int i = 36; i < 10000; i += 4) {
190 TEST(TessellatorTest, FilledCircleTessellationVertices) {
198 auto vertex_count = generator.GetVertexCount();
199 auto vertices = std::vector<Point>();
200 generator.GenerateVertices([&vertices](
const Point& p) {
201 vertices.push_back(p);
203 EXPECT_EQ(vertices.size(), vertex_count);
204 ASSERT_EQ(vertex_count % 4, 0u);
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;
212 double rcos = (i == quadrant_count - 1) ? 0.0f : cos(angle) * radius;
214 Point(center.x - rcos, center.y + rsin))
215 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
217 Point(center.x - rcos, center.y - rsin))
218 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
220 Point(center.x + rcos, center.y - rsin))
221 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
223 Point(center.x + rcos, center.y + rsin))
224 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
229 test({}, {10, 10}, 2.0);
234 TEST(TessellatorTest, StrokedCircleTessellationVertices) {
239 ASSERT_GT(radius, half_width);
244 auto vertex_count = generator.GetVertexCount();
245 auto vertices = std::vector<Point>();
246 generator.GenerateVertices([&vertices](
const Point& p) {
247 vertices.push_back(p);
249 EXPECT_EQ(vertices.size(), vertex_count);
250 ASSERT_EQ(vertex_count % 4, 0u);
252 auto quadrant_count = vertex_count / 8;
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);
261 (i == quadrant_count - 1) ? 0.0f : cos(angle) * (radius + half_width);
263 Point(center.x - rcos, center.y - rsin))
264 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
266 Point(center.x + rsin, center.y - rcos))
267 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
269 Point(center.x + rcos, center.y + rsin))
270 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
272 Point(center.x - rsin, center.y + rcos))
273 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
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);
283 (i == quadrant_count - 1) ? 0.0f : cos(angle) * (radius - half_width);
285 Point(center.x - rcos, center.y - rsin))
286 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
288 Point(center.x + rsin, center.y - rcos))
289 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
291 Point(center.x + rcos, center.y + rsin))
292 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
294 Point(center.x - rsin, center.y + rcos))
295 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
299 test({}, {}, 2.0, 1.0);
300 test({}, {}, 2.0, 0.5);
301 test({}, {10, 10}, 2.0, 1.0);
306 TEST(TessellatorTest, FilledArcStripTessellationVertices) {
314 auto vertex_count = generator.GetVertexCount();
315 auto vertices = std::vector<Point>();
316 generator.GenerateVertices([&vertices](
const Point& p) {
317 vertices.push_back(p);
319 EXPECT_EQ(vertices.size(), vertex_count);
321 auto center = arc.GetOvalBounds().GetCenter();
322 auto radius = arc.GetOvalSize().width * 0.5;
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));
338 Point origin = arc.IncludeCenter()
340 : (vertices[0] + vertices[vertex_count - 1]) * 0.5f;
341 for (
size_t i = 1; i < vertex_count; i += 2) {
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) {
350 EXPECT_NEAR((vertices[i] - center).GetLength(), radius,
kEhCloseEnough);
353 if (i == 2 || i == vertex_count - 1) {
356 EXPECT_LE((vertices[i] - previous_outer_point).GetLength(),
360 EXPECT_NEAR((vertices[i] - previous_outer_point).GetLength(),
364 previous_outer_point = vertices[i];
382 TEST(TessellatorTest, RoundCapLineTessellationVertices) {
390 auto vertex_count = generator.GetVertexCount();
391 auto vertices = std::vector<Point>();
392 generator.GenerateVertices([&vertices](
const Point& p) {
393 vertices.push_back(p);
395 EXPECT_EQ(vertices.size(), vertex_count);
396 ASSERT_EQ(vertex_count % 4, 0u);
398 Point along = p1 - p0;
401 along *= radius / length;
405 Point across = {-along.
y, along.
x};
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;
412 Point relative_along =
413 along * ((i == quadrant_count - 1) ? 0.0f : cos(angle));
414 Point relative_across = across * sin(angle);
416 p0 - relative_along + relative_across)
417 <<
"vertex " << i <<
", angle = " << degrees <<
", "
418 <<
"line = " << p0 <<
" => " << p1 <<
", "
419 <<
"radius = " << radius << std::endl;
421 p0 - relative_along - relative_across)
422 <<
"vertex " << i <<
", angle = " << degrees <<
", "
423 <<
"line = " << p0 <<
" => " << p1 <<
", "
424 <<
"radius = " << radius << std::endl;
426 p1 + relative_along - relative_across)
427 <<
"vertex " << i <<
", angle = " << degrees <<
", "
428 <<
"line = " << p0 <<
" => " << p1 <<
", "
429 <<
"radius = " << radius << std::endl;
431 p1 + relative_along + relative_across)
432 <<
"vertex " << i <<
", angle = " << degrees <<
", "
433 <<
"line = " << p0 <<
" => " << p1 <<
", "
434 <<
"radius = " << radius << std::endl;
440 test({}, {0, 0}, {0, 0}, 10);
442 test({}, {0, 0}, {10, 0}, 2);
443 test({}, {10, 0}, {0, 0}, 2);
444 test({}, {0, 0}, {10, 10}, 2);
455 TEST(TessellatorTest, FilledEllipseTessellationVertices) {
459 auto center = bounds.GetCenter();
460 auto half_size = bounds.GetSize() * 0.5f;
465 auto vertex_count = generator.GetVertexCount();
466 auto vertices = std::vector<Point>();
467 generator.GenerateVertices([&vertices](
const Point& p) {
468 vertices.push_back(p);
470 EXPECT_EQ(vertices.size(), vertex_count);
471 ASSERT_EQ(vertex_count % 4, 0u);
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;
479 (i == quadrant_count - 1) ? 0.0f : cos(angle) * half_size.width;
480 double rsin = sin(angle) * half_size.height;
482 Point(center.x - rcos, center.y + rsin))
483 <<
"vertex " << i <<
", angle = " << degrees <<
", "
484 <<
"bounds = " << bounds << std::endl;
486 Point(center.x - rcos, center.y - rsin))
487 <<
"vertex " << i <<
", angle = " << degrees <<
", "
488 <<
"bounds = " << bounds << std::endl;
490 Point(center.x + rcos, center.y - rsin))
491 <<
"vertex " << i <<
", angle = " << degrees <<
", "
492 <<
"bounds = " << bounds << std::endl;
494 Point(center.x + rcos, center.y + rsin))
495 <<
"vertex " << i <<
", angle = " << degrees <<
", "
496 <<
"bounds = " << bounds << std::endl;
516 TEST(TessellatorTest, FilledRoundRectTessellationVertices) {
521 FML_DCHECK(radii.width * 2 <= bounds.GetWidth()) << radii << bounds;
522 FML_DCHECK(radii.height * 2 <= bounds.GetHeight()) << radii << bounds;
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;
532 auto vertex_count = generator.GetVertexCount();
533 auto vertices = std::vector<Point>();
534 generator.GenerateVertices([&vertices](
const Point& p) {
535 vertices.push_back(p);
537 EXPECT_EQ(vertices.size(), vertex_count);
538 ASSERT_EQ(vertex_count % 4, 0u);
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;
545 double rcos = (i == quadrant_count - 1) ? 0.0f : cos(angle) * radii.width;
546 double rsin = sin(angle) * radii.height;
548 Point(middle_left - rcos, middle_bottom + rsin))
549 <<
"vertex " << i <<
", angle = " << degrees <<
", "
550 <<
"bounds = " << bounds << std::endl;
552 Point(middle_left - rcos, middle_top - rsin))
553 <<
"vertex " << i <<
", angle = " << degrees <<
", "
554 <<
"bounds = " << bounds << std::endl;
556 Point(middle_right + rcos, middle_top - rsin))
557 <<
"vertex " << i <<
", angle = " << degrees <<
", "
558 <<
"bounds = " << bounds << std::endl;
560 Point(middle_right + rcos, middle_bottom + rsin))
561 <<
"vertex " << i <<
", angle = " << degrees <<
", "
562 <<
"bounds = " << bounds << std::endl;
590 TEST(TessellatorTest, EarlyReturnEmptyConvexShape) {
593 flutter::DlPathBuilder builder;
594 builder.MoveTo({0, 0});
595 builder.MoveTo({10, 10});
597 std::vector<Point>
points;
598 std::vector<uint16_t> indices;
602 EXPECT_TRUE(
points.empty());
603 EXPECT_TRUE(indices.empty());
size_t GetVertexCount() const override
|VertexGenerator|
A utility that generates triangles of the specified fill type given a polyline. This happens on the C...
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 ¢er, 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 ¢er, 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 EXPECT_POINT_NEAR(a, b)
TEST(AllocationSizeTest, CanCreateTypedAllocations)
constexpr float kEhCloseEnough
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
A 4x4 matrix using column-major storage.
static constexpr Matrix MakeScale(const Vector3 &s)
constexpr Type GetLength() const
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
std::vector< Point > points