55 {
56
57class ImpellerEntityUnitTestAccessor {
58 public:
59 static std::vector<Point> GenerateSolidStrokeVertices(
60 const PathSource& path,
61 const StrokeParameters& stroke,
62 Scalar scale) {
63
64
65 Tessellator tessellator;
66 return StrokePathGeometry::GenerateSolidStrokeVertices(
67 tessellator, path, stroke, scale);
68 }
69};
70
71namespace testing {
72
73TEST(EntityGeometryTest, RectGeometryCoversArea) {
74 auto geometry = Geometry::MakeRect(Rect::MakeLTRB(0, 0, 100, 100));
75 ASSERT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(0, 0, 100, 100)));
76 ASSERT_FALSE(geometry->CoversArea({}, Rect::MakeLTRB(-1, 0, 100, 100)));
77 ASSERT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(1, 1, 100, 100)));
78 ASSERT_TRUE(geometry->CoversArea({},
Rect()));
79}
80
81TEST(EntityGeometryTest, FillPathGeometryCoversArea) {
83 .
AddRect(Rect::MakeLTRB(0, 0, 100, 100))
85 auto geometry = Geometry::MakeFillPath(
86 path, Rect::MakeLTRB(0, 0, 100, 100));
87 ASSERT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(0, 0, 100, 100)));
88 ASSERT_FALSE(geometry->CoversArea({}, Rect::MakeLTRB(-1, 0, 100, 100)));
89 ASSERT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(1, 1, 100, 100)));
90 ASSERT_TRUE(geometry->CoversArea({},
Rect()));
91}
92
93TEST(EntityGeometryTest, FillPathGeometryCoversAreaNoInnerRect) {
95 .
AddRect(Rect::MakeLTRB(0, 0, 100, 100))
97 auto geometry = Geometry::MakeFillPath(path);
98 ASSERT_FALSE(geometry->CoversArea({}, Rect::MakeLTRB(0, 0, 100, 100)));
99 ASSERT_FALSE(geometry->CoversArea({}, Rect::MakeLTRB(-1, 0, 100, 100)));
100 ASSERT_FALSE(geometry->CoversArea({}, Rect::MakeLTRB(1, 1, 100, 100)));
101 ASSERT_FALSE(geometry->CoversArea({},
Rect()));
102}
103
104TEST(EntityGeometryTest, FillArcGeometryCoverage) {
105 Rect oval_bounds = Rect::MakeLTRB(100, 100, 200, 200);
106 Matrix transform45 = Matrix::MakeTranslation(oval_bounds.GetCenter()) *
107 Matrix::MakeRotationZ(Degrees(45)) *
108 Matrix::MakeTranslation(-oval_bounds.GetCenter());
109
110 {
111 for (
int start = -720;
start <= 720;
start += 10) {
112 for (int sweep = 360; sweep <= 720; sweep += 30) {
113 std::string label =
114 "start: " + std::to_string(start) + " + " + std::to_string(sweep);
115 auto geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
116 Degrees(sweep), false);
117 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
118 <<
"start: " <<
start <<
", sweep: " << sweep;
119 geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
120 Degrees(-sweep), false);
121 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
122 <<
"start: " <<
start <<
", sweep: " << -sweep;
123 geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
124 Degrees(-sweep), true);
125 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
126 <<
"start: " <<
start <<
", sweep: " << -sweep <<
", with center";
127 }
128 }
129 }
130 {
131 for (
int start = 60;
start < 360;
start += 90) {
132 auto geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
133 Degrees(330), false);
134 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
135 <<
"start: " <<
start <<
" without center";
136 geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
137 Degrees(330), true);
138 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
139 <<
"start: " <<
start <<
" with center";
140 }
141 }
142 {
143 for (
int start = 30;
start < 360;
start += 90) {
144 auto geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
145 Degrees(-330), false);
146 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
147 <<
"start: " <<
start <<
" without center";
148 geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
149 Degrees(-330), true);
150 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
151 <<
"start: " <<
start <<
" with center";
152 }
153 }
154 {
155 for (
int start = -360;
start <= 720;
start += 360) {
156 {
157 auto geometry = Geometry::MakeFilledArc(
158 oval_bounds, Degrees(start - 45), Degrees(90), false);
159 Rect expected_bounds = Rect::MakeLTRB(150 + 50 * kSqrt2Over2,
160 150 - 50 * kSqrt2Over2,
161 200,
162 150 + 50 * kSqrt2Over2);
164 expected_bounds)
165 <<
"start: " <<
start - 45;
166 }
167 {
168 auto geometry = Geometry::MakeFilledArc(
169 oval_bounds, Degrees(start + 45), Degrees(90), false);
170 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2,
171 150 + 50 * kSqrt2Over2,
172 150 + 50 * kSqrt2Over2,
173 200);
175 expected_bounds)
176 <<
"start: " <<
start + 45;
177 }
178 {
179 auto geometry = Geometry::MakeFilledArc(
180 oval_bounds, Degrees(start + 135), Degrees(90), false);
181 Rect expected_bounds = Rect::MakeLTRB(100,
182 150 - 50 * kSqrt2Over2,
183 150 - 50 * kSqrt2Over2,
184 150 + 50 * kSqrt2Over2);
186 expected_bounds)
187 <<
"start: " <<
start + 135;
188 }
189 {
190 auto geometry = Geometry::MakeFilledArc(
191 oval_bounds, Degrees(start + 225), Degrees(90), false);
192 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2,
193 100,
194 150 + 50 * kSqrt2Over2,
195 150 - 50 * kSqrt2Over2);
197 expected_bounds)
198 <<
"start: " <<
start + 225;
199 }
200 }
201 }
202 {
203 for (
int start = -360;
start <= 720;
start += 360) {
204 {
205 auto geometry = Geometry::MakeFilledArc(
206 oval_bounds, Degrees(start - 45), Degrees(90), true);
207 Rect expected_bounds = Rect::MakeLTRB(150,
208 150 - 50 * kSqrt2Over2,
209 200,
210 150 + 50 * kSqrt2Over2);
212 expected_bounds)
213 <<
"start: " <<
start - 45;
214 }
215 {
216 auto geometry = Geometry::MakeFilledArc(
217 oval_bounds, Degrees(start + 45), Degrees(90), true);
218 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2,
219 150,
220 150 + 50 * kSqrt2Over2,
221 200);
223 expected_bounds)
224 <<
"start: " <<
start + 45;
225 }
226 {
227 auto geometry = Geometry::MakeFilledArc(
228 oval_bounds, Degrees(start + 135), Degrees(90), true);
229 Rect expected_bounds = Rect::MakeLTRB(100,
230 150 - 50 * kSqrt2Over2,
231 150,
232 150 + 50 * kSqrt2Over2);
234 expected_bounds)
235 <<
"start: " <<
start + 135;
236 }
237 {
238 auto geometry = Geometry::MakeFilledArc(
239 oval_bounds, Degrees(start + 225), Degrees(90), true);
240 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2,
241 100,
242 150 + 50 * kSqrt2Over2,
243 150);
245 expected_bounds)
246 <<
"start: " <<
start + 225;
247 }
248 }
249 }
250 {
251 auto geometry =
252 Geometry::MakeFilledArc(oval_bounds, Degrees(0), Degrees(360), false);
253 ASSERT_TRUE(oval_bounds.TransformBounds(transform45).Contains(oval_bounds));
254
255 EXPECT_TRUE(geometry->GetCoverage(transform45)
258 }
259 {
260 auto geometry =
261 Geometry::MakeFilledArc(oval_bounds, Degrees(3), Degrees(359), false);
262 ASSERT_TRUE(oval_bounds.TransformBounds(transform45).Contains(oval_bounds));
263
264 EXPECT_TRUE(geometry->GetCoverage(transform45)
267 }
268}
269
270TEST(EntityGeometryTest, StrokeArcGeometryCoverage) {
271 Rect oval_bounds = Rect::MakeLTRB(100, 100, 200, 200);
272 Rect expanded_bounds = Rect::MakeLTRB(95, 95, 205, 205);
273 Rect squared_bounds = Rect::MakeLTRB(100 - 5 * kSqrt2, 100 - 5 * kSqrt2,
274 200 + 5 * kSqrt2, 200 + 5 * kSqrt2);
275 Matrix transform45 = Matrix::MakeTranslation(oval_bounds.GetCenter()) *
276 Matrix::MakeRotationZ(Degrees(45)) *
277 Matrix::MakeTranslation(-oval_bounds.GetCenter());
278
279 StrokeParameters butt_params = {
280 .width = 10.0f,
281 .cap = Cap::kButt,
282 };
283 StrokeParameters square_params = {
284 .width = 10.0f,
285 .cap = Cap::kSquare,
286 };
287
288 {
289 for (
int start = -720;
start <= 720;
start += 10) {
290 for (int sweep = 360; sweep <= 720; sweep += 30) {
291 std::string label =
292 "start: " + std::to_string(start) + " + " + std::to_string(sweep);
293 auto geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
294 Degrees(sweep), butt_params);
295 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
296 <<
"start: " <<
start <<
", sweep: " << sweep;
297 geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
298 Degrees(-sweep), butt_params);
299 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
300 <<
"start: " <<
start <<
", sweep: " << -sweep;
301 geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
302 Degrees(-sweep), square_params);
303 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
304 <<
"start: " <<
start <<
", sweep: " << -sweep <<
", square caps";
305 }
306 }
307 }
308 {
309 for (
int start = 60;
start < 360;
start += 90) {
310 auto geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
311 Degrees(330), butt_params);
312 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
313 <<
"start: " <<
start <<
", butt caps";
314 geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
315 Degrees(330), square_params);
316 EXPECT_EQ(geometry->GetCoverage({}), squared_bounds)
317 <<
"start: " <<
start <<
", square caps";
318 }
319 }
320 {
321 for (
int start = 30;
start < 360;
start += 90) {
322 auto geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
323 Degrees(-330), butt_params);
324 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
325 <<
"start: " <<
start <<
" without center";
326 geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
327 Degrees(-330), square_params);
328 EXPECT_EQ(geometry->GetCoverage({}), squared_bounds)
329 <<
"start: " <<
start <<
" with center";
330 }
331 }
332 {
333 for (
int start = -360;
start <= 720;
start += 360) {
334 {
335 auto geometry = Geometry::MakeStrokedArc(
336 oval_bounds, Degrees(start - 45), Degrees(90), butt_params);
337 Rect expected_bounds = Rect::MakeLTRB(150 + 50 * kSqrt2Over2 - 5,
338 150 - 50 * kSqrt2Over2 - 5,
339 205,
340 150 + 50 * kSqrt2Over2 + 5);
342 expected_bounds)
343 <<
"start: " <<
start - 45;
344 }
345 {
346 auto geometry = Geometry::MakeStrokedArc(
347 oval_bounds, Degrees(start + 45), Degrees(90), butt_params);
348 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - 5,
349 150 + 50 * kSqrt2Over2 - 5,
350 150 + 50 * kSqrt2Over2 + 5,
351 205);
353 expected_bounds)
354 <<
"start: " <<
start + 45;
355 }
356 {
357 auto geometry = Geometry::MakeStrokedArc(
358 oval_bounds, Degrees(start + 135), Degrees(90), butt_params);
359 Rect expected_bounds = Rect::MakeLTRB(95,
360 150 - 50 * kSqrt2Over2 - 5,
361 150 - 50 * kSqrt2Over2 + 5,
362 150 + 50 * kSqrt2Over2 + 5);
364 expected_bounds)
365 <<
"start: " <<
start + 135;
366 }
367 {
368 auto geometry = Geometry::MakeStrokedArc(
369 oval_bounds, Degrees(start + 225), Degrees(90), butt_params);
370 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - 5,
371 95,
372 150 + 50 * kSqrt2Over2 + 5,
373 150 - 50 * kSqrt2Over2 + 5);
375 expected_bounds)
376 <<
"start: " <<
start + 225;
377 }
378 }
379 }
380 {
382 for (
int start = -360;
start <= 720;
start += 360) {
383 {
384 auto geometry = Geometry::MakeStrokedArc(
385 oval_bounds, Degrees(start - 45), Degrees(90), square_params);
386 Rect expected_bounds = Rect::MakeLTRB(150 + 50 * kSqrt2Over2 - pad,
387 150 - 50 * kSqrt2Over2 - pad,
388 200 + pad,
389 150 + 50 * kSqrt2Over2 + pad);
391 expected_bounds)
392 <<
"start: " <<
start - 45;
393 }
394 {
395 auto geometry = Geometry::MakeStrokedArc(
396 oval_bounds, Degrees(start + 45), Degrees(90), square_params);
397 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - pad,
398 150 + 50 * kSqrt2Over2 - pad,
399 150 + 50 * kSqrt2Over2 + pad,
400 200 + pad);
402 expected_bounds)
403 <<
"start: " <<
start + 45;
404 }
405 {
406 auto geometry = Geometry::MakeStrokedArc(
407 oval_bounds, Degrees(start + 135), Degrees(90), square_params);
408 Rect expected_bounds = Rect::MakeLTRB(100 - pad,
409 150 - 50 * kSqrt2Over2 - pad,
410 150 - 50 * kSqrt2Over2 + pad,
411 150 + 50 * kSqrt2Over2 + pad);
413 expected_bounds)
414 <<
"start: " <<
start + 135;
415 }
416 {
417 auto geometry = Geometry::MakeStrokedArc(
418 oval_bounds, Degrees(start + 225), Degrees(90), square_params);
419 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - pad,
420 100 - pad,
421 150 + 50 * kSqrt2Over2 + pad,
422 150 - 50 * kSqrt2Over2 + pad);
424 expected_bounds)
425 <<
"start: " <<
start + 225;
426 }
427 }
428 }
429 {
430 auto geometry = Geometry::MakeStrokedArc(
431 oval_bounds, Degrees(0), Degrees(360), butt_params);
432 ASSERT_TRUE(
433 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
434
435 EXPECT_TRUE(geometry->GetCoverage(transform45)
438 }
439 {
440 auto geometry = Geometry::MakeStrokedArc(
441 oval_bounds, Degrees(0), Degrees(360), square_params);
442 ASSERT_TRUE(
443 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
444
445 EXPECT_TRUE(geometry->GetCoverage(transform45)
448 }
449 {
450 auto geometry = Geometry::MakeStrokedArc(
451 oval_bounds, Degrees(3), Degrees(359), butt_params);
452 ASSERT_TRUE(
453 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
454
455 EXPECT_TRUE(geometry->GetCoverage(transform45)
458 }
459 {
460 auto geometry = Geometry::MakeStrokedArc(
461 oval_bounds, Degrees(3), Degrees(359), square_params);
462 ASSERT_TRUE(
463 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
464
465 EXPECT_TRUE(geometry->GetCoverage(transform45)
468 }
469}
470
471TEST(EntityGeometryTest, FillRoundRectGeometryCoversArea) {
472 Rect bounds = Rect::MakeLTRB(100, 100, 200, 200);
473 RoundRect round_rect =
474 RoundRect::MakeRectRadii(bounds, RoundingRadii{
475 .top_left =
Size(1, 11),
476 .top_right =
Size(2, 12),
477 .bottom_left =
Size(3, 13),
478 .bottom_right =
Size(4, 14),
479 });
480 FillRoundRectGeometry geom(round_rect);
481
482
483 EXPECT_TRUE(geom.CoversArea({}, Rect::MakeLTRB(103, 100, 196, 200)));
484 EXPECT_FALSE(geom.CoversArea({}, Rect::MakeLTRB(102, 100, 196, 200)));
485 EXPECT_FALSE(geom.CoversArea({}, Rect::MakeLTRB(103, 99, 196, 200)));
486 EXPECT_FALSE(geom.CoversArea({}, Rect::MakeLTRB(103, 100, 197, 200)));
487 EXPECT_FALSE(geom.CoversArea({}, Rect::MakeLTRB(103, 100, 196, 201)));
488
489
490 EXPECT_TRUE(geom.CoversArea({}, Rect::MakeLTRB(100, 112, 200, 186)));
491 EXPECT_FALSE(geom.CoversArea({}, Rect::MakeLTRB(99, 112, 200, 186)));
492 EXPECT_FALSE(geom.CoversArea({}, Rect::MakeLTRB(100, 111, 200, 186)));
493 EXPECT_FALSE(geom.CoversArea({}, Rect::MakeLTRB(100, 112, 201, 186)));
494 EXPECT_FALSE(geom.CoversArea({}, Rect::MakeLTRB(100, 112, 200, 187)));
495}
496
497TEST(EntityGeometryTest, LineGeometryCoverage) {
498 {
499 auto geometry = Geometry::MakeLine(
500 {10, 10}, {20, 10}, {.width = 2, .cap = Cap::kButt});
501 EXPECT_EQ(geometry->GetCoverage({}), Rect::MakeLTRB(10, 9, 20, 11));
502 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(10, 9, 20, 11)));
503 }
504
505 {
506 auto geometry = Geometry::MakeLine(
507 {10, 10}, {20, 10}, {.width = 2, .cap = Cap::kSquare});
508 EXPECT_EQ(geometry->GetCoverage({}), Rect::MakeLTRB(9, 9, 21, 11));
509 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(9, 9, 21, 11)));
510 }
511
512 {
513 auto geometry = Geometry::MakeLine(
514 {10, 10}, {10, 20}, {.width = 2, .cap = Cap::kButt});
515 EXPECT_EQ(geometry->GetCoverage({}), Rect::MakeLTRB(9, 10, 11, 20));
516 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(9, 10, 11, 20)));
517 }
518
519 {
520 auto geometry = Geometry::MakeLine(
521 {10, 10}, {10, 20}, {.width = 2, .cap = Cap::kSquare});
522 EXPECT_EQ(geometry->GetCoverage({}), Rect::MakeLTRB(9, 9, 11, 21));
523 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(9, 9, 11, 21)));
524 }
525}
526
527TEST(EntityGeometryTest, RoundRectGeometryCoversArea) {
528 auto geometry =
529 Geometry::MakeRoundRect(Rect::MakeLTRB(0, 0, 100, 100),
Size(20, 20));
530 EXPECT_FALSE(geometry->CoversArea({}, Rect::MakeLTRB(15, 15, 85, 85)));
531 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(20, 20, 80, 80)));
532 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(30, 1, 70, 99)));
533 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(1, 30, 99, 70)));
534}
535
536TEST(EntityGeometryTest, GeometryResultHasReasonableDefaults) {
537 GeometryResult result;
538 EXPECT_EQ(result.type, PrimitiveType::kTriangleStrip);
539 EXPECT_EQ(result.transform, Matrix());
540 EXPECT_EQ(result.mode, GeometryResult::Mode::kNormal);
541}
542
543TEST(EntityGeometryTest, AlphaCoverageStrokePaths) {
544 auto matrix = Matrix::MakeScale(Vector2{3.0, 3.0});
545 EXPECT_EQ(Geometry::MakeStrokePath({}, {.width = 0.5f})
546 ->ComputeAlphaCoverage(matrix),
547 1.0f);
548 EXPECT_NEAR(Geometry::MakeStrokePath({}, {.width = 0.1f})
549 ->ComputeAlphaCoverage(matrix),
550 0.6, 0.05);
551 EXPECT_NEAR(Geometry::MakeStrokePath({}, {.width = 0.05})
552 ->ComputeAlphaCoverage(matrix),
553 0.3, 0.05);
554 EXPECT_NEAR(Geometry::MakeStrokePath({}, {.width = 0.01})
555 ->ComputeAlphaCoverage(matrix),
556 0.1, 0.1);
557 EXPECT_NEAR(Geometry::MakeStrokePath({}, {.width = 0.0000005f})
558 ->ComputeAlphaCoverage(matrix),
559 1e-05, 0.001);
560 EXPECT_EQ(Geometry::MakeStrokePath({}, {.width = 0.0f})
561 ->ComputeAlphaCoverage(matrix),
562 1.0f);
563 EXPECT_EQ(Geometry::MakeStrokePath({}, {.width = 40.0f})
564 ->ComputeAlphaCoverage(matrix),
565 1.0f);
566}
567
568TEST(EntityGeometryTest, SimpleTwoLineStrokeVerticesButtCap) {
570 path_builder.
MoveTo({20, 20});
571 path_builder.
LineTo({30, 20});
572 path_builder.
MoveTo({120, 20});
573 path_builder.
LineTo({130, 20});
575
576 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
577 path,
578 {
579 .width = 10.0f,
580 .cap = Cap::kButt,
581 .join = Join::kBevel,
582 .miter_limit = 4.0f,
583 },
584 1.0f);
585
586 std::vector<Point> expected = {
587
592
593
598
599
604 };
605
606 EXPECT_EQ(
points, expected);
607}
608
609TEST(EntityGeometryTest, SimpleTwoLineStrokeVerticesRoundCap) {
611 path_builder.
MoveTo({20, 20});
612 path_builder.
LineTo({30, 20});
613 path_builder.
MoveTo({120, 20});
614 path_builder.
LineTo({130, 20});
616
617 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
618 path,
619 {
620 .width = 10.0f,
621 .cap = Cap::kRound,
622 .join = Join::kBevel,
623 .miter_limit = 4.0f,
624 },
625 1.0f);
626
627 size_t count =
points.size();
628 ASSERT_TRUE((count & 0x1) == 0x0);
629
630
631
632
633
634
635
636 ASSERT_EQ(
points.size(), 40u);
637
638
639
640
641
642 auto offset = [](
int step,
bool left,
bool backwards) -> Point {
643 Radians angle(kPiOver2 * (step / 4.0f));
644 Point along =
Point(5.0f, 0.0f) * std::cos(angle.radians);
645 Point across =
Point(0.0f, 5.0f) * std::sin(angle.radians);
648 };
649
650
652 EXPECT_EQ(
points[1],
Point(20, 20) + offset(1,
true,
true));
653 EXPECT_EQ(
points[2],
Point(20, 20) + offset(1,
false,
true));
654 EXPECT_EQ(
points[3],
Point(20, 20) + offset(2,
true,
true));
655 EXPECT_EQ(
points[4],
Point(20, 20) + offset(2,
false,
true));
656 EXPECT_EQ(
points[5],
Point(20, 20) + offset(3,
true,
true));
657 EXPECT_EQ(
points[6],
Point(20, 20) + offset(3,
false,
true));
662 EXPECT_EQ(
points[11],
Point(30, 20) + offset(3,
true,
false));
663 EXPECT_EQ(
points[12],
Point(30, 20) + offset(3,
false,
false));
664 EXPECT_EQ(
points[13],
Point(30, 20) + offset(2,
true,
false));
665 EXPECT_EQ(
points[14],
Point(30, 20) + offset(2,
false,
false));
666 EXPECT_EQ(
points[15],
Point(30, 20) + offset(1,
true,
false));
667 EXPECT_EQ(
points[16],
Point(30, 20) + offset(1,
false,
false));
669
670
675
676
678 EXPECT_EQ(
points[23],
Point(120, 20) + offset(1,
true,
true));
679 EXPECT_EQ(
points[24],
Point(120, 20) + offset(1,
false,
true));
680 EXPECT_EQ(
points[25],
Point(120, 20) + offset(2,
true,
true));
681 EXPECT_EQ(
points[26],
Point(120, 20) + offset(2,
false,
true));
682 EXPECT_EQ(
points[27],
Point(120, 20) + offset(3,
true,
true));
683 EXPECT_EQ(
points[28],
Point(120, 20) + offset(3,
false,
true));
688 EXPECT_EQ(
points[33],
Point(130, 20) + offset(3,
true,
false));
689 EXPECT_EQ(
points[34],
Point(130, 20) + offset(3,
false,
false));
690 EXPECT_EQ(
points[35],
Point(130, 20) + offset(2,
true,
false));
691 EXPECT_EQ(
points[36],
Point(130, 20) + offset(2,
false,
false));
692 EXPECT_EQ(
points[37],
Point(130, 20) + offset(1,
true,
false));
693 EXPECT_EQ(
points[38],
Point(130, 20) + offset(1,
false,
false));
695}
696
697TEST(EntityGeometryTest, SimpleTwoLineStrokeVerticesSquareCap) {
699 path_builder.
MoveTo({20, 20});
700 path_builder.
LineTo({30, 20});
701 path_builder.
MoveTo({120, 20});
702 path_builder.
LineTo({130, 20});
704
705 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
706 path,
707 {
708 .width = 10.0f,
709 .cap = Cap::kSquare,
710 .join = Join::kBevel,
711 .miter_limit = 4.0f,
712 },
713 1.0f);
714
715
716 std::vector<Point> expected = {
717
726
727
732
733
742 };
743
744
745 EXPECT_EQ(
points, expected);
746}
747
748TEST(EntityGeometryTest, TwoLineSegmentsRightTurnStrokeVerticesBevelJoin) {
750 path_builder.
MoveTo({20, 20});
751 path_builder.
LineTo({30, 20});
752 path_builder.
LineTo({30, 30});
754
755 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
756 path,
757 {
758 .width = 10.0f,
759 .cap = Cap::kButt,
760 .join = Join::kBevel,
761 .miter_limit = 4.0f,
762 },
763 1.0f);
764
765 std::vector<Point> expected = {
766
771
772
777 };
778
779 EXPECT_EQ(
points, expected);
780}
781
782TEST(EntityGeometryTest, TwoLineSegmentsLeftTurnStrokeVerticesBevelJoin) {
784 path_builder.
MoveTo({20, 20});
785 path_builder.
LineTo({30, 20});
786 path_builder.
LineTo({30, 10});
788
789 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
790 path,
791 {
792 .width = 10.0f,
793 .cap = Cap::kButt,
794 .join = Join::kBevel,
795 .miter_limit = 4.0f,
796 },
797 1.0f);
798
799 std::vector<Point> expected = {
800
805
806
811 };
812
813 EXPECT_EQ(
points, expected);
814}
815
816TEST(EntityGeometryTest, TwoLineSegmentsRightTurnStrokeVerticesMiterJoin) {
818 path_builder.
MoveTo({20, 20});
819 path_builder.
LineTo({30, 20});
820 path_builder.
LineTo({30, 30});
822
823 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
824 path,
825 {
826 .width = 10.0f,
827 .cap = Cap::kButt,
828 .join = Join::kMiter,
829 .miter_limit = 4.0f,
830 },
831 1.0f);
832
833 std::vector<Point> expected = {
834
839
840
842
843
848 };
849
850 EXPECT_EQ(
points, expected);
851}
852
853TEST(EntityGeometryTest, TwoLineSegmentsLeftTurnStrokeVerticesMiterJoin) {
855 path_builder.
MoveTo({20, 20});
856 path_builder.
LineTo({30, 20});
857 path_builder.
LineTo({30, 10});
859
860 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
861 path,
862 {
863 .width = 10.0f,
864 .cap = Cap::kButt,
865 .join = Join::kMiter,
866 .miter_limit = 4.0f,
867 },
868 1.0f);
869
870 std::vector<Point> expected = {
871
876
877
879
880
885 };
886
887 EXPECT_EQ(
points, expected);
888}
889
890TEST(EntityGeometryTest, TinyQuadGeneratesCaps) {
892 path_builder.
MoveTo({20, 20});
895
896 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
897 path,
898 {
899 .width = 4.0f,
900 .cap = Cap::kSquare,
901 .join = Join::kBevel,
902 .miter_limit = 4.0f,
903 },
904 1.0f);
905
906 std::vector<Point> expected = {
907
910
911
914
915
918
919
922 };
923
924 EXPECT_EQ(
points, expected);
925}
926
927TEST(EntityGeometryTest, TinyConicGeneratesCaps) {
929 path_builder.
MoveTo({20, 20});
930 path_builder.
ConicCurveTo({20.125, 20}, {20.250, 20}, 0.6);
932
933 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
934 path,
935 {
936 .width = 4.0f,
937 .cap = Cap::kSquare,
938 .join = Join::kBevel,
939 .miter_limit = 4.0f,
940 },
941 1.0f);
942
943 std::vector<Point> expected = {
944
947
948
951
952
955
956
959 };
960
961 EXPECT_EQ(
points, expected);
962}
963
964TEST(EntityGeometryTest, TinyCubicGeneratesCaps) {
966 path_builder.
MoveTo({20, 20});
967 path_builder.
CubicCurveTo({20.0625, 20}, {20.125, 20}, {20.250, 20});
969
970 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
971 path,
972 {
973 .width = 4.0f,
974 .cap = Cap::kSquare,
975 .join = Join::kBevel,
976 .miter_limit = 4.0f,
977 },
978 1.0f);
979
980 std::vector<Point> expected = {
981
984
985
988
989
992
993
996 };
997
998 EXPECT_EQ(
points, expected);
999}
1000
1001TEST(EntityGeometryTest, TwoLineSegmentsMiterLimit) {
1002
1003 for (int degrees = 10; degrees < 180; degrees += 10) {
1004
1005
1009 Point pixel_delta =
Point(std::cos(r.radians), std::sin(r.radians));
1010
1011 if (pixel_delta.GetDistance(
Point(1, 0)) *
width < 1.0f) {
1012
1013
1014
1015
1016 continue;
1017 }
1018
1019
1020 Degrees between(180 - degrees);
1021 Radians r_between(between);
1022 Scalar limit = 1.0f / std::sin(r_between.radians / 2.0f);
1023
1027 path_builder.
LineTo(
Point(30, 20) + pixel_delta * 10.0f);
1029
1030
1031 auto points1 =
1032 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1033 path,
1034 {
1036 .cap = Cap::kButt,
1037 .join = Join::kMiter,
1038 .miter_limit = limit * 0.99f,
1039 },
1040 1.0f);
1041 EXPECT_EQ(points1.size(), 8u)
1042 <<
"degrees: " << degrees <<
", width: " <<
width <<
", "
1043 << points1[4];
1044
1045
1046 auto points2 =
1047 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1048 path,
1049 {
1051 .cap = Cap::kButt,
1052 .join = Join::kMiter,
1053 .miter_limit = limit * 1.01f,
1054 },
1055 1.0f);
1056 EXPECT_EQ(points2.size(), 9u)
1057 <<
"degrees: " << degrees <<
", width: " <<
width;
1058 EXPECT_LE(points2[4].GetDistance({30, 20}),
width * limit * 1.05f)
1059 <<
"degrees: " << degrees <<
", width: " <<
width <<
", "
1060 << points2[4];
1061 }
1062 }
1063}
1064
1065TEST(EntityGeometryTest, TwoLineSegments180DegreeJoins) {
1066
1072
1073 auto points_bevel =
1074 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1075 path,
1076 {
1077 .width = 20.0f,
1078 .cap = Cap::kButt,
1079 .join = Join::kBevel,
1080 .miter_limit = 4.0f,
1081 },
1082 1.0f);
1083
1084 EXPECT_EQ(points_bevel.size(), 8u);
1085
1086 auto points_miter =
1087 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1088 path,
1089 {
1090 .width = 20.0f,
1091 .cap = Cap::kButt,
1092 .join = Join::kMiter,
1093 .miter_limit = 400.0f,
1094 },
1095 1.0f);
1096
1097 EXPECT_EQ(points_miter.size(), 8u);
1098
1099 auto points_round =
1100 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1101 path,
1102 {
1103 .width = 20.0f,
1104 .cap = Cap::kButt,
1105 .join = Join::kRound,
1106 .miter_limit = 4.0f,
1107 },
1108 1.0f);
1109
1110 EXPECT_EQ(points_round.size(), 19u);
1111}
1112
1113TEST(EntityGeometryTest, TightQuadratic180DegreeJoins) {
1114
1115
1120
1121 auto points_bevel_reference =
1122 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1123 path_reference,
1124 {
1125 .width = 20.0f,
1126 .cap = Cap::kButt,
1127 .join = Join::kBevel,
1128 .miter_limit = 4.0f,
1129 },
1130 1.0f);
1131
1132 EXPECT_EQ(points_bevel_reference.size(), 74u);
1133
1134
1139
1140 auto points_bevel =
1141 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1142 path,
1143 {
1144 .width = 20.0f,
1145 .cap = Cap::kButt,
1146 .join = Join::kBevel,
1147 .miter_limit = 4.0f,
1148 },
1149 1.0f);
1150
1151 EXPECT_GT(points_bevel.size(), points_bevel_reference.size());
1152
1153 auto points_miter =
1154 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1155 path,
1156 {
1157 .width = 20.0f,
1158 .cap = Cap::kButt,
1159 .join = Join::kMiter,
1160 .miter_limit = 400.0f,
1161 },
1162 1.0f);
1163
1164 EXPECT_GT(points_miter.size(), points_bevel_reference.size());
1165
1166 auto points_round =
1167 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1168 path,
1169 {
1170 .width = 20.0f,
1171 .cap = Cap::kButt,
1172 .join = Join::kRound,
1173 .miter_limit = 4.0f,
1174 },
1175 1.0f);
1176
1177 EXPECT_GT(points_round.size(), points_bevel_reference.size());
1178}
1179
1180TEST(EntityGeometryTest, TightConic180DegreeJoins) {
1181
1182
1187
1188 auto points_bevel_reference =
1189 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1190 path_reference,
1191 {
1192 .width = 20.0f,
1193 .cap = Cap::kButt,
1194 .join = Join::kBevel,
1195 .miter_limit = 4.0f,
1196 },
1197 1.0f);
1198
1199 EXPECT_EQ(points_bevel_reference.size(), 78u);
1200
1201
1206
1207 auto points_bevel =
1208 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1209 path,
1210 {
1211 .width = 20.0f,
1212 .cap = Cap::kButt,
1213 .join = Join::kBevel,
1214 .miter_limit = 4.0f,
1215 },
1216 1.0f);
1217
1218 EXPECT_GT(points_bevel.size(), points_bevel_reference.size());
1219
1220 auto points_miter =
1221 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1222 path,
1223 {
1224 .width = 20.0f,
1225 .cap = Cap::kButt,
1226 .join = Join::kMiter,
1227 .miter_limit = 400.0f,
1228 },
1229 1.0f);
1230
1231 EXPECT_GT(points_miter.size(), points_bevel_reference.size());
1232
1233 auto points_round =
1234 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1235 path,
1236 {
1237 .width = 20.0f,
1238 .cap = Cap::kButt,
1239 .join = Join::kRound,
1240 .miter_limit = 4.0f,
1241 },
1242 1.0f);
1243
1244 EXPECT_GT(points_round.size(), points_bevel_reference.size());
1245}
1246
1247TEST(EntityGeometryTest, TightCubic180DegreeJoins) {
1248
1249
1255
1256 auto points_reference =
1257 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1258 path_reference,
1259 {
1260 .width = 20.0f,
1261 .cap = Cap::kButt,
1262 .join = Join::kBevel,
1263 .miter_limit = 4.0f,
1264 },
1265 1.0f);
1266
1267 EXPECT_EQ(points_reference.size(), 76u);
1268
1269
1274
1275 auto points_bevel =
1276 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1277 path,
1278 {
1279 .width = 20.0f,
1280 .cap = Cap::kButt,
1281 .join = Join::kBevel,
1282 .miter_limit = 4.0f,
1283 },
1284 1.0f);
1285
1286 EXPECT_GT(points_bevel.size(), points_reference.size());
1287
1288 auto points_miter =
1289 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1290 path,
1291 {
1292 .width = 20.0f,
1293 .cap = Cap::kButt,
1294 .join = Join::kMiter,
1295 .miter_limit = 400.0f,
1296 },
1297 1.0f);
1298
1299 EXPECT_GT(points_miter.size(), points_reference.size());
1300
1301 auto points_round =
1302 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1303 path,
1304 {
1305 .width = 20.0f,
1306 .cap = Cap::kButt,
1307 .join = Join::kRound,
1308 .miter_limit = 4.0f,
1309 },
1310 1.0f);
1311
1312 EXPECT_GT(points_round.size(), points_reference.size());
1313}
1314
1315TEST(EntityGeometryTest, RotatedFilledCircleGeometryCoverage) {
1317 auto geometry = Geometry::MakeCircle(center, 50);
1318 Rect circle_bounds = Rect::MakeLTRB(0, 0, 100, 100);
1319 ASSERT_EQ(geometry->GetCoverage({}).value_or(
Rect()), circle_bounds);
1320
1321 Matrix transform45 = Matrix::MakeTranslation(center) *
1322 Matrix::MakeRotationZ(Degrees(45)) *
1323 Matrix::MakeTranslation(-center);
1324
1325 EXPECT_TRUE(geometry->GetCoverage(transform45).has_value());
1326 Rect bounds = geometry->GetCoverage(transform45).value_or(
Rect());
1327 EXPECT_TRUE(bounds.Contains(circle_bounds))
1328 << "geometry bounds: " << bounds << std::endl
1329 << " circle bounds: " << circle_bounds;
1330}
1331
1332TEST(EntityGeometryTest, RotatedStrokedCircleGeometryCoverage) {
1334 auto geometry = Geometry::MakeStrokedCircle(center, 50, 10);
1335 Rect circle_bounds = Rect::MakeLTRB(0, 0, 100, 100).
Expand(5);
1336 ASSERT_EQ(geometry->GetCoverage({}).value_or(
Rect()), circle_bounds);
1337
1338 Matrix transform45 = Matrix::MakeTranslation(center) *
1339 Matrix::MakeRotationZ(Degrees(45)) *
1340 Matrix::MakeTranslation(-center);
1341
1342 EXPECT_TRUE(geometry->GetCoverage(transform45).has_value());
1343 Rect bounds = geometry->GetCoverage(transform45).value_or(
Rect());
1344 EXPECT_TRUE(bounds.Contains(circle_bounds))
1345 << "geometry bounds: " << bounds << std::endl
1346 << " circle bounds: " << circle_bounds;
1347}
1348
1349}
1350}
TEST(AsciiTableTest, Simple)
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.
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & ConicCurveTo(DlPoint cp, DlPoint p2, DlScalar weight)
Draw a conic curve (a rational quadratic bezier curve) from the current point to the indicated point ...
DlPathBuilder & AddRect(const DlRect &rect)
Append a closed rectangular contour to the path.
DlPathBuilder & QuadraticCurveTo(DlPoint cp, DlPoint p2)
Draw a quadratic bezier curve from the current point to the indicated point p2, using the indicated p...
DlPathBuilder & CubicCurveTo(DlPoint cp1, DlPoint cp2, DlPoint p2)
Draw a cubic bezier curve from the current point to the indicated point p2, using the indicated point...
#define EXPECT_RECT_NEAR(a, b)
bool Contains(const Container &container, const Value &value)
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
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
std::vector< Point > points