58 {
59
60class ImpellerEntityUnitTestAccessor {
61 public:
62 static std::vector<Point> GenerateSolidStrokeVertices(
63 const PathSource& path,
64 const StrokeParameters& stroke,
65 Scalar scale) {
66
67
68 Tessellator tessellator;
69 return StrokePathGeometry::GenerateSolidStrokeVertices(
70 tessellator, path, stroke, scale);
71 }
72};
73
74namespace testing {
75
76TEST(EntityGeometryTest, RectGeometryCoversArea) {
77 auto geometry = Geometry::MakeRect(Rect::MakeLTRB(0, 0, 100, 100));
78 ASSERT_TRUE(geometry->CoversArea({}, IRect::MakeLTRB(0, 0, 100, 100)));
79 ASSERT_FALSE(geometry->CoversArea({}, IRect::MakeLTRB(-1, 0, 100, 100)));
80 ASSERT_TRUE(geometry->CoversArea({}, IRect::MakeLTRB(1, 1, 100, 100)));
81 ASSERT_TRUE(geometry->CoversArea({},
IRect()));
82}
83
84TEST(EntityGeometryTest, UberSDFGeometryPaddingIsAdjustedByInverseMaxBasis) {
85 UberSDFGeometry geometry(UberSDFParameters::MakeRect(
86 Color::Red(), Rect::MakeLTRB(0, 0, 100, 100), std::nullopt));
87
88
89 {
90 auto coverage = geometry.GetCoverage(Matrix());
91 EXPECT_TRUE(coverage.has_value());
92 if (coverage.has_value()) {
93 EXPECT_EQ(coverage.value(), Rect::MakeLTRB(-1, -1, 101, 101));
94 }
95 }
96
97
98
99 {
100 auto matrix = Matrix::MakeScale({2.0, 2.0, 1.0});
101 auto coverage = geometry.GetCoverage(matrix);
102 EXPECT_TRUE(coverage.has_value());
103 if (coverage.has_value()) {
104 EXPECT_EQ(coverage.value(), Rect::MakeLTRB(-0.5, -0.5, 100.5, 100.5)
105 .TransformAndClipBounds(matrix));
106 }
107 }
108
109
110
111 {
112 auto matrix = Matrix::MakeScale({0.5, 0.5, 1.0});
113 auto coverage = geometry.GetCoverage(matrix);
114 EXPECT_TRUE(coverage.has_value());
115 if (coverage.has_value()) {
116 EXPECT_EQ(coverage.value(), Rect::MakeLTRB(-2.0, -2.0, 102.0, 102.0)
117 .TransformAndClipBounds(matrix));
118 }
119 }
120}
121
122TEST(EntityGeometryTest, FillPathGeometryCoversArea) {
124 .
AddRect(Rect::MakeLTRB(0, 0, 100, 100))
126 auto geometry = Geometry::MakeFillPath(
127 path, Rect::MakeLTRB(0, 0, 100, 100));
128 ASSERT_TRUE(geometry->CoversArea({}, IRect::MakeLTRB(0, 0, 100, 100)));
129 ASSERT_FALSE(geometry->CoversArea({}, IRect::MakeLTRB(-1, 0, 100, 100)));
130 ASSERT_TRUE(geometry->CoversArea({}, IRect::MakeLTRB(1, 1, 100, 100)));
131 ASSERT_TRUE(geometry->CoversArea({},
IRect()));
132}
133
134TEST(EntityGeometryTest, FillPathGeometryCoversAreaNoInnerRect) {
136 .
AddRect(Rect::MakeLTRB(0, 0, 100, 100))
138 auto geometry = Geometry::MakeFillPath(path);
139 ASSERT_FALSE(geometry->CoversArea({}, IRect::MakeLTRB(0, 0, 100, 100)));
140 ASSERT_FALSE(geometry->CoversArea({}, IRect::MakeLTRB(-1, 0, 100, 100)));
141 ASSERT_FALSE(geometry->CoversArea({}, IRect::MakeLTRB(1, 1, 100, 100)));
142 ASSERT_FALSE(geometry->CoversArea({},
IRect()));
143}
144
145TEST(EntityGeometryTest, FillArcGeometryCoverage) {
146 Rect oval_bounds = Rect::MakeLTRB(100, 100, 200, 200);
147 Matrix transform45 = Matrix::MakeTranslation(oval_bounds.GetCenter()) *
148 Matrix::MakeRotationZ(Degrees(45)) *
149 Matrix::MakeTranslation(-oval_bounds.GetCenter());
150
151 {
152 for (
int start = -720;
start <= 720;
start += 10) {
153 for (int sweep = 360; sweep <= 720; sweep += 30) {
154 std::string label =
155 "start: " + std::to_string(start) + " + " + std::to_string(sweep);
156 auto geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
157 Degrees(sweep), false);
158 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
159 <<
"start: " <<
start <<
", sweep: " << sweep;
160 geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
161 Degrees(-sweep), false);
162 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
163 <<
"start: " <<
start <<
", sweep: " << -sweep;
164 geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
165 Degrees(-sweep), true);
166 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
167 <<
"start: " <<
start <<
", sweep: " << -sweep <<
", with center";
168 }
169 }
170 }
171 {
172 for (
int start = 60;
start < 360;
start += 90) {
173 auto geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
174 Degrees(330), false);
175 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
176 <<
"start: " <<
start <<
" without center";
177 geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
178 Degrees(330), true);
179 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
180 <<
"start: " <<
start <<
" with center";
181 }
182 }
183 {
184 for (
int start = 30;
start < 360;
start += 90) {
185 auto geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
186 Degrees(-330), false);
187 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
188 <<
"start: " <<
start <<
" without center";
189 geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start),
190 Degrees(-330), true);
191 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
192 <<
"start: " <<
start <<
" with center";
193 }
194 }
195 {
196 for (
int start = -360;
start <= 720;
start += 360) {
197 {
198 auto geometry = Geometry::MakeFilledArc(
199 oval_bounds, Degrees(start - 45), Degrees(90), false);
200 Rect expected_bounds = Rect::MakeLTRB(150 + 50 * kSqrt2Over2,
201 150 - 50 * kSqrt2Over2,
202 200,
203 150 + 50 * kSqrt2Over2);
205 expected_bounds)
206 <<
"start: " <<
start - 45;
207 }
208 {
209 auto geometry = Geometry::MakeFilledArc(
210 oval_bounds, Degrees(start + 45), Degrees(90), false);
211 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2,
212 150 + 50 * kSqrt2Over2,
213 150 + 50 * kSqrt2Over2,
214 200);
216 expected_bounds)
217 <<
"start: " <<
start + 45;
218 }
219 {
220 auto geometry = Geometry::MakeFilledArc(
221 oval_bounds, Degrees(start + 135), Degrees(90), false);
222 Rect expected_bounds = Rect::MakeLTRB(100,
223 150 - 50 * kSqrt2Over2,
224 150 - 50 * kSqrt2Over2,
225 150 + 50 * kSqrt2Over2);
227 expected_bounds)
228 <<
"start: " <<
start + 135;
229 }
230 {
231 auto geometry = Geometry::MakeFilledArc(
232 oval_bounds, Degrees(start + 225), Degrees(90), false);
233 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2,
234 100,
235 150 + 50 * kSqrt2Over2,
236 150 - 50 * kSqrt2Over2);
238 expected_bounds)
239 <<
"start: " <<
start + 225;
240 }
241 }
242 }
243 {
244 for (
int start = -360;
start <= 720;
start += 360) {
245 {
246 auto geometry = Geometry::MakeFilledArc(
247 oval_bounds, Degrees(start - 45), Degrees(90), true);
248 Rect expected_bounds = Rect::MakeLTRB(150,
249 150 - 50 * kSqrt2Over2,
250 200,
251 150 + 50 * kSqrt2Over2);
253 expected_bounds)
254 <<
"start: " <<
start - 45;
255 }
256 {
257 auto geometry = Geometry::MakeFilledArc(
258 oval_bounds, Degrees(start + 45), Degrees(90), true);
259 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2,
260 150,
261 150 + 50 * kSqrt2Over2,
262 200);
264 expected_bounds)
265 <<
"start: " <<
start + 45;
266 }
267 {
268 auto geometry = Geometry::MakeFilledArc(
269 oval_bounds, Degrees(start + 135), Degrees(90), true);
270 Rect expected_bounds = Rect::MakeLTRB(100,
271 150 - 50 * kSqrt2Over2,
272 150,
273 150 + 50 * kSqrt2Over2);
275 expected_bounds)
276 <<
"start: " <<
start + 135;
277 }
278 {
279 auto geometry = Geometry::MakeFilledArc(
280 oval_bounds, Degrees(start + 225), Degrees(90), true);
281 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2,
282 100,
283 150 + 50 * kSqrt2Over2,
284 150);
286 expected_bounds)
287 <<
"start: " <<
start + 225;
288 }
289 }
290 }
291 {
292 auto geometry =
293 Geometry::MakeFilledArc(oval_bounds, Degrees(0), Degrees(360), false);
294 ASSERT_TRUE(oval_bounds.TransformBounds(transform45).Contains(oval_bounds));
295
296 EXPECT_TRUE(geometry->GetCoverage(transform45)
299 }
300 {
301 auto geometry =
302 Geometry::MakeFilledArc(oval_bounds, Degrees(3), Degrees(359), false);
303 ASSERT_TRUE(oval_bounds.TransformBounds(transform45).Contains(oval_bounds));
304
305 EXPECT_TRUE(geometry->GetCoverage(transform45)
308 }
309}
310
311TEST(EntityGeometryTest, StrokeArcGeometryCoverage) {
312 Rect oval_bounds = Rect::MakeLTRB(100, 100, 200, 200);
313 Rect expanded_bounds = Rect::MakeLTRB(95, 95, 205, 205);
314 Rect squared_bounds = Rect::MakeLTRB(100 - 5 * kSqrt2, 100 - 5 * kSqrt2,
315 200 + 5 * kSqrt2, 200 + 5 * kSqrt2);
316 Matrix transform45 = Matrix::MakeTranslation(oval_bounds.GetCenter()) *
317 Matrix::MakeRotationZ(Degrees(45)) *
318 Matrix::MakeTranslation(-oval_bounds.GetCenter());
319
320 StrokeParameters butt_params = {
321 .width = 10.0f,
322 .cap = Cap::kButt,
323 };
324 StrokeParameters square_params = {
325 .width = 10.0f,
326 .cap = Cap::kSquare,
327 };
328
329 {
330 for (
int start = -720;
start <= 720;
start += 10) {
331 for (int sweep = 360; sweep <= 720; sweep += 30) {
332 std::string label =
333 "start: " + std::to_string(start) + " + " + std::to_string(sweep);
334 auto geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
335 Degrees(sweep), butt_params);
336 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
337 <<
"start: " <<
start <<
", sweep: " << sweep;
338 geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
339 Degrees(-sweep), butt_params);
340 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
341 <<
"start: " <<
start <<
", sweep: " << -sweep;
342 geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
343 Degrees(-sweep), square_params);
344 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
345 <<
"start: " <<
start <<
", sweep: " << -sweep <<
", square caps";
346 }
347 }
348 }
349 {
350 for (
int start = 60;
start < 360;
start += 90) {
351 auto geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
352 Degrees(330), butt_params);
353 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
354 <<
"start: " <<
start <<
", butt caps";
355 geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
356 Degrees(330), square_params);
357 EXPECT_EQ(geometry->GetCoverage({}), squared_bounds)
358 <<
"start: " <<
start <<
", square caps";
359 }
360 }
361 {
362 for (
int start = 30;
start < 360;
start += 90) {
363 auto geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
364 Degrees(-330), butt_params);
365 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
366 <<
"start: " <<
start <<
" without center";
367 geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start),
368 Degrees(-330), square_params);
369 EXPECT_EQ(geometry->GetCoverage({}), squared_bounds)
370 <<
"start: " <<
start <<
" with center";
371 }
372 }
373 {
374 for (
int start = -360;
start <= 720;
start += 360) {
375 {
376 auto geometry = Geometry::MakeStrokedArc(
377 oval_bounds, Degrees(start - 45), Degrees(90), butt_params);
378 Rect expected_bounds = Rect::MakeLTRB(150 + 50 * kSqrt2Over2 - 5,
379 150 - 50 * kSqrt2Over2 - 5,
380 205,
381 150 + 50 * kSqrt2Over2 + 5);
383 expected_bounds)
384 <<
"start: " <<
start - 45;
385 }
386 {
387 auto geometry = Geometry::MakeStrokedArc(
388 oval_bounds, Degrees(start + 45), Degrees(90), butt_params);
389 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - 5,
390 150 + 50 * kSqrt2Over2 - 5,
391 150 + 50 * kSqrt2Over2 + 5,
392 205);
394 expected_bounds)
395 <<
"start: " <<
start + 45;
396 }
397 {
398 auto geometry = Geometry::MakeStrokedArc(
399 oval_bounds, Degrees(start + 135), Degrees(90), butt_params);
400 Rect expected_bounds = Rect::MakeLTRB(95,
401 150 - 50 * kSqrt2Over2 - 5,
402 150 - 50 * kSqrt2Over2 + 5,
403 150 + 50 * kSqrt2Over2 + 5);
405 expected_bounds)
406 <<
"start: " <<
start + 135;
407 }
408 {
409 auto geometry = Geometry::MakeStrokedArc(
410 oval_bounds, Degrees(start + 225), Degrees(90), butt_params);
411 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - 5,
412 95,
413 150 + 50 * kSqrt2Over2 + 5,
414 150 - 50 * kSqrt2Over2 + 5);
416 expected_bounds)
417 <<
"start: " <<
start + 225;
418 }
419 }
420 }
421 {
423 for (
int start = -360;
start <= 720;
start += 360) {
424 {
425 auto geometry = Geometry::MakeStrokedArc(
426 oval_bounds, Degrees(start - 45), Degrees(90), square_params);
427 Rect expected_bounds = Rect::MakeLTRB(150 + 50 * kSqrt2Over2 - pad,
428 150 - 50 * kSqrt2Over2 - pad,
429 200 + pad,
430 150 + 50 * kSqrt2Over2 + pad);
432 expected_bounds)
433 <<
"start: " <<
start - 45;
434 }
435 {
436 auto geometry = Geometry::MakeStrokedArc(
437 oval_bounds, Degrees(start + 45), Degrees(90), square_params);
438 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - pad,
439 150 + 50 * kSqrt2Over2 - pad,
440 150 + 50 * kSqrt2Over2 + pad,
441 200 + pad);
443 expected_bounds)
444 <<
"start: " <<
start + 45;
445 }
446 {
447 auto geometry = Geometry::MakeStrokedArc(
448 oval_bounds, Degrees(start + 135), Degrees(90), square_params);
449 Rect expected_bounds = Rect::MakeLTRB(100 - pad,
450 150 - 50 * kSqrt2Over2 - pad,
451 150 - 50 * kSqrt2Over2 + pad,
452 150 + 50 * kSqrt2Over2 + pad);
454 expected_bounds)
455 <<
"start: " <<
start + 135;
456 }
457 {
458 auto geometry = Geometry::MakeStrokedArc(
459 oval_bounds, Degrees(start + 225), Degrees(90), square_params);
460 Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - pad,
461 100 - pad,
462 150 + 50 * kSqrt2Over2 + pad,
463 150 - 50 * kSqrt2Over2 + pad);
465 expected_bounds)
466 <<
"start: " <<
start + 225;
467 }
468 }
469 }
470 {
471 auto geometry = Geometry::MakeStrokedArc(
472 oval_bounds, Degrees(0), Degrees(360), butt_params);
473 ASSERT_TRUE(
474 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
475
476 EXPECT_TRUE(geometry->GetCoverage(transform45)
479 }
480 {
481 auto geometry = Geometry::MakeStrokedArc(
482 oval_bounds, Degrees(0), Degrees(360), square_params);
483 ASSERT_TRUE(
484 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
485
486 EXPECT_TRUE(geometry->GetCoverage(transform45)
489 }
490 {
491 auto geometry = Geometry::MakeStrokedArc(
492 oval_bounds, Degrees(3), Degrees(359), butt_params);
493 ASSERT_TRUE(
494 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
495
496 EXPECT_TRUE(geometry->GetCoverage(transform45)
499 }
500 {
501 auto geometry = Geometry::MakeStrokedArc(
502 oval_bounds, Degrees(3), Degrees(359), square_params);
503 ASSERT_TRUE(
504 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
505
506 EXPECT_TRUE(geometry->GetCoverage(transform45)
509 }
510}
511
512TEST(EntityGeometryTest, FillRoundRectGeometryCoversArea) {
513 Rect bounds = Rect::MakeLTRB(100, 100, 200, 200);
514 RoundRect round_rect =
515 RoundRect::MakeRectRadii(bounds, RoundingRadii{
516 .top_left =
Size(1, 11),
517 .top_right =
Size(2, 12),
518 .bottom_left =
Size(3, 13),
519 .bottom_right =
Size(4, 14),
520 });
521 FillRoundRectGeometry geom(round_rect);
522
523
524 EXPECT_TRUE(geom.CoversArea({}, IRect::MakeLTRB(103, 100, 196, 200)));
525 EXPECT_FALSE(geom.CoversArea({}, IRect::MakeLTRB(102, 100, 196, 200)));
526 EXPECT_FALSE(geom.CoversArea({}, IRect::MakeLTRB(103, 99, 196, 200)));
527 EXPECT_FALSE(geom.CoversArea({}, IRect::MakeLTRB(103, 100, 197, 200)));
528 EXPECT_FALSE(geom.CoversArea({}, IRect::MakeLTRB(103, 100, 196, 201)));
529
530
531 EXPECT_TRUE(geom.CoversArea({}, IRect::MakeLTRB(100, 112, 200, 186)));
532 EXPECT_FALSE(geom.CoversArea({}, IRect::MakeLTRB(99, 112, 200, 186)));
533 EXPECT_FALSE(geom.CoversArea({}, IRect::MakeLTRB(100, 111, 200, 186)));
534 EXPECT_FALSE(geom.CoversArea({}, IRect::MakeLTRB(100, 112, 201, 186)));
535 EXPECT_FALSE(geom.CoversArea({}, IRect::MakeLTRB(100, 112, 200, 187)));
536}
537
538TEST(EntityGeometryTest, LineGeometryCoverage) {
539 {
540 auto geometry = Geometry::MakeLine(
541 {10, 10}, {20, 10}, {.width = 2, .cap = Cap::kButt});
542 EXPECT_EQ(geometry->GetCoverage({}), Rect::MakeLTRB(10, 9, 20, 11));
543 EXPECT_TRUE(geometry->CoversArea({}, IRect::MakeLTRB(10, 9, 20, 11)));
544 }
545
546 {
547 auto geometry = Geometry::MakeLine(
548 {10, 10}, {20, 10}, {.width = 2, .cap = Cap::kSquare});
549 EXPECT_EQ(geometry->GetCoverage({}), Rect::MakeLTRB(9, 9, 21, 11));
550 EXPECT_TRUE(geometry->CoversArea({}, IRect::MakeLTRB(9, 9, 21, 11)));
551 }
552
553 {
554 auto geometry = Geometry::MakeLine(
555 {10, 10}, {10, 20}, {.width = 2, .cap = Cap::kButt});
556 EXPECT_EQ(geometry->GetCoverage({}), Rect::MakeLTRB(9, 10, 11, 20));
557 EXPECT_TRUE(geometry->CoversArea({}, IRect::MakeLTRB(9, 10, 11, 20)));
558 }
559
560 {
561 auto geometry = Geometry::MakeLine(
562 {10, 10}, {10, 20}, {.width = 2, .cap = Cap::kSquare});
563 EXPECT_EQ(geometry->GetCoverage({}), Rect::MakeLTRB(9, 9, 11, 21));
564 EXPECT_TRUE(geometry->CoversArea({}, IRect::MakeLTRB(9, 9, 11, 21)));
565 }
566}
567
568TEST(EntityGeometryTest, RoundRectGeometryCoversArea) {
569 auto geometry =
570 Geometry::MakeRoundRect(Rect::MakeLTRB(0, 0, 100, 100),
Size(20, 20));
571 EXPECT_FALSE(geometry->CoversArea({}, IRect::MakeLTRB(15, 15, 85, 85)));
572 EXPECT_TRUE(geometry->CoversArea({}, IRect::MakeLTRB(20, 20, 80, 80)));
573 EXPECT_TRUE(geometry->CoversArea({}, IRect::MakeLTRB(30, 1, 70, 99)));
574 EXPECT_TRUE(geometry->CoversArea({}, IRect::MakeLTRB(1, 30, 99, 70)));
575}
576
577TEST(EntityGeometryTest, GeometryResultHasReasonableDefaults) {
578 GeometryResult result;
579 EXPECT_EQ(result.type, PrimitiveType::kTriangleStrip);
580 EXPECT_EQ(result.transform, Matrix());
581 EXPECT_EQ(result.mode, GeometryResult::Mode::kNormal);
582}
583
584TEST(EntityGeometryTest, AlphaCoverageStrokePaths) {
585 auto matrix = Matrix::MakeScale(Vector2{3.0, 3.0});
586 EXPECT_EQ(Geometry::MakeStrokePath({}, {.width = 0.5f})
587 ->ComputeAlphaCoverage(matrix),
588 1.0f);
589 EXPECT_NEAR(Geometry::MakeStrokePath({}, {.width = 0.1f})
590 ->ComputeAlphaCoverage(matrix),
591 0.6, 0.05);
592 EXPECT_NEAR(Geometry::MakeStrokePath({}, {.width = 0.05})
593 ->ComputeAlphaCoverage(matrix),
594 0.3, 0.05);
595 EXPECT_NEAR(Geometry::MakeStrokePath({}, {.width = 0.01})
596 ->ComputeAlphaCoverage(matrix),
597 0.1, 0.1);
598 EXPECT_NEAR(Geometry::MakeStrokePath({}, {.width = 0.0000005f})
599 ->ComputeAlphaCoverage(matrix),
600 1e-05, 0.001);
601 EXPECT_EQ(Geometry::MakeStrokePath({}, {.width = 0.0f})
602 ->ComputeAlphaCoverage(matrix),
603 1.0f);
604 EXPECT_EQ(Geometry::MakeStrokePath({}, {.width = 40.0f})
605 ->ComputeAlphaCoverage(matrix),
606 1.0f);
607}
608
609TEST(EntityGeometryTest, SimpleTwoLineStrokeVerticesButtCap) {
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::kButt,
622 .join = Join::kBevel,
623 .miter_limit = 4.0f,
624 },
625 1.0f);
626
627 std::vector<Point> expected = {
628
633
634
639
640
645 };
646
647 EXPECT_EQ(
points, expected);
648}
649
650TEST(EntityGeometryTest, SimpleTwoLineStrokeVerticesRoundCap) {
652 path_builder.
MoveTo({20, 20});
653 path_builder.
LineTo({30, 20});
654 path_builder.
MoveTo({120, 20});
655 path_builder.
LineTo({130, 20});
657
658 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
659 path,
660 {
661 .width = 10.0f,
662 .cap = Cap::kRound,
663 .join = Join::kBevel,
664 .miter_limit = 4.0f,
665 },
666 1.0f);
667
668 size_t count =
points.size();
669 ASSERT_TRUE((count & 0x1) == 0x0);
670
671
672
673
674
675
676
677 ASSERT_EQ(
points.size(), 40u);
678
679
680
681
682
683 auto offset = [](
int step,
bool left,
bool backwards) -> Point {
684 Radians angle(kPiOver2 * (step / 4.0f));
685 Point along =
Point(5.0f, 0.0f) * std::cos(angle.radians);
686 Point across =
Point(0.0f, 5.0f) * std::sin(angle.radians);
689 };
690
691
693 EXPECT_EQ(
points[1],
Point(20, 20) + offset(1,
true,
true));
694 EXPECT_EQ(
points[2],
Point(20, 20) + offset(1,
false,
true));
695 EXPECT_EQ(
points[3],
Point(20, 20) + offset(2,
true,
true));
696 EXPECT_EQ(
points[4],
Point(20, 20) + offset(2,
false,
true));
697 EXPECT_EQ(
points[5],
Point(20, 20) + offset(3,
true,
true));
698 EXPECT_EQ(
points[6],
Point(20, 20) + offset(3,
false,
true));
703 EXPECT_EQ(
points[11],
Point(30, 20) + offset(3,
true,
false));
704 EXPECT_EQ(
points[12],
Point(30, 20) + offset(3,
false,
false));
705 EXPECT_EQ(
points[13],
Point(30, 20) + offset(2,
true,
false));
706 EXPECT_EQ(
points[14],
Point(30, 20) + offset(2,
false,
false));
707 EXPECT_EQ(
points[15],
Point(30, 20) + offset(1,
true,
false));
708 EXPECT_EQ(
points[16],
Point(30, 20) + offset(1,
false,
false));
710
711
716
717
719 EXPECT_EQ(
points[23],
Point(120, 20) + offset(1,
true,
true));
720 EXPECT_EQ(
points[24],
Point(120, 20) + offset(1,
false,
true));
721 EXPECT_EQ(
points[25],
Point(120, 20) + offset(2,
true,
true));
722 EXPECT_EQ(
points[26],
Point(120, 20) + offset(2,
false,
true));
723 EXPECT_EQ(
points[27],
Point(120, 20) + offset(3,
true,
true));
724 EXPECT_EQ(
points[28],
Point(120, 20) + offset(3,
false,
true));
729 EXPECT_EQ(
points[33],
Point(130, 20) + offset(3,
true,
false));
730 EXPECT_EQ(
points[34],
Point(130, 20) + offset(3,
false,
false));
731 EXPECT_EQ(
points[35],
Point(130, 20) + offset(2,
true,
false));
732 EXPECT_EQ(
points[36],
Point(130, 20) + offset(2,
false,
false));
733 EXPECT_EQ(
points[37],
Point(130, 20) + offset(1,
true,
false));
734 EXPECT_EQ(
points[38],
Point(130, 20) + offset(1,
false,
false));
736}
737
738TEST(EntityGeometryTest, SimpleTwoLineStrokeVerticesSquareCap) {
740 path_builder.
MoveTo({20, 20});
741 path_builder.
LineTo({30, 20});
742 path_builder.
MoveTo({120, 20});
743 path_builder.
LineTo({130, 20});
745
746 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
747 path,
748 {
749 .width = 10.0f,
750 .cap = Cap::kSquare,
751 .join = Join::kBevel,
752 .miter_limit = 4.0f,
753 },
754 1.0f);
755
756
757 std::vector<Point> expected = {
758
767
768
773
774
783 };
784
785
786 EXPECT_EQ(
points, expected);
787}
788
789TEST(EntityGeometryTest, TwoLineSegmentsRightTurnStrokeVerticesBevelJoin) {
791 path_builder.
MoveTo({20, 20});
792 path_builder.
LineTo({30, 20});
793 path_builder.
LineTo({30, 30});
795
796 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
797 path,
798 {
799 .width = 10.0f,
800 .cap = Cap::kButt,
801 .join = Join::kBevel,
802 .miter_limit = 4.0f,
803 },
804 1.0f);
805
806 std::vector<Point> expected = {
807
812
813
818 };
819
820 EXPECT_EQ(
points, expected);
821}
822
823TEST(EntityGeometryTest, TwoLineSegmentsLeftTurnStrokeVerticesBevelJoin) {
825 path_builder.
MoveTo({20, 20});
826 path_builder.
LineTo({30, 20});
827 path_builder.
LineTo({30, 10});
829
830 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
831 path,
832 {
833 .width = 10.0f,
834 .cap = Cap::kButt,
835 .join = Join::kBevel,
836 .miter_limit = 4.0f,
837 },
838 1.0f);
839
840 std::vector<Point> expected = {
841
846
847
852 };
853
854 EXPECT_EQ(
points, expected);
855}
856
857TEST(EntityGeometryTest, TwoLineSegmentsInDifferentContoursAreNotJoined) {
859
860 path_builder.
MoveTo({20, 20});
861 path_builder.
LineTo({30, 20});
862
863
864 path_builder.
MoveTo({30, 20});
865
866 path_builder.
LineTo({30, 30});
868
869 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
870 path,
871 {
872 .width = 10.0f,
873 .cap = Cap::kButt,
874 .join = Join::kBevel,
875 .miter_limit = 4.0f,
876 },
877 1.0f);
878
879 std::vector<Point> expected = {
880
885
886
887
888
893
894
899 };
900
901 EXPECT_EQ(
points, expected);
902}
903
904TEST(EntityGeometryTest, TwoLineSegmentsRightTurnStrokeVerticesMiterJoin) {
906 path_builder.
MoveTo({20, 20});
907 path_builder.
LineTo({30, 20});
908 path_builder.
LineTo({30, 30});
910
911 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
912 path,
913 {
914 .width = 10.0f,
915 .cap = Cap::kButt,
916 .join = Join::kMiter,
917 .miter_limit = 4.0f,
918 },
919 1.0f);
920
921 std::vector<Point> expected = {
922
927
928
930
931
936 };
937
938 EXPECT_EQ(
points, expected);
939}
940
941TEST(EntityGeometryTest, TwoLineSegmentsLeftTurnStrokeVerticesMiterJoin) {
943 path_builder.
MoveTo({20, 20});
944 path_builder.
LineTo({30, 20});
945 path_builder.
LineTo({30, 10});
947
948 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
949 path,
950 {
951 .width = 10.0f,
952 .cap = Cap::kButt,
953 .join = Join::kMiter,
954 .miter_limit = 4.0f,
955 },
956 1.0f);
957
958 std::vector<Point> expected = {
959
964
965
967
968
973 };
974
975 EXPECT_EQ(
points, expected);
976}
977
978TEST(EntityGeometryTest, TinyQuadGeneratesCaps) {
980 path_builder.
MoveTo({20, 20});
983
984 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
985 path,
986 {
987 .width = 4.0f,
988 .cap = Cap::kSquare,
989 .join = Join::kBevel,
990 .miter_limit = 4.0f,
991 },
992 1.0f);
993
994 std::vector<Point> expected = {
995
998
999
1002
1003
1006
1007
1010 };
1011
1012 EXPECT_EQ(
points, expected);
1013}
1014
1015TEST(EntityGeometryTest, TinyConicGeneratesCaps) {
1017 path_builder.
MoveTo({20, 20});
1018 path_builder.
ConicCurveTo({20.125, 20}, {20.250, 20}, 0.6);
1020
1021 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1022 path,
1023 {
1024 .width = 4.0f,
1025 .cap = Cap::kSquare,
1026 .join = Join::kBevel,
1027 .miter_limit = 4.0f,
1028 },
1029 1.0f);
1030
1031 std::vector<Point> expected = {
1032
1035
1036
1039
1040
1043
1044
1047 };
1048
1049 EXPECT_EQ(
points, expected);
1050}
1051
1052TEST(EntityGeometryTest, TinyCubicGeneratesCaps) {
1054 path_builder.
MoveTo({20, 20});
1055 path_builder.
CubicCurveTo({20.0625, 20}, {20.125, 20}, {20.250, 20});
1057
1058 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1059 path,
1060 {
1061 .width = 4.0f,
1062 .cap = Cap::kSquare,
1063 .join = Join::kBevel,
1064 .miter_limit = 4.0f,
1065 },
1066 1.0f);
1067
1068 std::vector<Point> expected = {
1069
1072
1073
1076
1077
1080
1081
1084 };
1085
1086 EXPECT_EQ(
points, expected);
1087}
1088
1089TEST(EntityGeometryTest, TwoLineSegmentsMiterLimit) {
1090
1091 for (int degrees = 10; degrees < 180; degrees += 10) {
1092
1093
1097 Point pixel_delta =
Point(std::cos(r.radians), std::sin(r.radians));
1098
1099 if (pixel_delta.GetDistance(
Point(1, 0)) *
width < 1.0f) {
1100
1101
1102
1103
1104 continue;
1105 }
1106
1107
1108 Degrees between(180 - degrees);
1109 Radians r_between(between);
1110 Scalar limit = 1.0f / std::sin(r_between.radians / 2.0f);
1111
1115 path_builder.
LineTo(
Point(30, 20) + pixel_delta * 10.0f);
1117
1118
1119 auto points1 =
1120 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1121 path,
1122 {
1124 .cap = Cap::kButt,
1125 .join = Join::kMiter,
1126 .miter_limit = limit * 0.99f,
1127 },
1128 1.0f);
1129 EXPECT_EQ(points1.size(), 8u)
1130 <<
"degrees: " << degrees <<
", width: " <<
width <<
", "
1131 << points1[4];
1132
1133
1134 auto points2 =
1135 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1136 path,
1137 {
1139 .cap = Cap::kButt,
1140 .join = Join::kMiter,
1141 .miter_limit = limit * 1.01f,
1142 },
1143 1.0f);
1144 EXPECT_EQ(points2.size(), 9u)
1145 <<
"degrees: " << degrees <<
", width: " <<
width;
1146 EXPECT_LE(points2[4].GetDistance({30, 20}),
width * limit * 1.05f)
1147 <<
"degrees: " << degrees <<
", width: " <<
width <<
", "
1148 << points2[4];
1149 }
1150 }
1151}
1152
1153TEST(EntityGeometryTest, TwoLineSegments180DegreeJoins) {
1154
1160
1161 auto points_bevel =
1162 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1163 path,
1164 {
1165 .width = 20.0f,
1166 .cap = Cap::kButt,
1167 .join = Join::kBevel,
1168 .miter_limit = 4.0f,
1169 },
1170 1.0f);
1171
1172 EXPECT_EQ(points_bevel.size(), 8u);
1173
1174 auto points_miter =
1175 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1176 path,
1177 {
1178 .width = 20.0f,
1179 .cap = Cap::kButt,
1180 .join = Join::kMiter,
1181 .miter_limit = 400.0f,
1182 },
1183 1.0f);
1184
1185 EXPECT_EQ(points_miter.size(), 8u);
1186
1187 auto points_round =
1188 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1189 path,
1190 {
1191 .width = 20.0f,
1192 .cap = Cap::kButt,
1193 .join = Join::kRound,
1194 .miter_limit = 4.0f,
1195 },
1196 1.0f);
1197
1198 EXPECT_EQ(points_round.size(), 19u);
1199}
1200
1201TEST(EntityGeometryTest, TightQuadratic180DegreeJoins) {
1202
1203
1208
1209 auto points_bevel_reference =
1210 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1211 path_reference,
1212 {
1213 .width = 20.0f,
1214 .cap = Cap::kButt,
1215 .join = Join::kBevel,
1216 .miter_limit = 4.0f,
1217 },
1218 1.0f);
1219
1220 EXPECT_EQ(points_bevel_reference.size(), 74u);
1221
1222
1227
1228 auto points_bevel =
1229 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1230 path,
1231 {
1232 .width = 20.0f,
1233 .cap = Cap::kButt,
1234 .join = Join::kBevel,
1235 .miter_limit = 4.0f,
1236 },
1237 1.0f);
1238
1239 EXPECT_GT(points_bevel.size(), points_bevel_reference.size());
1240
1241 auto points_miter =
1242 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1243 path,
1244 {
1245 .width = 20.0f,
1246 .cap = Cap::kButt,
1247 .join = Join::kMiter,
1248 .miter_limit = 400.0f,
1249 },
1250 1.0f);
1251
1252 EXPECT_GT(points_miter.size(), points_bevel_reference.size());
1253
1254 auto points_round =
1255 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1256 path,
1257 {
1258 .width = 20.0f,
1259 .cap = Cap::kButt,
1260 .join = Join::kRound,
1261 .miter_limit = 4.0f,
1262 },
1263 1.0f);
1264
1265 EXPECT_GT(points_round.size(), points_bevel_reference.size());
1266}
1267
1268TEST(EntityGeometryTest, TightConic180DegreeJoins) {
1269
1270
1275
1276 auto points_bevel_reference =
1277 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1278 path_reference,
1279 {
1280 .width = 20.0f,
1281 .cap = Cap::kButt,
1282 .join = Join::kBevel,
1283 .miter_limit = 4.0f,
1284 },
1285 1.0f);
1286
1287 EXPECT_EQ(points_bevel_reference.size(), 78u);
1288
1289
1294
1295 auto points_bevel =
1296 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1297 path,
1298 {
1299 .width = 20.0f,
1300 .cap = Cap::kButt,
1301 .join = Join::kBevel,
1302 .miter_limit = 4.0f,
1303 },
1304 1.0f);
1305
1306 EXPECT_GT(points_bevel.size(), points_bevel_reference.size());
1307
1308 auto points_miter =
1309 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1310 path,
1311 {
1312 .width = 20.0f,
1313 .cap = Cap::kButt,
1314 .join = Join::kMiter,
1315 .miter_limit = 400.0f,
1316 },
1317 1.0f);
1318
1319 EXPECT_GT(points_miter.size(), points_bevel_reference.size());
1320
1321 auto points_round =
1322 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1323 path,
1324 {
1325 .width = 20.0f,
1326 .cap = Cap::kButt,
1327 .join = Join::kRound,
1328 .miter_limit = 4.0f,
1329 },
1330 1.0f);
1331
1332 EXPECT_GT(points_round.size(), points_bevel_reference.size());
1333}
1334
1335TEST(EntityGeometryTest, TightCubic180DegreeJoins) {
1336
1337
1343
1344 auto points_reference =
1345 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1346 path_reference,
1347 {
1348 .width = 20.0f,
1349 .cap = Cap::kButt,
1350 .join = Join::kBevel,
1351 .miter_limit = 4.0f,
1352 },
1353 1.0f);
1354
1355 EXPECT_EQ(points_reference.size(), 76u);
1356
1357
1362
1363 auto points_bevel =
1364 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1365 path,
1366 {
1367 .width = 20.0f,
1368 .cap = Cap::kButt,
1369 .join = Join::kBevel,
1370 .miter_limit = 4.0f,
1371 },
1372 1.0f);
1373
1374 EXPECT_GT(points_bevel.size(), points_reference.size());
1375
1376 auto points_miter =
1377 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1378 path,
1379 {
1380 .width = 20.0f,
1381 .cap = Cap::kButt,
1382 .join = Join::kMiter,
1383 .miter_limit = 400.0f,
1384 },
1385 1.0f);
1386
1387 EXPECT_GT(points_miter.size(), points_reference.size());
1388
1389 auto points_round =
1390 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1391 path,
1392 {
1393 .width = 20.0f,
1394 .cap = Cap::kButt,
1395 .join = Join::kRound,
1396 .miter_limit = 4.0f,
1397 },
1398 1.0f);
1399
1400 EXPECT_GT(points_round.size(), points_reference.size());
1401}
1402
1403TEST(EntityGeometryTest, RotatedFilledCircleGeometryCoverage) {
1405 auto geometry = Geometry::MakeCircle(center, 50);
1406 Rect circle_bounds = Rect::MakeLTRB(0, 0, 100, 100);
1407 ASSERT_EQ(geometry->GetCoverage({}).value_or(
Rect()), circle_bounds);
1408
1409 Matrix transform45 = Matrix::MakeTranslation(center) *
1410 Matrix::MakeRotationZ(Degrees(45)) *
1411 Matrix::MakeTranslation(-center);
1412
1413 EXPECT_TRUE(geometry->GetCoverage(transform45).has_value());
1414 Rect bounds = geometry->GetCoverage(transform45).value_or(
Rect());
1415 EXPECT_TRUE(bounds.Contains(circle_bounds))
1416 << "geometry bounds: " << bounds << std::endl
1417 << " circle bounds: " << circle_bounds;
1418}
1419
1420TEST(EntityGeometryTest, RotatedStrokedCircleGeometryCoverage) {
1422 auto geometry = Geometry::MakeStrokedCircle(center, 50, 10);
1423 Rect circle_bounds = Rect::MakeLTRB(0, 0, 100, 100).
Expand(5);
1424 ASSERT_EQ(geometry->GetCoverage({}).value_or(
Rect()), circle_bounds);
1425
1426 Matrix transform45 = Matrix::MakeTranslation(center) *
1427 Matrix::MakeRotationZ(Degrees(45)) *
1428 Matrix::MakeTranslation(-center);
1429
1430 EXPECT_TRUE(geometry->GetCoverage(transform45).has_value());
1431 Rect bounds = geometry->GetCoverage(transform45).value_or(
Rect());
1432 EXPECT_TRUE(bounds.Contains(circle_bounds))
1433 << "geometry bounds: " << bounds << std::endl
1434 << " circle bounds: " << circle_bounds;
1435}
1436
1437}
1438}
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