Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
aiks_dl_shadow_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
13
14namespace impeller {
15namespace testing {
16
17using namespace flutter;
18
19namespace {
20/// @brief Reflect the segments of a path around a coordinate using the
21/// PathReceiver interface.
22class PathReflector : public PathReceiver {
23 public:
24 /// Reflect a path horizontally around the given x coordinate.
25 static PathReflector ReflectAroundX(Scalar x_coordinate) {
26 return PathReflector(-1.0f, x_coordinate * 2.0f, 1.0f, 0.0f);
27 }
28
29 /// Reflect a path vertically around the given y coordinate.
30 static PathReflector ReflectAroundY(Scalar y_coordinate) {
31 return PathReflector(1.0f, 0.0f, -1.0f, y_coordinate * 2.0f);
32 }
33
34 /// Reflect a path horizontally and vertically around the given coordinate.
35 static PathReflector ReflectAround(const Point& anchor) {
36 return PathReflector(-1.0f, anchor.x * 2.0f, -1.0f, anchor.y * 2.0f);
37 }
38
39 // |PathReceiver|
40 void MoveTo(const Point& p2, bool will_be_closed) override {
41 path_builder_.MoveTo(reflect(p2));
42 }
43
44 // |PathReceiver|
45 void LineTo(const Point& p2) override { path_builder_.LineTo(reflect(p2)); }
46
47 // |PathReceiver|
48 void QuadTo(const Point& cp, const Point& p2) override {
49 path_builder_.QuadraticCurveTo(reflect(cp), reflect(p2));
50 }
51
52 // |PathReceiver|
53 bool ConicTo(const Point& cp, const Point& p2, Scalar weight) override {
54 path_builder_.ConicCurveTo(reflect(cp), reflect(p2), weight);
55 return true;
56 }
57
58 // |PathReceiver|
59 void CubicTo(const Point& cp1, const Point& cp2, const Point& p2) override {
60 path_builder_.CubicCurveTo(reflect(cp1), reflect(cp2), reflect(p2));
61 }
62
63 // |PathReceiver|
64 void Close() override { path_builder_.Close(); }
65
66 DlPath TakePath() { return path_builder_.TakePath(); }
67
68 private:
69 PathReflector(Scalar scale_x,
70 Scalar translate_x,
71 Scalar scale_y,
72 Scalar translate_y)
73 : scale_x_(scale_x),
74 translate_x_(translate_x),
75 scale_y_(scale_y),
76 translate_y_(translate_y) {}
77
78 const Scalar scale_x_;
79 const Scalar translate_x_;
80 const Scalar scale_y_;
81 const Scalar translate_y_;
82
83 DlPoint reflect(const DlPoint& in_point) {
84 return DlPoint(in_point.x * scale_x_ + translate_x_,
85 in_point.y * scale_y_ + translate_y_);
86 }
87
88 DlPathBuilder path_builder_;
89};
90
91DlPath ReflectPath(const DlPath& path) {
92 PathReflector reflector =
93 PathReflector::ReflectAroundY(path.GetBounds().GetCenter().y);
94 path.Dispatch(reflector);
95 return reflector.TakePath();
96}
97
98void DrawShadowMesh(DisplayListBuilder& builder,
99 const DlPath& path,
100 Scalar elevation,
101 Scalar dpr) {
102 bool should_optimize = path.IsConvex();
103 Matrix matrix = builder.GetMatrix();
104
105 // From dl_dispatcher, making a MaskFilter.
106 Scalar light_radius = 800 / 600;
107 EXPECT_EQ(light_radius, 1.0f); // Value in dl_dispatcher is bad.
108 Scalar occluder_z = elevation * dpr;
109 Radius radius = Radius{light_radius * occluder_z / matrix.GetScale().y};
110 Sigma sigma = radius;
111
112 // From canvas.cc computing the device radius.
113 Scalar device_radius = sigma.sigma * 2.8 * matrix.GetMaxBasisLengthXY();
114
115 Tessellator tessellator;
116 std::shared_ptr<ShadowVertices> shadow_vertices =
118 device_radius, matrix);
119 EXPECT_EQ(shadow_vertices != nullptr, should_optimize);
120 Point shadow_translate = Point(0, occluder_z) * matrix.Invert().GetScale().y;
121
122 DlPaint paint;
123 paint.setDrawStyle(DlDrawStyle::kStroke);
125
126 if (shadow_vertices) {
127 builder.Save();
128 builder.Translate(shadow_translate.x, shadow_translate.y);
129 auto indices = shadow_vertices->GetIndices();
130 auto vertices = shadow_vertices->GetVertices();
131 DlPathBuilder mesh_builder;
132 for (size_t i = 0; i < shadow_vertices->GetIndexCount(); i += 3) {
133 mesh_builder.MoveTo(vertices[indices[i + 0]]);
134 mesh_builder.LineTo(vertices[indices[i + 1]]);
135 mesh_builder.LineTo(vertices[indices[i + 2]]);
136 mesh_builder.Close();
137 }
138 DlPath mesh_path = mesh_builder.TakePath();
139 builder.DrawPath(mesh_path, paint);
140 builder.Restore();
141 }
142
143 builder.Save();
144 builder.Translate(shadow_translate.x, shadow_translate.y);
145 paint.setColor(DlColor::kPurple());
146 builder.DrawPath(path, paint);
147 builder.Restore();
148}
149
150DlPath MakeComplexPath(const DlPath& path) {
151 DlPathBuilder path_builder;
152 path_builder.AddPath(path);
153 // A single line contour won't make any visible change to the shadow,
154 // but none of the shadow to mesh converters will touch a path that
155 // has multiple contours so this path should always default to the
156 // general shadow code based on a blur filter.
157 path_builder.LineTo(DlPoint(0, 0));
158 return path_builder.TakePath();
159}
160
161void DrawShadowAndCompareMeshes(DisplayListBuilder& builder,
162 const DlPath& path,
163 Scalar elevation,
164 Scalar dpr,
165 const DlPath* simple_path = nullptr) {
166 DlPath complex_path = MakeComplexPath(path);
167
168 builder.Save();
169
170 if (simple_path) {
171 builder.DrawShadow(*simple_path, DlColor::kBlue(), elevation, true, dpr);
172 }
173
174 builder.Translate(300, 0);
175 builder.DrawShadow(path, DlColor::kBlue(), elevation, true, dpr);
176
177 builder.Translate(300, 0);
178 builder.DrawShadow(complex_path, DlColor::kBlue(), elevation, true, dpr);
179
180 builder.Restore();
181 builder.Translate(0, 300);
182 builder.Save();
183
184 // Draw the mesh wireframe underneath the regular path output in the
185 // row above us.
186 builder.Translate(300, 0);
187 builder.DrawShadow(path, DlColor::kBlue(), elevation, true, dpr);
188 DrawShadowMesh(builder, path, elevation, dpr);
189
190 builder.Restore();
191}
192
193// Makes a Round Rect path using conics, but the weights on the corners is
194// off by just a tiny amount so the path will not be recognized.
195DlPath MakeAlmostRoundRectPath(const Rect& bounds,
196 const RoundingRadii& radii,
197 bool clockwise = true) {
198 DlScalar left = bounds.GetLeft();
199 DlScalar top = bounds.GetTop();
200 DlScalar right = bounds.GetRight();
201 DlScalar bottom = bounds.GetBottom();
202
203 // A weight of sqrt(2)/2 is how you really perform conic circular sections,
204 // but by tweaking it slightly the path will not be recognized as an oval
205 // and accelerated.
206 constexpr Scalar kWeight = kSqrt2Over2 - 0.0005f;
207
208 DlPathBuilder path_builder;
209 path_builder.MoveTo(DlPoint(right - radii.top_right.width, top));
210 path_builder.ConicCurveTo(DlPoint(right, top),
211 DlPoint(right, top + radii.top_right.height),
212 kWeight);
213 path_builder.LineTo(DlPoint(right, bottom - radii.bottom_right.height));
214 path_builder.ConicCurveTo(DlPoint(right, bottom),
215 DlPoint(right - radii.bottom_right.width, bottom),
216 kWeight);
217 path_builder.LineTo(DlPoint(left + radii.bottom_left.width, bottom));
218 path_builder.ConicCurveTo(DlPoint(left, bottom),
219 DlPoint(left, bottom - radii.bottom_left.height),
220 kWeight);
221 path_builder.LineTo(DlPoint(left, top + radii.top_left.height));
222 path_builder.ConicCurveTo(DlPoint(left, top),
223 DlPoint(left + radii.top_left.width, top), //
224 kWeight);
225 path_builder.Close();
226 DlPath path = path_builder.TakePath();
227 if (!clockwise) {
228 path = ReflectPath(path);
229 }
230 return path;
231}
232} // namespace
233
234TEST_P(AiksTest, DrawShadowDoesNotOptimizeHourglass) {
235 DisplayListBuilder builder;
236 builder.Clear(DlColor::kWhite());
237 builder.Scale(GetContentScale().x, GetContentScale().y);
238 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
239 Scalar elevation = 30.0f;
240
241 DlPathBuilder path_builder;
242 path_builder.MoveTo(DlPoint(100, 100));
243 path_builder.LineTo(DlPoint(300, 300));
244 path_builder.LineTo(DlPoint(100, 300));
245 path_builder.LineTo(DlPoint(300, 100));
246 path_builder.Close();
247 DlPath path = path_builder.TakePath();
248
249 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
250
251 auto dl = builder.Build();
252 ASSERT_TRUE(OpenPlaygroundHere(dl));
253}
254
255TEST_P(AiksTest, DrawShadowDoesNotOptimizeInnerOuterSpiral) {
256 DisplayListBuilder builder;
257 builder.Clear(DlColor::kWhite());
258 builder.Scale(GetContentScale().x, GetContentScale().y);
259 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
260 Scalar elevation = 30.0f;
261 int step_count = 20;
262
263 DlPathBuilder path_builder;
264 path_builder.MoveTo(DlPoint(300, 200));
265 for (int i = 1; i < step_count * 2; i++) {
266 Scalar angle = (k2Pi * i) / step_count;
267 Scalar radius = 80.0f + std::abs(i - step_count);
268 path_builder.LineTo(DlPoint(200, 200) + DlPoint(std::cos(angle) * radius,
269 std::sin(angle) * radius));
270 }
271 path_builder.Close();
272 DlPath path = path_builder.TakePath();
273
274 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
275
276 auto dl = builder.Build();
277 ASSERT_TRUE(OpenPlaygroundHere(dl));
278}
279
280TEST_P(AiksTest, DrawShadowDoesNotOptimizeOuterInnerSpiral) {
281 DisplayListBuilder builder;
282 builder.Clear(DlColor::kWhite());
283 builder.Scale(GetContentScale().x, GetContentScale().y);
284 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
285 Scalar elevation = 30.0f;
286 int step_count = 20;
287
288 DlPathBuilder path_builder;
289 path_builder.MoveTo(DlPoint(280, 200));
290 for (int i = 1; i < step_count * 2; i++) {
291 Scalar angle = (k2Pi * i) / step_count;
292 Scalar radius = 100.0f - std::abs(i - step_count);
293 path_builder.LineTo(DlPoint(200, 200) + DlPoint(std::cos(angle) * radius,
294 std::sin(angle) * radius));
295 }
296 path_builder.Close();
297 DlPath path = path_builder.TakePath();
298
299 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
300
301 auto dl = builder.Build();
302 ASSERT_TRUE(OpenPlaygroundHere(dl));
303}
304
305TEST_P(AiksTest, DrawShadowDoesNotOptimizeMultipleContours) {
306 DisplayListBuilder builder;
307 builder.Clear(DlColor::kWhite());
308 builder.Scale(GetContentScale().x, GetContentScale().y);
309 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
310 Scalar elevation = 30.0f;
311
312 DlPathBuilder path_builder;
313 path_builder.MoveTo(DlPoint(150, 100));
314 path_builder.LineTo(DlPoint(200, 300));
315 path_builder.LineTo(DlPoint(100, 300));
316 path_builder.Close();
317 path_builder.MoveTo(DlPoint(250, 100));
318 path_builder.LineTo(DlPoint(300, 300));
319 path_builder.LineTo(DlPoint(200, 300));
320 path_builder.Close();
321 DlPath path = path_builder.TakePath();
322
323 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
324
325 auto dl = builder.Build();
326 ASSERT_TRUE(OpenPlaygroundHere(dl));
327}
328
329TEST_P(AiksTest, DrawShadowCanOptimizeClockwiseTriangle) {
330 DisplayListBuilder builder;
331 builder.Clear(DlColor::kWhite());
332 builder.Scale(GetContentScale().x, GetContentScale().y);
333 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
334 Scalar elevation = 30.0f;
335
336 DlPathBuilder path_builder;
337 path_builder.MoveTo(DlPoint(200, 100));
338 path_builder.LineTo(DlPoint(300, 300));
339 path_builder.LineTo(DlPoint(100, 300));
340 path_builder.Close();
341 DlPath path = path_builder.TakePath();
342
343 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
344
345 auto dl = builder.Build();
346 ASSERT_TRUE(OpenPlaygroundHere(dl));
347}
348
349TEST_P(AiksTest, DrawShadowCanOptimizeCounterClockwiseTriangle) {
350 DisplayListBuilder builder;
351 builder.Clear(DlColor::kWhite());
352 builder.Scale(GetContentScale().x, GetContentScale().y);
353 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
354 Scalar elevation = 30.0f;
355
356 DlPathBuilder path_builder;
357 path_builder.MoveTo(DlPoint(200, 100));
358 path_builder.LineTo(DlPoint(100, 300));
359 path_builder.LineTo(DlPoint(300, 300));
360 path_builder.Close();
361 DlPath path = path_builder.TakePath();
362
363 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
364
365 auto dl = builder.Build();
366 ASSERT_TRUE(OpenPlaygroundHere(dl));
367}
368
369TEST_P(AiksTest, DrawShadowCanOptimizeClockwiseRect) {
370 DisplayListBuilder builder;
371 builder.Clear(DlColor::kWhite());
372 builder.Scale(GetContentScale().x, GetContentScale().y);
373 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
374 Scalar elevation = 30.0f;
375
376 DlPathBuilder path_builder;
377 path_builder.MoveTo(DlPoint(100, 100));
378 // Tweak one corner by a sub-pixel amount to prevent recognition as
379 // a rectangle, but still generating a rectangular shadow.
380 path_builder.LineTo(DlPoint(299.9, 100));
381 path_builder.LineTo(DlPoint(300, 300));
382 path_builder.LineTo(DlPoint(100, 300));
383 path_builder.Close();
384 DlPath path = path_builder.TakePath();
385
386 // Path must be convex, but unrecognizable as a simple shape.
387 ASSERT_TRUE(path.IsConvex());
388 ASSERT_FALSE(path.IsRect());
389 ASSERT_FALSE(path.IsOval());
390 ASSERT_FALSE(path.IsRoundRect());
391
392 const DlPath simple_path = DlPath::MakeRectLTRB(100, 100, 300, 300);
393 DrawShadowAndCompareMeshes(builder, path, elevation, dpr, &simple_path);
394
395 auto dl = builder.Build();
396 ASSERT_TRUE(OpenPlaygroundHere(dl));
397}
398
399TEST_P(AiksTest, DrawShadowCanOptimizeCounterClockwiseRect) {
400 DisplayListBuilder builder;
401 builder.Clear(DlColor::kWhite());
402 builder.Scale(GetContentScale().x, GetContentScale().y);
403 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
404 Scalar elevation = 30.0f;
405
406 DlPathBuilder path_builder;
407 path_builder.MoveTo(DlPoint(100, 100));
408 path_builder.LineTo(DlPoint(100, 300));
409 path_builder.LineTo(DlPoint(300, 300));
410 // Tweak one corner by a sub-pixel amount to prevent recognition as
411 // a rectangle, but still generating a rectangular shadow.
412 path_builder.LineTo(DlPoint(299.9, 100));
413 path_builder.Close();
414 DlPath path = path_builder.TakePath();
415
416 // Path must be convex, but unrecognizable as a simple shape.
417 ASSERT_TRUE(path.IsConvex());
418 ASSERT_FALSE(path.IsRect());
419 ASSERT_FALSE(path.IsOval());
420 ASSERT_FALSE(path.IsRoundRect());
421
422 const DlPath simple_path = DlPath::MakeRectLTRB(100, 100, 300, 300);
423 DrawShadowAndCompareMeshes(builder, path, elevation, dpr, &simple_path);
424
425 auto dl = builder.Build();
426 ASSERT_TRUE(OpenPlaygroundHere(dl));
427}
428
429TEST_P(AiksTest, DrawShadowCanOptimizeClockwiseCircle) {
430 DisplayListBuilder builder;
431 builder.Clear(DlColor::kWhite());
432 builder.Scale(GetContentScale().x, GetContentScale().y);
433 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
434 Scalar elevation = 30.0f;
435
436 // A weight of sqrt(2) is how you really perform conic circular sections,
437 // but by tweaking it slightly the path will not be recognized as an oval
438 // and accelerated.
439 constexpr Scalar kWeight = kSqrt2Over2 - 0.0005f;
440
441 DlPathBuilder path_builder;
442 path_builder.MoveTo(DlPoint(200, 100));
443 path_builder.ConicCurveTo(DlPoint(300, 100), DlPoint(300, 200), kWeight);
444 path_builder.ConicCurveTo(DlPoint(300, 300), DlPoint(200, 300), kWeight);
445 path_builder.ConicCurveTo(DlPoint(100, 300), DlPoint(100, 200), kWeight);
446 path_builder.ConicCurveTo(DlPoint(100, 100), DlPoint(200, 100), kWeight);
447 path_builder.Close();
448 DlPath path = path_builder.TakePath();
449
450 // Path must be convex, but unrecognizable as a simple shape.
451 ASSERT_TRUE(path.IsConvex());
452 ASSERT_FALSE(path.IsRect());
453 ASSERT_FALSE(path.IsOval());
454 ASSERT_FALSE(path.IsRoundRect());
455
456 const DlPath simple_path = DlPath::MakeCircle(DlPoint(200, 200), 100);
457 DrawShadowAndCompareMeshes(builder, path, elevation, dpr, &simple_path);
458
459 auto dl = builder.Build();
460 ASSERT_TRUE(OpenPlaygroundHere(dl));
461}
462
463TEST_P(AiksTest, DrawShadowCanOptimizeCounterClockwiseCircle) {
464 DisplayListBuilder builder;
465 builder.Clear(DlColor::kWhite());
466 builder.Scale(GetContentScale().x, GetContentScale().y);
467 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
468 Scalar elevation = 30.0f;
469
470 // A weight of sqrt(2)/2 is how you really perform conic circular sections,
471 // but by tweaking it slightly the path will not be recognized as an oval
472 // and accelerated.
473 constexpr Scalar kWeight = kSqrt2Over2 - 0.0005f;
474
475 DlPathBuilder path_builder;
476 path_builder.MoveTo(DlPoint(200, 100));
477 path_builder.ConicCurveTo(DlPoint(100, 100), DlPoint(100, 200), kWeight);
478 path_builder.ConicCurveTo(DlPoint(100, 300), DlPoint(200, 300), kWeight);
479 path_builder.ConicCurveTo(DlPoint(300, 300), DlPoint(300, 200), kWeight);
480 path_builder.ConicCurveTo(DlPoint(300, 100), DlPoint(200, 100), kWeight);
481 path_builder.Close();
482 DlPath path = path_builder.TakePath();
483
484 // Path must be convex, but unrecognizable as a simple shape.
485 ASSERT_TRUE(path.IsConvex());
486 ASSERT_FALSE(path.IsRect());
487 ASSERT_FALSE(path.IsOval());
488 ASSERT_FALSE(path.IsRoundRect());
489
490 const DlPath simple_path = DlPath::MakeCircle(DlPoint(200, 200), 100);
491 DrawShadowAndCompareMeshes(builder, path, elevation, dpr, &simple_path);
492
493 auto dl = builder.Build();
494 ASSERT_TRUE(OpenPlaygroundHere(dl));
495}
496
497TEST_P(AiksTest, DrawShadowCanOptimizeClockwiseOval) {
498 DisplayListBuilder builder;
499 builder.Clear(DlColor::kWhite());
500 builder.Scale(GetContentScale().x, GetContentScale().y);
501 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
502 Scalar elevation = 30.0f;
503
504 // A weight of sqrt(2) is how you really perform conic circular sections,
505 // but by tweaking it slightly the path will not be recognized as an oval
506 // and accelerated.
507 constexpr Scalar kWeight = kSqrt2Over2 - 0.0005f;
508
509 DlPathBuilder path_builder;
510 path_builder.MoveTo(DlPoint(200, 120));
511 path_builder.ConicCurveTo(DlPoint(300, 120), DlPoint(300, 200), kWeight);
512 path_builder.ConicCurveTo(DlPoint(300, 280), DlPoint(200, 280), kWeight);
513 path_builder.ConicCurveTo(DlPoint(100, 280), DlPoint(100, 200), kWeight);
514 path_builder.ConicCurveTo(DlPoint(100, 120), DlPoint(200, 120), kWeight);
515 path_builder.Close();
516 DlPath path = path_builder.TakePath();
517
518 // Path must be convex, but unrecognizable as a simple shape.
519 ASSERT_TRUE(path.IsConvex());
520 ASSERT_FALSE(path.IsRect());
521 ASSERT_FALSE(path.IsOval());
522 ASSERT_FALSE(path.IsRoundRect());
523
524 const DlPath simple_path = DlPath::MakeOvalLTRB(100, 120, 300, 280);
525 DrawShadowAndCompareMeshes(builder, path, elevation, dpr, &simple_path);
526
527 auto dl = builder.Build();
528 ASSERT_TRUE(OpenPlaygroundHere(dl));
529}
530
531TEST_P(AiksTest, DrawShadowCanOptimizeCounterClockwiseOval) {
532 DisplayListBuilder builder;
533 builder.Clear(DlColor::kWhite());
534 builder.Scale(GetContentScale().x, GetContentScale().y);
535 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
536 Scalar elevation = 30.0f;
537
538 // A weight of sqrt(2)/2 is how you really perform conic circular sections,
539 // but by tweaking it slightly the path will not be recognized as an oval
540 // and accelerated.
541 constexpr Scalar kWeight = kSqrt2Over2 - 0.0005f;
542
543 DlPathBuilder path_builder;
544 path_builder.MoveTo(DlPoint(200, 120));
545 path_builder.ConicCurveTo(DlPoint(100, 120), DlPoint(100, 200), kWeight);
546 path_builder.ConicCurveTo(DlPoint(100, 280), DlPoint(200, 280), kWeight);
547 path_builder.ConicCurveTo(DlPoint(300, 280), DlPoint(300, 200), kWeight);
548 path_builder.ConicCurveTo(DlPoint(300, 120), DlPoint(200, 120), kWeight);
549 path_builder.Close();
550 DlPath path = path_builder.TakePath();
551
552 // Path must be convex, but unrecognizable as a simple shape.
553 ASSERT_TRUE(path.IsConvex());
554 ASSERT_FALSE(path.IsRect());
555 ASSERT_FALSE(path.IsOval());
556 ASSERT_FALSE(path.IsRoundRect());
557
558 const DlPath simple_path = DlPath::MakeOvalLTRB(100, 120, 300, 280);
559 DrawShadowAndCompareMeshes(builder, path, elevation, dpr, &simple_path);
560
561 auto dl = builder.Build();
562 ASSERT_TRUE(OpenPlaygroundHere(dl));
563}
564
565TEST_P(AiksTest, DrawShadowCanOptimizeClockwiseUniformRoundRect) {
566 DisplayListBuilder builder;
567 builder.Clear(DlColor::kWhite());
568 builder.Scale(GetContentScale().x, GetContentScale().y);
569 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
570 Scalar elevation = 30.0f;
571
572 DlPath path = MakeAlmostRoundRectPath(DlRect::MakeLTRB(100, 100, 300, 300),
574
575 // Path must be convex, but unrecognizable as a simple shape.
576 ASSERT_TRUE(path.IsConvex());
577 ASSERT_FALSE(path.IsRect());
578 ASSERT_FALSE(path.IsOval());
579 ASSERT_FALSE(path.IsRoundRect());
580
581 const RoundRect round_rect =
582 RoundRect::MakeRectRadius(Rect::MakeLTRB(100, 100, 300, 300), 30);
583 const DlPath simple_path = DlPath::MakeRoundRect(round_rect);
584 DrawShadowAndCompareMeshes(builder, path, elevation, dpr, &simple_path);
585
586 auto dl = builder.Build();
587 ASSERT_TRUE(OpenPlaygroundHere(dl));
588}
589
590TEST_P(AiksTest, DrawShadowCanOptimizeCounterClockwiseUniformRoundRect) {
591 DisplayListBuilder builder;
592 builder.Clear(DlColor::kWhite());
593 builder.Scale(GetContentScale().x, GetContentScale().y);
594 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
595 Scalar elevation = 30.0f;
596
597 DlPath path = MakeAlmostRoundRectPath(DlRect::MakeLTRB(100, 100, 300, 300),
598 DlRoundingRadii::MakeRadius(30), false);
599
600 // Path must be convex, but unrecognizable as a simple shape.
601 ASSERT_TRUE(path.IsConvex());
602 ASSERT_FALSE(path.IsRect());
603 ASSERT_FALSE(path.IsOval());
604 ASSERT_FALSE(path.IsRoundRect());
605
606 const RoundRect round_rect =
607 RoundRect::MakeRectRadius(Rect::MakeLTRB(100, 100, 300, 300), 30);
608 const DlPath simple_path = DlPath::MakeRoundRect(round_rect);
609 DrawShadowAndCompareMeshes(builder, path, elevation, dpr, &simple_path);
610
611 auto dl = builder.Build();
612 ASSERT_TRUE(OpenPlaygroundHere(dl));
613}
614
615TEST_P(AiksTest, DrawShadowCanOptimizeClockwiseMultiRadiiRoundRect) {
616 DisplayListBuilder builder;
617 builder.Clear(DlColor::kWhite());
618 builder.Scale(GetContentScale().x, GetContentScale().y);
619 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
620 Scalar elevation = 30.0f;
621
623 .top_left = {80, 60},
624 .top_right = {20, 25},
625 .bottom_left = {60, 80},
626 .bottom_right = {25, 20},
627 };
628 DlPath path = MakeAlmostRoundRectPath(DlRect::MakeLTRB(100, 100, 300, 300),
629 radii, true);
630
631 // Path must be convex, but unrecognizable as a simple shape.
632 ASSERT_TRUE(path.IsConvex());
633 ASSERT_FALSE(path.IsRect());
634 ASSERT_FALSE(path.IsOval());
635 ASSERT_FALSE(path.IsRoundRect());
636
637 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
638
639 auto dl = builder.Build();
640 ASSERT_TRUE(OpenPlaygroundHere(dl));
641}
642
643TEST_P(AiksTest, DrawShadowCanOptimizeCounterClockwiseMultiRadiiRoundRect) {
644 DisplayListBuilder builder;
645 builder.Clear(DlColor::kWhite());
646 builder.Scale(GetContentScale().x, GetContentScale().y);
647 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
648 Scalar elevation = 30.0f;
649
651 .top_left = {80, 60},
652 .top_right = {20, 25},
653 .bottom_left = {60, 80},
654 .bottom_right = {25, 20},
655 };
656 DlPath path = MakeAlmostRoundRectPath(DlRect::MakeLTRB(100, 100, 300, 300),
657 radii, false);
658
659 // Path must be convex, but unrecognizable as a simple shape.
660 ASSERT_TRUE(path.IsConvex());
661 ASSERT_FALSE(path.IsRect());
662 ASSERT_FALSE(path.IsOval());
663 ASSERT_FALSE(path.IsRoundRect());
664
665 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
666
667 auto dl = builder.Build();
668 ASSERT_TRUE(OpenPlaygroundHere(dl));
669}
670
671TEST_P(AiksTest, DrawShadowCanOptimizeClockwiseQuadratic) {
672 DisplayListBuilder builder;
673 builder.Clear(DlColor::kWhite());
674 builder.Scale(GetContentScale().x, GetContentScale().y);
675 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
676 Scalar elevation = 30.0f;
677
678 DlPathBuilder path_builder;
679 path_builder.MoveTo(DlPoint(200, 100));
680 path_builder.QuadraticCurveTo(DlPoint(300, 100), DlPoint(300, 200));
681 path_builder.QuadraticCurveTo(DlPoint(300, 300), DlPoint(200, 300));
682 path_builder.QuadraticCurveTo(DlPoint(100, 300), DlPoint(100, 200));
683 path_builder.QuadraticCurveTo(DlPoint(100, 100), DlPoint(200, 100));
684 path_builder.Close();
685 DlPath path = path_builder.TakePath();
686
687 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
688
689 auto dl = builder.Build();
690 ASSERT_TRUE(OpenPlaygroundHere(dl));
691}
692
693TEST_P(AiksTest, DrawShadowCanOptimizeCounterClockwiseQuadratic) {
694 DisplayListBuilder builder;
695 builder.Clear(DlColor::kWhite());
696 builder.Scale(GetContentScale().x, GetContentScale().y);
697 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
698 Scalar elevation = 30.0f;
699
700 DlPathBuilder path_builder;
701 path_builder.MoveTo(DlPoint(200, 100));
702 path_builder.QuadraticCurveTo(DlPoint(100, 100), DlPoint(100, 200));
703 path_builder.QuadraticCurveTo(DlPoint(100, 300), DlPoint(200, 300));
704 path_builder.QuadraticCurveTo(DlPoint(300, 300), DlPoint(300, 200));
705 path_builder.QuadraticCurveTo(DlPoint(300, 100), DlPoint(200, 100));
706 path_builder.Close();
707 DlPath path = path_builder.TakePath();
708
709 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
710
711 auto dl = builder.Build();
712 ASSERT_TRUE(OpenPlaygroundHere(dl));
713}
714
715TEST_P(AiksTest, DrawShadowCanOptimizeClockwiseConic) {
716 DisplayListBuilder builder;
717 builder.Clear(DlColor::kWhite());
718 builder.Scale(GetContentScale().x, GetContentScale().y);
719 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
720 Scalar elevation = 30.0f;
721
722 DlPathBuilder path_builder;
723 path_builder.MoveTo(DlPoint(200, 100));
724 path_builder.ConicCurveTo(DlPoint(300, 100), DlPoint(300, 200), 0.4f);
725 path_builder.ConicCurveTo(DlPoint(300, 300), DlPoint(200, 300), 0.4f);
726 path_builder.ConicCurveTo(DlPoint(100, 300), DlPoint(100, 200), 0.4f);
727 path_builder.ConicCurveTo(DlPoint(100, 100), DlPoint(200, 100), 0.4f);
728 path_builder.Close();
729 DlPath path = path_builder.TakePath();
730
731 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
732
733 auto dl = builder.Build();
734 ASSERT_TRUE(OpenPlaygroundHere(dl));
735}
736
737TEST_P(AiksTest, DrawShadowCanOptimizeCounterClockwiseConic) {
738 DisplayListBuilder builder;
739 builder.Clear(DlColor::kWhite());
740 builder.Scale(GetContentScale().x, GetContentScale().y);
741 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
742 Scalar elevation = 30.0f;
743
744 DlPathBuilder path_builder;
745 path_builder.MoveTo(DlPoint(200, 100));
746 path_builder.ConicCurveTo(DlPoint(100, 100), DlPoint(100, 200), 0.4f);
747 path_builder.ConicCurveTo(DlPoint(100, 300), DlPoint(200, 300), 0.4f);
748 path_builder.ConicCurveTo(DlPoint(300, 300), DlPoint(300, 200), 0.4f);
749 path_builder.ConicCurveTo(DlPoint(300, 100), DlPoint(200, 100), 0.4f);
750 path_builder.Close();
751 DlPath path = path_builder.TakePath();
752
753 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
754
755 auto dl = builder.Build();
756 ASSERT_TRUE(OpenPlaygroundHere(dl));
757}
758
759TEST_P(AiksTest, DrawShadowCanOptimizeClockwiseCubic) {
760 DisplayListBuilder builder;
761 builder.Clear(DlColor::kWhite());
762 builder.Scale(GetContentScale().x, GetContentScale().y);
763 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
764 Scalar elevation = 30.0f;
765
766 DlPathBuilder path_builder;
767 path_builder.MoveTo(DlPoint(200, 100));
768 path_builder.CubicCurveTo(DlPoint(280, 100), DlPoint(300, 120),
769 DlPoint(300, 200));
770 path_builder.CubicCurveTo(DlPoint(300, 280), DlPoint(280, 300),
771 DlPoint(200, 300));
772 path_builder.CubicCurveTo(DlPoint(120, 300), DlPoint(100, 280),
773 DlPoint(100, 200));
774 path_builder.CubicCurveTo(DlPoint(100, 120), DlPoint(120, 100),
775 DlPoint(200, 100));
776 path_builder.Close();
777 DlPath path = path_builder.TakePath();
778
779 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
780
781 auto dl = builder.Build();
782 ASSERT_TRUE(OpenPlaygroundHere(dl));
783}
784
785TEST_P(AiksTest, DrawShadowCanOptimizeCounterClockwiseCubic) {
786 DisplayListBuilder builder;
787 builder.Clear(DlColor::kWhite());
788 builder.Scale(GetContentScale().x, GetContentScale().y);
789 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
790 Scalar elevation = 30.0f;
791
792 DlPathBuilder path_builder;
793 path_builder.MoveTo(DlPoint(200, 100));
794 path_builder.CubicCurveTo(DlPoint(120, 100), DlPoint(100, 120),
795 DlPoint(100, 200));
796 path_builder.CubicCurveTo(DlPoint(100, 280), DlPoint(120, 300),
797 DlPoint(200, 300));
798 path_builder.CubicCurveTo(DlPoint(280, 300), DlPoint(300, 280),
799 DlPoint(300, 200));
800 path_builder.CubicCurveTo(DlPoint(300, 120), DlPoint(280, 100),
801 DlPoint(200, 100));
802 path_builder.Close();
803 DlPath path = path_builder.TakePath();
804
805 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
806
807 auto dl = builder.Build();
808 ASSERT_TRUE(OpenPlaygroundHere(dl));
809}
810
811TEST_P(AiksTest, DrawShadowCanOptimizeClockwiseOctagon) {
812 DisplayListBuilder builder;
813 builder.Clear(DlColor::kWhite());
814 builder.Scale(GetContentScale().x, GetContentScale().y);
815 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
816 Scalar elevation = 30.0f;
817
818 DlPathBuilder path_builder;
819 path_builder.MoveTo(DlPoint(100, 125));
820 path_builder.LineTo(DlPoint(125, 100));
821 path_builder.LineTo(DlPoint(275, 100));
822 path_builder.LineTo(DlPoint(300, 125));
823 path_builder.LineTo(DlPoint(300, 275));
824 path_builder.LineTo(DlPoint(275, 300));
825 path_builder.LineTo(DlPoint(125, 300));
826 path_builder.LineTo(DlPoint(100, 275));
827 path_builder.Close();
828 DlPath path = path_builder.TakePath();
829
830 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
831
832 auto dl = builder.Build();
833 ASSERT_TRUE(OpenPlaygroundHere(dl));
834}
835
836TEST_P(AiksTest, DrawShadowCanOptimizeCounterClockwiseOctagon) {
837 DisplayListBuilder builder;
838 builder.Clear(DlColor::kWhite());
839 builder.Scale(GetContentScale().x, GetContentScale().y);
840 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
841 Scalar elevation = 30.0f;
842
843 DlPathBuilder path_builder;
844 path_builder.MoveTo(DlPoint(100, 125));
845 path_builder.LineTo(DlPoint(100, 275));
846 path_builder.LineTo(DlPoint(125, 300));
847 path_builder.LineTo(DlPoint(275, 300));
848 path_builder.LineTo(DlPoint(300, 275));
849 path_builder.LineTo(DlPoint(300, 125));
850 path_builder.LineTo(DlPoint(275, 100));
851 path_builder.LineTo(DlPoint(125, 100));
852 path_builder.Close();
853 DlPath path = path_builder.TakePath();
854
855 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
856
857 auto dl = builder.Build();
858 ASSERT_TRUE(OpenPlaygroundHere(dl));
859}
860
861TEST_P(AiksTest, DrawShadowCanOptimizeWithExtraneousMoveTos) {
862 DisplayListBuilder builder;
863 builder.Clear(DlColor::kWhite());
864 builder.Scale(GetContentScale().x, GetContentScale().y);
865 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
866 Scalar elevation = 30.0f;
867
868 DlPathBuilder path_builder;
869 path_builder.MoveTo(DlPoint(0, 0));
870 path_builder.MoveTo(DlPoint(1000, 1000));
871 path_builder.MoveTo(DlPoint(100, 50));
872 path_builder.MoveTo(DlPoint(200, 100));
873 path_builder.LineTo(DlPoint(300, 300));
874 path_builder.LineTo(DlPoint(100, 300));
875 path_builder.Close();
876 path_builder.MoveTo(DlPoint(1000, 1000));
877 path_builder.MoveTo(DlPoint(500, 300));
878 DlPath path = path_builder.TakePath();
879
880 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
881
882 auto dl = builder.Build();
883 ASSERT_TRUE(OpenPlaygroundHere(dl));
884}
885
886TEST_P(AiksTest, DrawShadowCanOptimizeClockwiseWithExtraColinearVertices) {
887 DisplayListBuilder builder;
888 builder.Clear(DlColor::kWhite());
889 builder.Scale(GetContentScale().x, GetContentScale().y);
890 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
891 Scalar elevation = 30.0f;
892
893 DlPathBuilder path_builder;
894 path_builder.MoveTo(DlPoint(200, 100));
895 path_builder.LineTo(DlPoint(250, 200));
896 path_builder.LineTo(DlPoint(300, 300));
897 path_builder.LineTo(DlPoint(200, 300));
898 path_builder.LineTo(DlPoint(100, 300));
899 path_builder.LineTo(DlPoint(150, 200));
900 path_builder.Close();
901 DlPath path = path_builder.TakePath();
902
903 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
904
905 auto dl = builder.Build();
906 ASSERT_TRUE(OpenPlaygroundHere(dl));
907}
908
910 DrawShadowCanOptimizeCounterClockwiseWithExtraColinearVertices) {
911 DisplayListBuilder builder;
912 builder.Clear(DlColor::kWhite());
913 builder.Scale(GetContentScale().x, GetContentScale().y);
914 Scalar dpr = std::max(GetContentScale().x, GetContentScale().y);
915 Scalar elevation = 30.0f;
916
917 DlPathBuilder path_builder;
918 path_builder.MoveTo(DlPoint(200, 100));
919 path_builder.LineTo(DlPoint(150, 200));
920 path_builder.LineTo(DlPoint(100, 300));
921 path_builder.LineTo(DlPoint(200, 300));
922 path_builder.LineTo(DlPoint(300, 300));
923 path_builder.LineTo(DlPoint(250, 200));
924 path_builder.Close();
925 DlPath path = path_builder.TakePath();
926
927 DrawShadowAndCompareMeshes(builder, path, elevation, dpr);
928
929 auto dl = builder.Build();
930 ASSERT_TRUE(OpenPlaygroundHere(dl));
931}
932
933} // namespace testing
934} // namespace impeller
void DrawShadow(const DlPath &path, const DlColor color, const DlScalar elevation, bool transparent_occluder, DlScalar dpr) override
Draws the shadow of the given |path| rendered in the provided |color| (which is only consulted for it...
DlMatrix GetMatrix() const override
Definition dl_builder.h:102
void Scale(DlScalar sx, DlScalar sy) override
void Translate(DlScalar tx, DlScalar ty) override
sk_sp< DisplayList > Build()
Definition dl_builder.cc:66
void DrawPath(const DlPath &path, const DlPaint &paint) override
void Clear(DlColor color)
Definition dl_canvas.h:104
DlPaint & setColor(DlColor color)
Definition dl_paint.h:70
DlPaint & setDrawStyle(DlDrawStyle style)
Definition dl_paint.h:93
DlPathBuilder & LineTo(DlPoint p2)
Draw a line from the current point to the indicated point p2.
DlPathBuilder & AddPath(const DlPath &path)
Append the provided path to this path as if the commands used to construct it were repeated on this p...
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 & QuadraticCurveTo(DlPoint cp, DlPoint p2)
Draw a quadratic bezier curve from the current point to the indicated point p2, using the indicated p...
DlPathBuilder & Close()
The path is closed back to the location of the most recent MoveTo call. Contours that are filled are ...
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...
static DlPath MakeRectLTRB(DlScalar left, DlScalar top, DlScalar right, DlScalar bottom)
Definition dl_path.cc:43
static DlPath MakeRoundRect(const DlRoundRect &rrect)
Definition dl_path.cc:72
static DlPath MakeCircle(const DlPoint center, DlScalar radius)
Definition dl_path.cc:68
static DlPath MakeOvalLTRB(DlScalar left, DlScalar top, DlScalar right, DlScalar bottom)
Definition dl_path.cc:61
double x() const
Definition geometry.h:22
double y() const
Definition geometry.h:23
double height() const
Definition geometry.h:45
double width() const
Definition geometry.h:44
Collection of functions to receive path segments from the underlying path representation via the DlPa...
Definition path_source.h:42
static std::shared_ptr< ShadowVertices > MakeAmbientShadowVertices(Tessellator &tessellator, const PathSource &source, Scalar occluder_height, const Matrix &matrix)
A utility that generates triangles of the specified fill type given a polyline. This happens on the C...
Definition tessellator.h:37
int32_t x
double y
impeller::Scalar DlScalar
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
Definition switch_defs.h:52
impeller::Point DlPoint
TEST_P(AiksTest, DrawAtlasNoColor)
constexpr float k2Pi
Definition constants.h:29
float Scalar
Definition scalar.h:19
constexpr float kSqrt2Over2
Definition constants.h:51
void MoveTo(PathBuilder *builder, Scalar x, Scalar y)
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
void CubicTo(PathBuilder *builder, Scalar x1, Scalar y1, Scalar x2, Scalar y2, Scalar x3, Scalar y3)
void Close(PathBuilder *builder)
static constexpr DlColor kWhite()
Definition dl_color.h:70
static constexpr DlColor kBlue()
Definition dl_color.h:73
static constexpr DlColor kPurple()
Definition dl_color.h:88
static constexpr DlColor kDarkGrey()
Definition dl_color.h:77
A 4x4 matrix using column-major storage.
Definition matrix.h:37
Matrix Invert() const
Definition matrix.cc:99
Vector3 GetScale() const
Definition matrix.h:394
Scalar GetMaxBasisLengthXY() const
Return the maximum scale applied specifically to either the X axis or Y axis unit vectors (the bases)...
Definition matrix.h:328
For convolution filters, the "radius" is the size of the convolution kernel to use on the local space...
Definition sigma.h:48
static RoundRect MakeRectRadius(const Rect &rect, Scalar radius)
Definition round_rect.h:27
static constexpr RoundingRadii MakeRadius(Scalar radius)
In filters that use Gaussian distributions, "sigma" is a size of one standard deviation in terms of t...
Definition sigma.h:32
Scalar sigma
Definition sigma.h:33
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129