Flutter Engine
 
Loading...
Searching...
No Matches
dl_path_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
7#include "gtest/gtest.h"
8
11#include "flutter/third_party/skia/include/core/SkPath.h"
12#include "flutter/third_party/skia/include/core/SkRRect.h"
13
14namespace flutter {
15namespace testing {
16
17TEST(DisplayListPath, DefaultConstruction) {
19
20 EXPECT_EQ(path, DlPath());
21 EXPECT_EQ(path.GetSkPath(), SkPath());
22 EXPECT_TRUE(path.IsEmpty());
23
24 EXPECT_EQ(path.GetBounds(), DlRect());
25 EXPECT_TRUE(path.IsConvex());
26 EXPECT_EQ(path.GetFillType(), DlPathFillType::kNonZero);
27
28 EXPECT_FALSE(path.IsVolatile());
29
30 bool is_closed = false;
31 EXPECT_FALSE(path.IsRect(nullptr));
32 EXPECT_FALSE(path.IsRect(nullptr, &is_closed));
33 EXPECT_FALSE(is_closed);
34 EXPECT_FALSE(path.IsOval(nullptr));
35 EXPECT_FALSE(path.IsRoundRect(nullptr));
36
37 is_closed = false;
38 EXPECT_FALSE(path.IsRect(nullptr));
39 EXPECT_FALSE(path.IsRect(nullptr, &is_closed));
40 EXPECT_FALSE(is_closed);
41 EXPECT_FALSE(path.IsOval(nullptr));
42 EXPECT_FALSE(path.IsRoundRect(nullptr));
43
44 EXPECT_EQ(path.GetBounds(), DlRect());
45}
46
47TEST(DisplayListPath, ConstructFromEmptySkiaPath) {
48 SkPath sk_path;
49 DlPath path(sk_path);
50
51 EXPECT_EQ(path, DlPath());
52 EXPECT_EQ(path.GetSkPath(), SkPath());
53
54 EXPECT_TRUE(path.IsEmpty());
55 EXPECT_FALSE(path.IsVolatile());
56
57 EXPECT_EQ(path.GetBounds(), DlRect());
58 EXPECT_TRUE(path.IsConvex());
59 EXPECT_EQ(path.GetFillType(), DlPathFillType::kNonZero);
60
61 bool is_closed = false;
62 EXPECT_FALSE(path.IsRect(nullptr));
63 EXPECT_FALSE(path.IsRect(nullptr, &is_closed));
64 EXPECT_FALSE(is_closed);
65 EXPECT_FALSE(path.IsOval(nullptr));
66 EXPECT_FALSE(path.IsRoundRect(nullptr));
67
68 is_closed = false;
69 EXPECT_FALSE(path.IsRect(nullptr));
70 EXPECT_FALSE(path.IsRect(nullptr, &is_closed));
71 EXPECT_FALSE(is_closed);
72 EXPECT_FALSE(path.IsOval(nullptr));
73 EXPECT_FALSE(path.IsRoundRect(nullptr));
74
75 EXPECT_EQ(path.GetBounds(), DlRect());
76}
77
78TEST(DisplayListPath, ConstructFromEmptyDlPathBuilder) {
79 DlPathBuilder path_builder;
80 DlPath path = path_builder.TakePath();
81
82 EXPECT_EQ(path, DlPath());
83 EXPECT_EQ(path.GetSkPath(), SkPath());
84
85 EXPECT_TRUE(path.IsEmpty());
86 EXPECT_FALSE(path.IsVolatile());
87
88 EXPECT_EQ(path.GetBounds(), DlRect());
89 EXPECT_TRUE(path.IsConvex());
90 EXPECT_EQ(path.GetFillType(), DlPathFillType::kNonZero);
91
92 bool is_closed = false;
93 EXPECT_FALSE(path.IsRect(nullptr));
94 EXPECT_FALSE(path.IsRect(nullptr, &is_closed));
95 EXPECT_FALSE(is_closed);
96 EXPECT_FALSE(path.IsOval(nullptr));
97 EXPECT_FALSE(path.IsRoundRect(nullptr));
98
99 is_closed = false;
100 EXPECT_FALSE(path.IsRect(nullptr));
101 EXPECT_FALSE(path.IsRect(nullptr, &is_closed));
102 EXPECT_FALSE(is_closed);
103 EXPECT_FALSE(path.IsOval(nullptr));
104 EXPECT_FALSE(path.IsRoundRect(nullptr));
105
106 EXPECT_EQ(path.GetBounds(), DlRect());
107}
108
109TEST(DisplayListPath, CopyConstruct) {
110 SkPath sk_path = SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20));
111 DlPath path1(sk_path);
112 DlPath path2 = DlPath(path1);
113
114 EXPECT_EQ(path2, path1);
115 EXPECT_EQ(path2, DlPath(SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20))));
116 EXPECT_EQ(path2.GetSkPath(), SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20)));
117
118 EXPECT_FALSE(path2.IsVolatile());
119
120 EXPECT_EQ(path2.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
121 EXPECT_TRUE(path2.IsConvex());
122 EXPECT_EQ(path2.GetFillType(), DlPathFillType::kNonZero);
123
124 bool is_closed = false;
125 EXPECT_FALSE(path2.IsRect(nullptr));
126 EXPECT_FALSE(path2.IsRect(nullptr, &is_closed));
127 EXPECT_FALSE(is_closed);
128 EXPECT_TRUE(path2.IsOval(nullptr));
129 EXPECT_FALSE(path2.IsRoundRect(nullptr));
130
131 is_closed = false;
132 EXPECT_FALSE(path2.IsRect(nullptr));
133 EXPECT_FALSE(path2.IsRect(nullptr, &is_closed));
134 EXPECT_FALSE(is_closed);
135 EXPECT_TRUE(path2.IsOval(nullptr));
136 EXPECT_FALSE(path2.IsRoundRect(nullptr));
137
138 EXPECT_EQ(path2.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
139}
140
141TEST(DisplayListPath, ConstructFromVolatile) {
142 SkPath sk_path;
143 sk_path.setIsVolatile(true);
144 DlPath path(sk_path);
145
146 EXPECT_EQ(path, DlPath());
147 EXPECT_EQ(path.GetSkPath(), SkPath());
148
149 EXPECT_TRUE(path.IsEmpty());
150 EXPECT_TRUE(path.IsVolatile());
151
152 bool is_closed = false;
153 EXPECT_FALSE(path.IsRect(nullptr));
154 EXPECT_FALSE(path.IsRect(nullptr, &is_closed));
155 EXPECT_FALSE(is_closed);
156 EXPECT_FALSE(path.IsOval(nullptr));
157 EXPECT_FALSE(path.IsRoundRect(nullptr));
158
159 is_closed = false;
160 EXPECT_FALSE(path.IsRect(nullptr));
161 EXPECT_FALSE(path.IsRect(nullptr, &is_closed));
162 EXPECT_FALSE(is_closed);
163 EXPECT_FALSE(path.IsOval(nullptr));
164 EXPECT_FALSE(path.IsRoundRect(nullptr));
165
166 EXPECT_EQ(path.GetBounds(), DlRect());
167}
168
169TEST(DisplayListPath, VolatileBecomesNonVolatile) {
170 SkPath sk_path;
171 sk_path.setIsVolatile(true);
172 DlPath path(sk_path);
173
174 EXPECT_TRUE(path.IsVolatile());
175
176 for (int i = 0; i < 1000; i++) {
177 // not specifying intent to render does not make it non-volatile
178 path.GetSkPath();
179 }
180 EXPECT_TRUE(path.IsVolatile());
181
182 for (uint32_t i = 0; i < DlPath::kMaxVolatileUses; i++) {
183 // Expressing intent to render will only be volatile the first few times
184 path.WillRenderSkPath();
185 path.GetSkPath();
186 EXPECT_TRUE(path.IsVolatile());
187 }
188
189 for (int i = 0; i < 1000; i++) {
190 // further uses without expressing intent to render do not make it
191 // non-volatile
192 path.GetSkPath();
193 }
194 EXPECT_TRUE(path.IsVolatile());
195
196 // One last time makes the path non-volatile
197 path.WillRenderSkPath();
198 path.GetSkPath();
199 EXPECT_FALSE(path.IsVolatile());
200}
201
202TEST(DisplayListPath, MultipleVolatileCopiesBecomeNonVolatileTogether) {
203 SkPath sk_path;
204 sk_path.setIsVolatile(true);
205 DlPath path(sk_path);
206 const DlPath paths[4] = {
207 path,
208 path,
209 path,
210 path,
211 };
212
213 EXPECT_TRUE(path.IsVolatile());
214
215 for (uint32_t i = 0; i < DlPath::kMaxVolatileUses; i++) {
216 // Expressing intent to render will only be volatile the first few times
217 paths[i].WillRenderSkPath();
218 EXPECT_TRUE(path.IsVolatile());
219 for (const auto& p : paths) {
220 EXPECT_TRUE(p.IsVolatile());
221 }
222 }
223
224 // One last time makes the path non-volatile
225 paths[3].WillRenderSkPath();
226 EXPECT_FALSE(path.IsVolatile());
227 for (const auto& p : paths) {
228 EXPECT_FALSE(p.IsVolatile());
229 }
230}
231
232TEST(DisplayListPath, ConstructFromRect) {
233 SkPath sk_path = SkPath::Rect(SkRect::MakeLTRB(10, 10, 20, 20));
234 DlPath path(sk_path);
235
236 EXPECT_EQ(path, DlPath(SkPath::Rect(SkRect::MakeLTRB(10, 10, 20, 20))));
237 EXPECT_EQ(path.GetSkPath(), SkPath::Rect(SkRect::MakeLTRB(10, 10, 20, 20)));
238
239 EXPECT_FALSE(path.IsEmpty());
240
241 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
242 EXPECT_TRUE(path.IsConvex());
243 EXPECT_EQ(path.GetFillType(), DlPathFillType::kNonZero);
244
245 bool is_closed = false;
246 EXPECT_TRUE(path.IsRect(nullptr));
247 DlRect dl_rect;
248 EXPECT_TRUE(path.IsRect(&dl_rect, &is_closed));
249 EXPECT_EQ(dl_rect, DlRect::MakeLTRB(10, 10, 20, 20));
250 EXPECT_TRUE(is_closed);
251 EXPECT_FALSE(path.IsOval(nullptr));
252 EXPECT_FALSE(path.IsRoundRect(nullptr));
253
254 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
255}
256
257TEST(DisplayListPath, ConstructFromDlPathBuilderRect) {
258 DlPathBuilder builder;
259 builder.AddRect(DlRect::MakeLTRB(10, 10, 20, 20));
260 DlPath path = builder.TakePath();
261
262 {
263 DlPathBuilder builder2;
264 builder2.AddRect(DlRect::MakeLTRB(10, 10, 20, 20));
265 EXPECT_EQ(path, builder2.TakePath());
266 }
267
268 EXPECT_FALSE(path.GetSkPath().isEmpty());
269 EXPECT_FALSE(path.IsEmpty());
270
271 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
272 EXPECT_TRUE(path.IsConvex());
273 EXPECT_EQ(path.GetFillType(), DlPathFillType::kNonZero);
274
275 bool is_closed = false;
276 EXPECT_TRUE(path.IsRect(nullptr));
277 DlRect dl_rect;
278 EXPECT_TRUE(path.IsRect(&dl_rect, &is_closed));
279 EXPECT_EQ(dl_rect, DlRect::MakeLTRB(10, 10, 20, 20));
280 EXPECT_TRUE(is_closed);
281 EXPECT_FALSE(path.IsOval(nullptr));
282 EXPECT_FALSE(path.IsRoundRect(nullptr));
283
284 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
285}
286
287TEST(DisplayListPath, ConstructFromOval) {
288 SkPath sk_path = SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20));
289 DlPath path(sk_path);
290
291 EXPECT_EQ(path, DlPath(SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20))));
292 EXPECT_EQ(path.GetSkPath(), SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20)));
293
294 EXPECT_FALSE(path.IsEmpty());
295
296 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
297 EXPECT_TRUE(path.IsConvex());
298 EXPECT_EQ(path.GetFillType(), DlPathFillType::kNonZero);
299
300 EXPECT_FALSE(path.IsRect(nullptr));
301 EXPECT_TRUE(path.IsOval(nullptr));
302 DlRect dl_bounds;
303 EXPECT_TRUE(path.IsOval(&dl_bounds));
304 EXPECT_EQ(dl_bounds, DlRect::MakeLTRB(10, 10, 20, 20));
305 EXPECT_FALSE(path.IsRoundRect(nullptr));
306
307 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
308}
309
310TEST(DisplayListPath, ConstructFromDlPathBuilderOval) {
311 DlPathBuilder builder;
312 builder.AddOval(DlRect::MakeLTRB(10, 10, 20, 20));
313 DlPath path = builder.TakePath();
314
315 {
316 DlPathBuilder builder2;
317 builder2.AddOval(DlRect::MakeLTRB(10, 10, 20, 20));
318 EXPECT_EQ(path, builder2.TakePath());
319 }
320
321 EXPECT_FALSE(path.GetSkPath().isEmpty());
322 EXPECT_FALSE(path.IsEmpty());
323
324 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
325 EXPECT_TRUE(path.IsConvex());
326 EXPECT_EQ(path.GetFillType(), DlPathFillType::kNonZero);
327
328 EXPECT_FALSE(path.IsRect(nullptr));
329 EXPECT_TRUE(path.IsOval(nullptr));
330 DlRect dl_bounds;
331 EXPECT_TRUE(path.IsOval(&dl_bounds));
332 EXPECT_EQ(dl_bounds, DlRect::MakeLTRB(10, 10, 20, 20));
333 EXPECT_FALSE(path.IsRoundRect(nullptr));
334
335 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
336}
337
338TEST(DisplayListPath, ConstructFromRRect) {
339 SkPath sk_path = SkPath::RRect(SkRect::MakeLTRB(10, 10, 20, 20), 1, 2);
340 DlPath path(sk_path);
341
342 EXPECT_EQ(path,
343 DlPath(SkPath::RRect(SkRect::MakeLTRB(10, 10, 20, 20), 1, 2)));
344 EXPECT_EQ(path.GetSkPath(),
345 SkPath::RRect(SkRect::MakeLTRB(10, 10, 20, 20), 1, 2));
346
347 EXPECT_FALSE(path.GetSkPath().isEmpty());
348 EXPECT_FALSE(path.IsEmpty());
349
350 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
351 EXPECT_TRUE(path.IsConvex());
352 EXPECT_EQ(path.GetFillType(), DlPathFillType::kNonZero);
353
354 EXPECT_FALSE(path.IsRect(nullptr));
355 EXPECT_FALSE(path.IsOval(nullptr));
356 DlRoundRect roundrect;
357 EXPECT_TRUE(path.IsRoundRect(&roundrect));
358 EXPECT_EQ(roundrect,
359 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(10, 10, 20, 20), 1, 2));
360
361 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
362}
363
364TEST(DisplayListPath, ConstructFromDlPathBuilderRoundRect) {
365 DlPathBuilder builder;
366 builder.AddRoundRect(
367 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(10, 10, 20, 20), 1, 2));
368 DlPath path = builder.TakePath();
369
370 {
371 DlPathBuilder builder2;
372 builder2.AddRoundRect(
373 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(10, 10, 20, 20), 1, 2));
374 EXPECT_EQ(path, builder2.TakePath());
375 }
376
377 EXPECT_FALSE(path.GetSkPath().isEmpty());
378 EXPECT_FALSE(path.IsEmpty());
379
380 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
381 EXPECT_TRUE(path.IsConvex());
382 EXPECT_EQ(path.GetFillType(), DlPathFillType::kNonZero);
383
384 EXPECT_FALSE(path.IsRect(nullptr));
385 EXPECT_FALSE(path.IsOval(nullptr));
386 DlRoundRect roundrect;
387 EXPECT_TRUE(path.IsRoundRect(&roundrect));
388 EXPECT_EQ(roundrect,
389 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(10, 10, 20, 20), 1, 2));
390
391 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
392}
393
394TEST(DisplayListPath, ConstructFromPath) {
395 SkPath sk_path1;
396 sk_path1.moveTo(10, 10);
397 sk_path1.lineTo(20, 20);
398 sk_path1.lineTo(20, 10);
399 SkPath sk_path2;
400 sk_path2.moveTo(10, 10);
401 sk_path2.lineTo(20, 20);
402 sk_path2.lineTo(20, 10);
403 DlPath path(sk_path1);
404
405 ASSERT_EQ(sk_path1, sk_path2);
406
407 EXPECT_EQ(path, DlPath(sk_path2));
408 EXPECT_EQ(path.GetSkPath(), sk_path2);
409
410 EXPECT_FALSE(path.IsEmpty());
411
412 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
413 EXPECT_TRUE(path.IsConvex());
414 EXPECT_EQ(path.GetFillType(), DlPathFillType::kNonZero);
415
416 EXPECT_FALSE(path.IsRect(nullptr));
417 EXPECT_FALSE(path.IsOval(nullptr));
418 EXPECT_FALSE(path.IsRoundRect(nullptr));
419
420 EXPECT_EQ(path.GetBounds(), DlRect::MakeLTRB(10, 10, 20, 20));
421}
422
423TEST(DisplayListPath, ConstructFromDlPathBuilderEqualsConstructFromSkia) {
424 DlPathBuilder path_builder;
425 path_builder.SetFillType(DlPathFillType::kNonZero);
426 path_builder.MoveTo({0, 0});
427 path_builder.LineTo({100, 0});
428 path_builder.LineTo({0, 100});
429 path_builder.Close();
430
431 SkPath sk_path;
432 sk_path.setFillType(SkPathFillType::kWinding);
433 sk_path.moveTo(0, 0);
434 sk_path.lineTo(100, 0);
435 sk_path.lineTo(0, 100);
436 sk_path.close();
437
438 EXPECT_EQ(path_builder.TakePath(), DlPath(sk_path));
439}
440
441TEST(DisplayListPath, IsLineFromSkPath) {
442 SkPath sk_path;
443 sk_path.moveTo(SkPoint::Make(0, 0));
444 sk_path.lineTo(SkPoint::Make(100, 100));
445
446 DlPath path = DlPath(sk_path);
447
449 DlPoint end;
450 EXPECT_TRUE(path.IsLine(&start, &end));
451 EXPECT_EQ(start, DlPoint::MakeXY(0, 0));
452 EXPECT_EQ(end, DlPoint::MakeXY(100, 100));
453
454 EXPECT_FALSE(DlPath(SkPath::Rect(SkRect::MakeLTRB(0, 0, 100, 100))).IsLine());
455}
456
457TEST(DisplayListPath, IsLineFromPathBuilder) {
458 DlPathBuilder path_builder;
459 path_builder.SetFillType(DlPathFillType::kNonZero);
460 path_builder.MoveTo({0, 0});
461 path_builder.LineTo({100, 0});
462 DlPath path = path_builder.TakePath();
463
465 DlPoint end;
466 EXPECT_TRUE(path.IsLine(&start, &end));
467 EXPECT_EQ(start, DlPoint::MakeXY(0, 0));
468 EXPECT_EQ(end, DlPoint::MakeXY(100, 0));
469
470 {
471 DlPathBuilder path_builder;
472 path_builder.SetFillType(DlPathFillType::kNonZero);
473 path_builder.MoveTo({0, 0});
474 path_builder.LineTo({100, 0});
475 path_builder.LineTo({100, 100});
476
477 DlPath path = path_builder.TakePath();
478 EXPECT_FALSE(path.IsLine());
479 }
480}
481
482namespace {
483using ::testing::AtMost;
484using ::testing::Return;
485} // namespace
486
488 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
489
490 {
491 ::testing::InSequence sequence;
492
493 EXPECT_CALL(mock_receiver, MoveTo(DlPoint(100, 200), true));
494 EXPECT_CALL(mock_receiver, LineTo(DlPoint(101, 201)));
495 EXPECT_CALL(mock_receiver, QuadTo(DlPoint(110, 202), DlPoint(102, 210)));
496 EXPECT_CALL(mock_receiver,
497 ConicTo(DlPoint(150, 240), DlPoint(250, 140), 0.5f))
498 .WillOnce(Return(true));
499 EXPECT_CALL(mock_receiver, CubicTo(DlPoint(300, 300), DlPoint(350, 300),
500 DlPoint(300, 350)));
501 // Closing LineTo added implicitly to return to first point
502 EXPECT_CALL(mock_receiver, LineTo(DlPoint(100, 200)));
503 EXPECT_CALL(mock_receiver, Close());
504 }
505
506 path.Dispatch(mock_receiver);
507}
508
509TEST(DisplayListPath, DispatchSkiaPathOneOfEachVerb) {
510 SkPath path;
511
512 path.moveTo(100, 200);
513 path.lineTo(101, 201);
514 path.quadTo(110, 202, 102, 210);
515 path.conicTo(150, 240, 250, 140, 0.5);
516 path.cubicTo(300, 300, 350, 300, 300, 350);
517 path.close();
518
520}
521
522TEST(DisplayListPath, DispatchImpellerPathOneOfEachVerb) {
523 DlPathBuilder path_builder;
524
525 path_builder.MoveTo(DlPoint(100, 200));
526 path_builder.LineTo(DlPoint(101, 201));
527 path_builder.QuadraticCurveTo(DlPoint(110, 202), DlPoint(102, 210));
528 path_builder.ConicCurveTo(DlPoint(150, 240), DlPoint(250, 140), 0.5);
529 path_builder.CubicCurveTo(DlPoint(300, 300), DlPoint(350, 300),
530 DlPoint(300, 350));
531 path_builder.Close();
532
534}
535
537 const DlPath& path,
538 DlScalar weight,
539 const std::array<DlPoint, 4>& quad_points) {
540 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
541
542 {
543 ::testing::InSequence sequence;
544
545 EXPECT_CALL(mock_receiver, MoveTo(DlPoint(10, 10), false));
546 EXPECT_CALL(mock_receiver,
547 ConicTo(DlPoint(20, 10), DlPoint(20, 20), weight))
548 .WillOnce(Return(false));
549 EXPECT_CALL(mock_receiver,
550 QuadTo(PointEq(quad_points[0]), PointEq(quad_points[1])));
551 EXPECT_CALL(mock_receiver,
552 QuadTo(PointEq(quad_points[2]), PointEq(quad_points[3])));
553 }
554
555 path.Dispatch(mock_receiver);
556}
557
559 DlScalar weight,
560 const std::array<DlPoint, 4>& quad_points) {
561 SkPath sk_path;
562 sk_path.moveTo(10, 10);
563 sk_path.conicTo(20, 10, 20, 20, weight);
564
565 TestPathDispatchConicToQuads(DlPath(sk_path), weight, quad_points);
566}
567
569 DlScalar weight,
570 const std::array<DlPoint, 4>& quad_points) {
571 DlPathBuilder path_builder;
572 path_builder.MoveTo(DlPoint(10, 10));
573 path_builder.ConicCurveTo(DlPoint(20, 10), DlPoint(20, 20), weight);
574
575 TestPathDispatchConicToQuads(path_builder.TakePath(), weight, quad_points);
576}
577
578TEST(DisplayListPath, DispatchSkiaPathConicToQuadsNearlyZero) {
580 {
581 DlPoint(10.01f, 10.0f),
582 DlPoint(15.005f, 14.995f),
583 DlPoint(20.0f, 19.99f),
584 DlPoint(20.0f, 20.0f),
585 });
586}
587TEST(DisplayListPath, DispatchSkiaPathConicToQuadsHalf) {
589 DlPoint(13.3333f, 10.0f),
590 DlPoint(16.6667f, 13.3333f),
591 DlPoint(20.0f, 16.6667f),
592 DlPoint(20.0f, 20.0f),
593 });
594}
595TEST(DisplayListPath, DispatchSkiaPathConicToQuadsCircular) {
597 {
598 DlPoint(14.1421f, 10.0f),
599 DlPoint(17.0711f, 12.9289f),
600 DlPoint(20.0f, 15.8579f),
601 DlPoint(20.0f, 20.0f),
602 });
603}
604TEST(DisplayListPath, DispatchSkiaPathConicToQuadsNearlyOne) {
606 {
607 DlPoint(14.9975f, 10.0f),
608 DlPoint(17.4987f, 12.5013f),
609 DlPoint(20.0f, 15.0025f),
610 DlPoint(20.0f, 20.0f),
611 });
612}
613
614TEST(DisplayListPath, DispatchImpellerPathConicToQuadsNearlyZero) {
616 {
617 DlPoint(10.01f, 10.0f),
618 DlPoint(15.005f, 14.995f),
619 DlPoint(20.0f, 19.99f),
620 DlPoint(20.0f, 20.0f),
621 });
622}
623TEST(DisplayListPath, DispatchImpellerPathConicToQuadsHalf) {
625 DlPoint(13.3333f, 10.0f),
626 DlPoint(16.6667f, 13.3333f),
627 DlPoint(20.0f, 16.6667f),
628 DlPoint(20.0f, 20.0f),
629 });
630}
631TEST(DisplayListPath, DispatchImpellerPathConicToQuadsCircular) {
633 {
634 DlPoint(14.1421f, 10.0f),
635 DlPoint(17.0711f, 12.9289f),
636 DlPoint(20.0f, 15.8579f),
637 DlPoint(20.0f, 20.0f),
638 });
639}
640TEST(DisplayListPath, DispatchImpellerPathConicToQuadsNearlyOne) {
642 {
643 DlPoint(14.9975f, 10.0f),
644 DlPoint(17.4987f, 12.5013f),
645 DlPoint(20.0f, 15.0025f),
646 DlPoint(20.0f, 20.0f),
647 });
648}
649
651 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
652
653 {
654 ::testing::InSequence sequence;
655
656 EXPECT_CALL(mock_receiver, MoveTo(DlPoint(10, 10), false));
657 EXPECT_CALL(mock_receiver, LineTo(DlPoint(20, 10)));
658 EXPECT_CALL(mock_receiver, LineTo(DlPoint(10, 20)));
659 }
660
661 path.Dispatch(mock_receiver);
662}
663
664TEST(DisplayListPath, DispatchUnclosedSkiaTriangle) {
665 SkPath sk_path;
666 sk_path.moveTo(10, 10);
667 sk_path.lineTo(20, 10);
668 sk_path.lineTo(10, 20);
669
671}
672
673TEST(DisplayListPath, DispatchUnclosedImpellerTriangle) {
674 DlPathBuilder path_builder;
675 path_builder.MoveTo({10, 10});
676 path_builder.LineTo({20, 10});
677 path_builder.LineTo({10, 20});
678
680}
681
683 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
684
685 {
686 ::testing::InSequence sequence;
687
688 EXPECT_CALL(mock_receiver, MoveTo(DlPoint(10, 10), true));
689 EXPECT_CALL(mock_receiver, LineTo(DlPoint(20, 10)));
690 EXPECT_CALL(mock_receiver, LineTo(DlPoint(10, 20)));
691 EXPECT_CALL(mock_receiver, LineTo(DlPoint(10, 10)));
692 EXPECT_CALL(mock_receiver, Close());
693 }
694
695 path.Dispatch(mock_receiver);
696}
697
698TEST(DisplayListPath, DispatchClosedSkiaTriangle) {
699 SkPath sk_path;
700 sk_path.moveTo(10, 10);
701 sk_path.lineTo(20, 10);
702 sk_path.lineTo(10, 20);
703 sk_path.close();
704
706}
707
708TEST(DisplayListPath, DispatchClosedPathBuilderTriangle) {
709 DlPathBuilder path_builder;
710 path_builder.MoveTo({10, 10});
711 path_builder.LineTo({20, 10});
712 path_builder.LineTo({10, 20});
713 path_builder.Close();
714
716}
717
719 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
720
721 {
722 ::testing::InSequence sequence;
723
724 EXPECT_CALL(mock_receiver, MoveTo(DlPoint(10, 10), false));
725 EXPECT_CALL(mock_receiver, LineTo(DlPoint(20, 10)));
726 EXPECT_CALL(mock_receiver, LineTo(DlPoint(10, 20)));
727 EXPECT_CALL(mock_receiver, MoveTo(DlPoint(110, 10), true));
728 EXPECT_CALL(mock_receiver, LineTo(DlPoint(120, 10)));
729 EXPECT_CALL(mock_receiver, LineTo(DlPoint(110, 20)));
730 EXPECT_CALL(mock_receiver, LineTo(DlPoint(110, 10)));
731 EXPECT_CALL(mock_receiver, Close());
732 EXPECT_CALL(mock_receiver, MoveTo(DlPoint(210, 10), false));
733 EXPECT_CALL(mock_receiver, LineTo(DlPoint(220, 10)));
734 EXPECT_CALL(mock_receiver, LineTo(DlPoint(210, 20)));
735 }
736
737 path.Dispatch(mock_receiver);
738}
739
740TEST(DisplayListPath, DispatchMixedCloseSkiaPath) {
741 SkPath sk_path;
742 sk_path.moveTo(10, 10);
743 sk_path.lineTo(20, 10);
744 sk_path.lineTo(10, 20);
745 sk_path.moveTo(110, 10);
746 sk_path.lineTo(120, 10);
747 sk_path.lineTo(110, 20);
748 sk_path.close();
749 sk_path.moveTo(210, 10);
750 sk_path.lineTo(220, 10);
751 sk_path.lineTo(210, 20);
752
754}
755
756TEST(DisplayListPath, DispatchMixedCloseImpellerPath) {
757 DlPathBuilder path_builder;
758 path_builder.MoveTo({10, 10});
759 path_builder.LineTo({20, 10});
760 path_builder.LineTo({10, 20});
761 path_builder.MoveTo({110, 10});
762 path_builder.LineTo({120, 10});
763 path_builder.LineTo({110, 20});
764 path_builder.Close();
765 path_builder.MoveTo({210, 10});
766 path_builder.LineTo({220, 10});
767 path_builder.LineTo({210, 20});
768
770}
771
773 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
774
775 {
776 ::testing::InSequence sequence;
777
778 EXPECT_CALL(mock_receiver, MoveTo(DlPoint(10, 10), true));
779 EXPECT_CALL(mock_receiver, LineTo(DlPoint(20, 10)));
780 EXPECT_CALL(mock_receiver, LineTo(DlPoint(10, 20)));
781 EXPECT_CALL(mock_receiver, LineTo(DlPoint(10, 10)));
782 EXPECT_CALL(mock_receiver, Close());
783 EXPECT_CALL(mock_receiver, MoveTo(DlPoint(10, 10), false));
784 EXPECT_CALL(mock_receiver, LineTo(DlPoint(-20, 10)));
785 EXPECT_CALL(mock_receiver, LineTo(DlPoint(10, -20)));
786 }
787
788 path.Dispatch(mock_receiver);
789}
790
791TEST(DisplayListPath, DispatchImplicitMoveAfterCloseSkiaPath) {
792 SkPath sk_path;
793 sk_path.moveTo(10, 10);
794 sk_path.lineTo(20, 10);
795 sk_path.lineTo(10, 20);
796 sk_path.close();
797 sk_path.lineTo(-20, 10);
798 sk_path.lineTo(10, -20);
799
801}
802
803TEST(DisplayListPath, DispatchImplicitMoveAfterClosePathBuilder) {
804 DlPathBuilder path_builder;
805 path_builder.MoveTo({10, 10});
806 path_builder.LineTo({20, 10});
807 path_builder.LineTo({10, 20});
808 path_builder.Close();
809 path_builder.LineTo({-20, 10});
810 path_builder.LineTo({10, -20});
811
813}
814
815#ifndef NDEBUG
816// Tests that verify we don't try to use inverse path modes as they aren't
817// supported by either Flutter public APIs or Impeller
818
819TEST(DisplayListPath, CannotConstructFromSkiaInverseWinding) {
820 SkPath sk_path;
821 sk_path.setFillType(SkPathFillType::kInverseWinding);
822 sk_path.moveTo(0, 0);
823 sk_path.lineTo(100, 0);
824 sk_path.lineTo(0, 100);
825 sk_path.close();
826
827 EXPECT_DEATH_IF_SUPPORTED(new DlPath(sk_path), "SkPathFillType_IsInverse");
828}
829
830TEST(DisplayListPath, CannotConstructFromSkiaInverseEvenOdd) {
831 SkPath sk_path;
832 sk_path.setFillType(SkPathFillType::kInverseEvenOdd);
833 sk_path.moveTo(0, 0);
834 sk_path.lineTo(100, 0);
835 sk_path.lineTo(0, 100);
836 sk_path.close();
837
838 EXPECT_DEATH_IF_SUPPORTED(new DlPath(sk_path), "SkPathFillType_IsInverse");
839}
840#endif
841
842} // namespace testing
843} // namespace flutter
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.
DlPathBuilder & SetFillType(DlPathFillType fill_type)
Set the fill type that should be used to determine the interior of this path to the indicated |fill_t...
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 & AddRoundRect(const DlRoundRect &round_rect)
Append a closed rounded rect 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 & Close()
The path is closed back to the location of the most recent MoveTo call. Contours that are filled are ...
DlPathBuilder & AddOval(const DlRect &bounds)
Append a closed elliptical contour to the path inscribed in the provided bounds.
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...
bool IsRect(DlRect *rect=nullptr, bool *is_closed=nullptr) const
Definition dl_path.cc:210
static constexpr uint32_t kMaxVolatileUses
Definition dl_path.h:21
bool IsRoundRect(DlRoundRect *rrect=nullptr) const
Definition dl_path.cc:228
DlRect GetBounds() const override
Definition dl_path.cc:245
const SkPath & GetSkPath() const
Definition dl_path.cc:116
DlPathFillType GetFillType() const override
Definition dl_path.cc:241
void WillRenderSkPath() const
Definition dl_path.cc:174
bool IsVolatile() const
Definition dl_path.cc:253
bool IsConvex() const override
Definition dl_path.cc:257
bool IsOval(DlRect *bounds=nullptr) const
Definition dl_path.cc:214
static void TestSkiaPathDispatchConicToQuads(DlScalar weight, const std::array< DlPoint, 4 > &quad_points)
static void TestPathDispatchConicToQuads(const DlPath &path, DlScalar weight, const std::array< DlPoint, 4 > &quad_points)
static void TestPathDispatchImplicitMoveAfterClose(const DlPath &path)
static void TestImpellerPathDispatchConicToQuads(DlScalar weight, const std::array< DlPoint, 4 > &quad_points)
static void TestPathDispatchUnclosedTriangle(const DlPath &path)
TEST(NativeAssetsManagerTest, NoAvailableAssets)
static void TestPathDispatchClosedTriangle(const DlPath &path)
static void TestPathDispatchMixedCloseTriangles(const DlPath &path)
static void TestPathDispatchOneOfEachVerb(const DlPath &path)
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
static constexpr DlScalar kEhCloseEnough
impeller::Point DlPoint
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 RoundRect MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
Definition round_rect.h:31
static constexpr TPoint< Type > MakeXY(Type x, Type y)
Definition point.h:46
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129
const size_t start
const size_t end