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