5 #include "flutter/testing/testing.h"
6 #include "gtest/gtest.h"
8 #include "flutter/display_list/geometry/dl_path_builder.h"
16 TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) {
20 auto path = flutter::DlPathBuilder{}
25 [](
const float* vertices,
size_t vertices_count,
26 const uint16_t* indices,
size_t indices_count) {
return true; });
34 auto path = flutter::DlPathBuilder{}
40 [](
const float* vertices,
size_t vertices_count,
41 const uint16_t* indices,
size_t indices_count) {
return true; });
49 auto path = flutter::DlPathBuilder{}
56 [](
const float* vertices,
size_t vertices_count,
57 const uint16_t* indices,
size_t indices_count) {
return true; });
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});
73 [](
const float* vertices,
size_t vertices_count,
74 const uint16_t* indices,
size_t indices_count) {
return true; });
82 auto path = flutter::DlPathBuilder{}
89 [](
const float* vertices,
size_t vertices_count,
90 const uint16_t* indices,
size_t indices_count) {
return false; });
96 TEST(TessellatorTest, TessellateConvex) {
99 std::vector<uint16_t> indices;
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);
114 std::vector<Point>
points;
115 std::vector<uint16_t> indices;
123 std::vector<Point> expected = {{0, 0}, {10, 0}, {10, 10}, {0, 10},
124 {0, 0}, {20, 20}, {30, 20}, {30, 30},
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);
133 TEST(TessellatorTest, TessellateConvexUnclosedPath) {
134 std::vector<Point>
points;
135 std::vector<uint16_t> indices;
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);
153 TEST(TessellatorTest, CircleVertexCounts) {
154 auto tessellator = std::make_shared<Tessellator>();
157 auto generator = tessellator->FilledCircle(
transform, {}, radius);
158 size_t quadrant_divisions = generator.GetVertexCount() / 4;
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;
170 <<
", transform = " <<
transform <<
", radius = " << radius
171 <<
", divisions = " << quadrant_divisions;
184 for (
int i = 36; i < 10000; i += 4) {
189 TEST(TessellatorTest, FilledCircleTessellationVertices) {
190 auto tessellator = std::make_shared<Tessellator>();
194 auto generator = tessellator->FilledCircle(
transform, center, radius);
197 auto vertex_count = generator.GetVertexCount();
198 auto vertices = std::vector<Point>();
199 generator.GenerateVertices([&vertices](
const Point& p) {
200 vertices.push_back(p);
202 EXPECT_EQ(vertices.size(), vertex_count);
203 ASSERT_EQ(vertex_count % 4, 0u);
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;
211 double rcos = (i == quadrant_count - 1) ? 0.0f : cos(angle) * radius;
213 Point(center.x - rcos, center.y + rsin))
214 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
216 Point(center.x - rcos, center.y - rsin))
217 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
219 Point(center.x + rcos, center.y - rsin))
220 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
222 Point(center.x + rcos, center.y + rsin))
223 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
228 test({}, {10, 10}, 2.0);
233 TEST(TessellatorTest, StrokedCircleTessellationVertices) {
234 auto tessellator = std::make_shared<Tessellator>();
238 ASSERT_GT(radius, half_width);
240 tessellator->StrokedCircle(
transform, center, radius, half_width);
243 auto vertex_count = generator.GetVertexCount();
244 auto vertices = std::vector<Point>();
245 generator.GenerateVertices([&vertices](
const Point& p) {
246 vertices.push_back(p);
248 EXPECT_EQ(vertices.size(), vertex_count);
249 ASSERT_EQ(vertex_count % 4, 0u);
251 auto quadrant_count = vertex_count / 8;
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);
260 (i == quadrant_count - 1) ? 0.0f : cos(angle) * (radius + half_width);
262 Point(center.x - rcos, center.y - rsin))
263 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
265 Point(center.x + rsin, center.y - rcos))
266 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
268 Point(center.x + rcos, center.y + rsin))
269 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
271 Point(center.x - rsin, center.y + rcos))
272 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
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);
282 (i == quadrant_count - 1) ? 0.0f : cos(angle) * (radius - half_width);
284 Point(center.x - rcos, center.y - rsin))
285 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
287 Point(center.x + rsin, center.y - rcos))
288 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
290 Point(center.x + rcos, center.y + rsin))
291 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
293 Point(center.x - rsin, center.y + rcos))
294 <<
"vertex " << i <<
", angle = " << degrees << std::endl;
298 test({}, {}, 2.0, 1.0);
299 test({}, {}, 2.0, 0.5);
300 test({}, {10, 10}, 2.0, 1.0);
305 TEST(TessellatorTest, RoundCapLineTessellationVertices) {
306 auto tessellator = std::make_shared<Tessellator>();
310 auto generator = tessellator->RoundCapLine(
transform, p0, p1, radius);
313 auto vertex_count = generator.GetVertexCount();
314 auto vertices = std::vector<Point>();
315 generator.GenerateVertices([&vertices](
const Point& p) {
316 vertices.push_back(p);
318 EXPECT_EQ(vertices.size(), vertex_count);
319 ASSERT_EQ(vertex_count % 4, 0u);
321 Point along = p1 - p0;
324 along *= radius / length;
328 Point across = {-along.
y, along.
x};
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;
335 Point relative_along =
336 along * ((i == quadrant_count - 1) ? 0.0f : cos(angle));
337 Point relative_across = across * sin(angle);
339 p0 - relative_along + relative_across)
340 <<
"vertex " << i <<
", angle = " << degrees <<
", "
341 <<
"line = " << p0 <<
" => " << p1 <<
", "
342 <<
"radius = " << radius << std::endl;
344 p0 - relative_along - relative_across)
345 <<
"vertex " << i <<
", angle = " << degrees <<
", "
346 <<
"line = " << p0 <<
" => " << p1 <<
", "
347 <<
"radius = " << radius << std::endl;
349 p1 + relative_along - relative_across)
350 <<
"vertex " << i <<
", angle = " << degrees <<
", "
351 <<
"line = " << p0 <<
" => " << p1 <<
", "
352 <<
"radius = " << radius << std::endl;
354 p1 + relative_along + relative_across)
355 <<
"vertex " << i <<
", angle = " << degrees <<
", "
356 <<
"line = " << p0 <<
" => " << p1 <<
", "
357 <<
"radius = " << radius << std::endl;
363 test({}, {0, 0}, {0, 0}, 10);
365 test({}, {0, 0}, {10, 0}, 2);
366 test({}, {10, 0}, {0, 0}, 2);
367 test({}, {0, 0}, {10, 10}, 2);
378 TEST(TessellatorTest, FilledEllipseTessellationVertices) {
379 auto tessellator = std::make_shared<Tessellator>();
382 auto center = bounds.GetCenter();
383 auto half_size = bounds.GetSize() * 0.5f;
385 auto generator = tessellator->FilledEllipse(
transform, bounds);
388 auto vertex_count = generator.GetVertexCount();
389 auto vertices = std::vector<Point>();
390 generator.GenerateVertices([&vertices](
const Point& p) {
391 vertices.push_back(p);
393 EXPECT_EQ(vertices.size(), vertex_count);
394 ASSERT_EQ(vertex_count % 4, 0u);
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;
402 (i == quadrant_count - 1) ? 0.0f : cos(angle) * half_size.width;
403 double rsin = sin(angle) * half_size.height;
405 Point(center.x - rcos, center.y + rsin))
406 <<
"vertex " << i <<
", angle = " << degrees <<
", "
407 <<
"bounds = " << bounds << std::endl;
409 Point(center.x - rcos, center.y - rsin))
410 <<
"vertex " << i <<
", angle = " << degrees <<
", "
411 <<
"bounds = " << bounds << std::endl;
413 Point(center.x + rcos, center.y - rsin))
414 <<
"vertex " << i <<
", angle = " << degrees <<
", "
415 <<
"bounds = " << bounds << std::endl;
417 Point(center.x + rcos, center.y + rsin))
418 <<
"vertex " << i <<
", angle = " << degrees <<
", "
419 <<
"bounds = " << bounds << std::endl;
439 TEST(TessellatorTest, FilledRoundRectTessellationVertices) {
440 auto tessellator = std::make_shared<Tessellator>();
444 FML_DCHECK(radii.width * 2 <= bounds.GetWidth()) << radii << bounds;
445 FML_DCHECK(radii.height * 2 <= bounds.GetHeight()) << radii << bounds;
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;
452 auto generator = tessellator->FilledRoundRect(
transform, bounds, radii);
455 auto vertex_count = generator.GetVertexCount();
456 auto vertices = std::vector<Point>();
457 generator.GenerateVertices([&vertices](
const Point& p) {
458 vertices.push_back(p);
460 EXPECT_EQ(vertices.size(), vertex_count);
461 ASSERT_EQ(vertex_count % 4, 0u);
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;
468 double rcos = (i == quadrant_count - 1) ? 0.0f : cos(angle) * radii.width;
469 double rsin = sin(angle) * radii.height;
471 Point(middle_left - rcos, middle_bottom + rsin))
472 <<
"vertex " << i <<
", angle = " << degrees <<
", "
473 <<
"bounds = " << bounds << std::endl;
475 Point(middle_left - rcos, middle_top - rsin))
476 <<
"vertex " << i <<
", angle = " << degrees <<
", "
477 <<
"bounds = " << bounds << std::endl;
479 Point(middle_right + rcos, middle_top - rsin))
480 <<
"vertex " << i <<
", angle = " << degrees <<
", "
481 <<
"bounds = " << bounds << std::endl;
483 Point(middle_right + rcos, middle_bottom + rsin))
484 <<
"vertex " << i <<
", angle = " << degrees <<
", "
485 <<
"bounds = " << bounds << std::endl;
513 TEST(TessellatorTest, EarlyReturnEmptyConvexShape) {
516 flutter::DlPathBuilder builder;
517 builder.MoveTo({0, 0});
518 builder.MoveTo({10, 10});
520 std::vector<Point>
points;
521 std::vector<uint16_t> indices;
525 EXPECT_TRUE(
points.empty());
526 EXPECT_TRUE(indices.empty());
static constexpr Scalar kCircleTolerance
The pixel tolerance used by the algorighm to determine how many divisions to create for a circle.
static void TessellateConvexInternal(const PathSource &path, std::vector< Point > &point_buffer, std::vector< uint16_t > &index_buffer, Scalar tolerance)
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)
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