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, TwoLineSegmentsRightTurnStrokeVerticesMiterJoin) {
859 path_builder.
MoveTo({20, 20});
860 path_builder.
LineTo({30, 20});
861 path_builder.
LineTo({30, 30});
863
864 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
865 path,
866 {
867 .width = 10.0f,
868 .cap = Cap::kButt,
869 .join = Join::kMiter,
870 .miter_limit = 4.0f,
871 },
872 1.0f);
873
874 std::vector<Point> expected = {
875
880
881
883
884
889 };
890
891 EXPECT_EQ(
points, expected);
892}
893
894TEST(EntityGeometryTest, TwoLineSegmentsLeftTurnStrokeVerticesMiterJoin) {
896 path_builder.
MoveTo({20, 20});
897 path_builder.
LineTo({30, 20});
898 path_builder.
LineTo({30, 10});
900
901 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
902 path,
903 {
904 .width = 10.0f,
905 .cap = Cap::kButt,
906 .join = Join::kMiter,
907 .miter_limit = 4.0f,
908 },
909 1.0f);
910
911 std::vector<Point> expected = {
912
917
918
920
921
926 };
927
928 EXPECT_EQ(
points, expected);
929}
930
931TEST(EntityGeometryTest, TinyQuadGeneratesCaps) {
933 path_builder.
MoveTo({20, 20});
936
937 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
938 path,
939 {
940 .width = 4.0f,
941 .cap = Cap::kSquare,
942 .join = Join::kBevel,
943 .miter_limit = 4.0f,
944 },
945 1.0f);
946
947 std::vector<Point> expected = {
948
951
952
955
956
959
960
963 };
964
965 EXPECT_EQ(
points, expected);
966}
967
968TEST(EntityGeometryTest, TinyConicGeneratesCaps) {
970 path_builder.
MoveTo({20, 20});
971 path_builder.
ConicCurveTo({20.125, 20}, {20.250, 20}, 0.6);
973
974 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
975 path,
976 {
977 .width = 4.0f,
978 .cap = Cap::kSquare,
979 .join = Join::kBevel,
980 .miter_limit = 4.0f,
981 },
982 1.0f);
983
984 std::vector<Point> expected = {
985
988
989
992
993
996
997
1000 };
1001
1002 EXPECT_EQ(
points, expected);
1003}
1004
1005TEST(EntityGeometryTest, TinyCubicGeneratesCaps) {
1007 path_builder.
MoveTo({20, 20});
1008 path_builder.
CubicCurveTo({20.0625, 20}, {20.125, 20}, {20.250, 20});
1010
1011 auto points = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1012 path,
1013 {
1014 .width = 4.0f,
1015 .cap = Cap::kSquare,
1016 .join = Join::kBevel,
1017 .miter_limit = 4.0f,
1018 },
1019 1.0f);
1020
1021 std::vector<Point> expected = {
1022
1025
1026
1029
1030
1033
1034
1037 };
1038
1039 EXPECT_EQ(
points, expected);
1040}
1041
1042TEST(EntityGeometryTest, TwoLineSegmentsMiterLimit) {
1043
1044 for (int degrees = 10; degrees < 180; degrees += 10) {
1045
1046
1050 Point pixel_delta =
Point(std::cos(r.radians), std::sin(r.radians));
1051
1052 if (pixel_delta.GetDistance(
Point(1, 0)) *
width < 1.0f) {
1053
1054
1055
1056
1057 continue;
1058 }
1059
1060
1061 Degrees between(180 - degrees);
1062 Radians r_between(between);
1063 Scalar limit = 1.0f / std::sin(r_between.radians / 2.0f);
1064
1068 path_builder.
LineTo(
Point(30, 20) + pixel_delta * 10.0f);
1070
1071
1072 auto points1 =
1073 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1074 path,
1075 {
1077 .cap = Cap::kButt,
1078 .join = Join::kMiter,
1079 .miter_limit = limit * 0.99f,
1080 },
1081 1.0f);
1082 EXPECT_EQ(points1.size(), 8u)
1083 <<
"degrees: " << degrees <<
", width: " <<
width <<
", "
1084 << points1[4];
1085
1086
1087 auto points2 =
1088 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1089 path,
1090 {
1092 .cap = Cap::kButt,
1093 .join = Join::kMiter,
1094 .miter_limit = limit * 1.01f,
1095 },
1096 1.0f);
1097 EXPECT_EQ(points2.size(), 9u)
1098 <<
"degrees: " << degrees <<
", width: " <<
width;
1099 EXPECT_LE(points2[4].GetDistance({30, 20}),
width * limit * 1.05f)
1100 <<
"degrees: " << degrees <<
", width: " <<
width <<
", "
1101 << points2[4];
1102 }
1103 }
1104}
1105
1106TEST(EntityGeometryTest, TwoLineSegments180DegreeJoins) {
1107
1113
1114 auto points_bevel =
1115 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1116 path,
1117 {
1118 .width = 20.0f,
1119 .cap = Cap::kButt,
1120 .join = Join::kBevel,
1121 .miter_limit = 4.0f,
1122 },
1123 1.0f);
1124
1125 EXPECT_EQ(points_bevel.size(), 8u);
1126
1127 auto points_miter =
1128 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1129 path,
1130 {
1131 .width = 20.0f,
1132 .cap = Cap::kButt,
1133 .join = Join::kMiter,
1134 .miter_limit = 400.0f,
1135 },
1136 1.0f);
1137
1138 EXPECT_EQ(points_miter.size(), 8u);
1139
1140 auto points_round =
1141 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1142 path,
1143 {
1144 .width = 20.0f,
1145 .cap = Cap::kButt,
1146 .join = Join::kRound,
1147 .miter_limit = 4.0f,
1148 },
1149 1.0f);
1150
1151 EXPECT_EQ(points_round.size(), 19u);
1152}
1153
1154TEST(EntityGeometryTest, TightQuadratic180DegreeJoins) {
1155
1156
1161
1162 auto points_bevel_reference =
1163 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1164 path_reference,
1165 {
1166 .width = 20.0f,
1167 .cap = Cap::kButt,
1168 .join = Join::kBevel,
1169 .miter_limit = 4.0f,
1170 },
1171 1.0f);
1172
1173 EXPECT_EQ(points_bevel_reference.size(), 74u);
1174
1175
1180
1181 auto points_bevel =
1182 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1183 path,
1184 {
1185 .width = 20.0f,
1186 .cap = Cap::kButt,
1187 .join = Join::kBevel,
1188 .miter_limit = 4.0f,
1189 },
1190 1.0f);
1191
1192 EXPECT_GT(points_bevel.size(), points_bevel_reference.size());
1193
1194 auto points_miter =
1195 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1196 path,
1197 {
1198 .width = 20.0f,
1199 .cap = Cap::kButt,
1200 .join = Join::kMiter,
1201 .miter_limit = 400.0f,
1202 },
1203 1.0f);
1204
1205 EXPECT_GT(points_miter.size(), points_bevel_reference.size());
1206
1207 auto points_round =
1208 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1209 path,
1210 {
1211 .width = 20.0f,
1212 .cap = Cap::kButt,
1213 .join = Join::kRound,
1214 .miter_limit = 4.0f,
1215 },
1216 1.0f);
1217
1218 EXPECT_GT(points_round.size(), points_bevel_reference.size());
1219}
1220
1221TEST(EntityGeometryTest, TightConic180DegreeJoins) {
1222
1223
1228
1229 auto points_bevel_reference =
1230 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1231 path_reference,
1232 {
1233 .width = 20.0f,
1234 .cap = Cap::kButt,
1235 .join = Join::kBevel,
1236 .miter_limit = 4.0f,
1237 },
1238 1.0f);
1239
1240 EXPECT_EQ(points_bevel_reference.size(), 78u);
1241
1242
1247
1248 auto points_bevel =
1249 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1250 path,
1251 {
1252 .width = 20.0f,
1253 .cap = Cap::kButt,
1254 .join = Join::kBevel,
1255 .miter_limit = 4.0f,
1256 },
1257 1.0f);
1258
1259 EXPECT_GT(points_bevel.size(), points_bevel_reference.size());
1260
1261 auto points_miter =
1262 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1263 path,
1264 {
1265 .width = 20.0f,
1266 .cap = Cap::kButt,
1267 .join = Join::kMiter,
1268 .miter_limit = 400.0f,
1269 },
1270 1.0f);
1271
1272 EXPECT_GT(points_miter.size(), points_bevel_reference.size());
1273
1274 auto points_round =
1275 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1276 path,
1277 {
1278 .width = 20.0f,
1279 .cap = Cap::kButt,
1280 .join = Join::kRound,
1281 .miter_limit = 4.0f,
1282 },
1283 1.0f);
1284
1285 EXPECT_GT(points_round.size(), points_bevel_reference.size());
1286}
1287
1288TEST(EntityGeometryTest, TightCubic180DegreeJoins) {
1289
1290
1296
1297 auto points_reference =
1298 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1299 path_reference,
1300 {
1301 .width = 20.0f,
1302 .cap = Cap::kButt,
1303 .join = Join::kBevel,
1304 .miter_limit = 4.0f,
1305 },
1306 1.0f);
1307
1308 EXPECT_EQ(points_reference.size(), 76u);
1309
1310
1315
1316 auto points_bevel =
1317 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1318 path,
1319 {
1320 .width = 20.0f,
1321 .cap = Cap::kButt,
1322 .join = Join::kBevel,
1323 .miter_limit = 4.0f,
1324 },
1325 1.0f);
1326
1327 EXPECT_GT(points_bevel.size(), points_reference.size());
1328
1329 auto points_miter =
1330 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1331 path,
1332 {
1333 .width = 20.0f,
1334 .cap = Cap::kButt,
1335 .join = Join::kMiter,
1336 .miter_limit = 400.0f,
1337 },
1338 1.0f);
1339
1340 EXPECT_GT(points_miter.size(), points_reference.size());
1341
1342 auto points_round =
1343 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
1344 path,
1345 {
1346 .width = 20.0f,
1347 .cap = Cap::kButt,
1348 .join = Join::kRound,
1349 .miter_limit = 4.0f,
1350 },
1351 1.0f);
1352
1353 EXPECT_GT(points_round.size(), points_reference.size());
1354}
1355
1356TEST(EntityGeometryTest, RotatedFilledCircleGeometryCoverage) {
1358 auto geometry = Geometry::MakeCircle(center, 50);
1359 Rect circle_bounds = Rect::MakeLTRB(0, 0, 100, 100);
1360 ASSERT_EQ(geometry->GetCoverage({}).value_or(
Rect()), circle_bounds);
1361
1362 Matrix transform45 = Matrix::MakeTranslation(center) *
1363 Matrix::MakeRotationZ(Degrees(45)) *
1364 Matrix::MakeTranslation(-center);
1365
1366 EXPECT_TRUE(geometry->GetCoverage(transform45).has_value());
1367 Rect bounds = geometry->GetCoverage(transform45).value_or(
Rect());
1368 EXPECT_TRUE(bounds.Contains(circle_bounds))
1369 << "geometry bounds: " << bounds << std::endl
1370 << " circle bounds: " << circle_bounds;
1371}
1372
1373TEST(EntityGeometryTest, RotatedStrokedCircleGeometryCoverage) {
1375 auto geometry = Geometry::MakeStrokedCircle(center, 50, 10);
1376 Rect circle_bounds = Rect::MakeLTRB(0, 0, 100, 100).
Expand(5);
1377 ASSERT_EQ(geometry->GetCoverage({}).value_or(
Rect()), circle_bounds);
1378
1379 Matrix transform45 = Matrix::MakeTranslation(center) *
1380 Matrix::MakeRotationZ(Degrees(45)) *
1381 Matrix::MakeTranslation(-center);
1382
1383 EXPECT_TRUE(geometry->GetCoverage(transform45).has_value());
1384 Rect bounds = geometry->GetCoverage(transform45).value_or(
Rect());
1385 EXPECT_TRUE(bounds.Contains(circle_bounds))
1386 << "geometry bounds: " << bounds << std::endl
1387 << " circle bounds: " << circle_bounds;
1388}
1389
1390}
1391}
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