| Flutter Impeller |

path_tessellator_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
5 #include "flutter/testing/testing.h"
6 #include "gmock/gmock.h"
7 #include "gtest/gtest.h"
8
9 #include "flutter/impeller/tessellator/path_tessellator.h"
10
11 #include "flutter/display_list/geometry/dl_path.h"
12 #include "flutter/display_list/geometry/dl_path_builder.h"
13
14 namespace impeller {
15 namespace testing {
16
17 class MockPathVertexWriter : public impeller::PathTessellator::VertexWriter {
18 public:
19 MOCK_METHOD(void, Write, (Point point), (override));
20 MOCK_METHOD(void, EndContour, (), (override));
21 };
22
23 class MockSegmentReceiver : public impeller::PathTessellator::SegmentReceiver {
24 public:
25 MOCK_METHOD(void,
26 BeginContour,
27 (Point origin, bool will_be_closed),
28 (override));
29 MOCK_METHOD(void, RecordLine, (Point p1, Point p2), (override));
30 MOCK_METHOD(void, RecordQuad, (Point p1, Point cp, Point p2), (override));
31 MOCK_METHOD(void,
32 RecordConic,
33 (Point p1, Point cp, Point p2, Scalar weight),
34 (override));
35 MOCK_METHOD(void,
36 RecordCubic,
37 (Point p1, Point cp1, Point cp2, Point p2),
38 (override));
39 MOCK_METHOD(void, EndContour, (Point origin, bool with_close), (override));
40 };
41
42 TEST(PathTessellatorTest, EmptyPath) {
43 flutter::DlPathBuilder builder;
44 builder.MoveTo({0, 0});
45 flutter::DlPath path = builder.TakePath();
46
47 ::testing::StrictMock<MockSegmentReceiver> mock_receiver;
48 PathTessellator::PathToFilledSegments(path, mock_receiver);
49
50 auto [points, contours] = PathTessellator::CountFillStorage(path, 1.0f);
51 EXPECT_EQ(points, 0u);
52 EXPECT_EQ(contours, 0u);
53
54 ::testing::StrictMock<MockPathVertexWriter> mock_writer;
55 PathTessellator::PathToFilledVertices(path, mock_writer, 1.0f);
56 }
57
58 TEST(PathTessellatorTest, EmptyPathMultipleMoveTo) {
59 flutter::DlPathBuilder builder;
60 builder.MoveTo({0, 0});
61 builder.MoveTo({10, 10});
62 builder.MoveTo({20, 20});
63 flutter::DlPath path = builder.TakePath();
64
65 ::testing::StrictMock<MockSegmentReceiver> mock_receiver;
66 PathTessellator::PathToFilledSegments(path, mock_receiver);
67
68 auto [points, contours] = PathTessellator::CountFillStorage(path, 1.0f);
69 EXPECT_EQ(points, 0u);
70 EXPECT_EQ(contours, 0u);
71
72 ::testing::StrictMock<MockPathVertexWriter> mock_writer;
73 PathTessellator::PathToFilledVertices(path, mock_writer, 1.0f);
74 }
75
76 TEST(PathTessellatorTest, SimpleClosedPath) {
77 flutter::DlPathBuilder builder;
78 builder.MoveTo({0, 0});
79 builder.LineTo({10, 10});
80 builder.LineTo({0, 20});
81 builder.Close();
82 flutter::DlPath path = builder.TakePath();
83
84 ::testing::StrictMock<MockSegmentReceiver> mock_receiver;
85 {
86 ::testing::InSequence sequence;
87
88 EXPECT_CALL(mock_receiver,
89 BeginContour(Point(0, 0), /*will_be_closed=*/true));
90 EXPECT_CALL(mock_receiver, RecordLine(Point(0, 0), Point(10, 10)));
91 EXPECT_CALL(mock_receiver, RecordLine(Point(10, 10), Point(0, 20)));
92 EXPECT_CALL(mock_receiver, RecordLine(Point(0, 20), Point(0, 0)));
93 EXPECT_CALL(mock_receiver, EndContour(Point(0, 0), /*with_close=*/true));
94 }
95 PathTessellator::PathToFilledSegments(path, mock_receiver);
96
97 auto [points, contours] = PathTessellator::CountFillStorage(path, 1.0f);
98 EXPECT_EQ(points, 4u);
99 EXPECT_EQ(contours, 1u);
100
101 ::testing::StrictMock<MockPathVertexWriter> mock_writer;
102 {
103 ::testing::InSequence sequence;
104
105 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
106 EXPECT_CALL(mock_writer, Write(Point(10, 10)));
107 EXPECT_CALL(mock_writer, Write(Point(0, 20)));
108 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
109 EXPECT_CALL(mock_writer, EndContour());
110 }
111 PathTessellator::PathToFilledVertices(path, mock_writer, 1.0f);
112 }
113
114 TEST(PathTessellatorTest, SimpleUnclosedPath) {
115 flutter::DlPathBuilder builder;
116 builder.MoveTo({0, 0});
117 builder.LineTo({10, 10});
118 builder.LineTo({0, 20});
119 // Close not really needed for filled paths
120 flutter::DlPath path = builder.TakePath();
121
122 ::testing::StrictMock<MockSegmentReceiver> mock_receiver;
123 {
124 ::testing::InSequence sequence;
125
126 EXPECT_CALL(mock_receiver,
127 BeginContour(Point(0, 0), /*will_be_closed=*/false));
128 EXPECT_CALL(mock_receiver, RecordLine(Point(0, 0), Point(10, 10)));
129 EXPECT_CALL(mock_receiver, RecordLine(Point(10, 10), Point(0, 20)));
130 EXPECT_CALL(mock_receiver, RecordLine(Point(0, 20), Point(0, 0)));
131 EXPECT_CALL(mock_receiver, EndContour(Point(0, 0), /*with_close=*/false));
132 }
133 PathTessellator::PathToFilledSegments(path, mock_receiver);
134
135 auto [points, contours] = PathTessellator::CountFillStorage(path, 1.0f);
136 EXPECT_EQ(points, 4u);
137 EXPECT_EQ(contours, 1u);
138
139 ::testing::StrictMock<MockPathVertexWriter> mock_writer;
140 {
141 ::testing::InSequence sequence;
142
143 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
144 EXPECT_CALL(mock_writer, Write(Point(10, 10)));
145 EXPECT_CALL(mock_writer, Write(Point(0, 20)));
146 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
147 EXPECT_CALL(mock_writer, EndContour());
148 }
149 PathTessellator::PathToFilledVertices(path, mock_writer, 1.0f);
150 }
151
152 TEST(PathTessellatorTest, SimplePathTrailingMoveTo) {
153 flutter::DlPathBuilder builder;
154 builder.MoveTo({0, 0});
155 builder.LineTo({10, 10});
156 builder.LineTo({0, 20});
157 builder.Close();
158 builder.MoveTo({500, 100});
159 flutter::DlPath path = builder.TakePath();
160
161 ::testing::StrictMock<MockSegmentReceiver> mock_receiver;
162 {
163 ::testing::InSequence sequence;
164
165 EXPECT_CALL(mock_receiver,
166 BeginContour(Point(0, 0), /*will_be_closed=*/true));
167 EXPECT_CALL(mock_receiver, RecordLine(Point(0, 0), Point(10, 10)));
168 EXPECT_CALL(mock_receiver, RecordLine(Point(10, 10), Point(0, 20)));
169 EXPECT_CALL(mock_receiver, RecordLine(Point(0, 20), Point(0, 0)));
170 EXPECT_CALL(mock_receiver, EndContour(Point(0, 0), /*with_close=*/true));
171 }
172 PathTessellator::PathToFilledSegments(path, mock_receiver);
173
174 auto [points, contours] = PathTessellator::CountFillStorage(path, 1.0f);
175 EXPECT_EQ(points, 4u);
176 EXPECT_EQ(contours, 1u);
177
178 ::testing::StrictMock<MockPathVertexWriter> mock_writer;
179 {
180 ::testing::InSequence sequence;
181
182 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
183 EXPECT_CALL(mock_writer, Write(Point(10, 10)));
184 EXPECT_CALL(mock_writer, Write(Point(0, 20)));
185 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
186 EXPECT_CALL(mock_writer, EndContour());
187 }
188 PathTessellator::PathToFilledVertices(path, mock_writer, 1.0f);
189 }
190
191 TEST(PathTessellatorTest, DegenerateSegmentsPath) {
192 flutter::DlPathBuilder builder;
193 builder.MoveTo({0, 0});
194 builder.LineTo({0, 0});
195 builder.LineTo({0, 0});
196 builder.QuadraticCurveTo({0, 0}, {0, 0});
197 builder.QuadraticCurveTo({0, 0}, {0, 0});
198 builder.ConicCurveTo({0, 0}, {0, 0}, 12.0f);
199 builder.ConicCurveTo({0, 0}, {0, 0}, 12.0f);
200 builder.CubicCurveTo({0, 0}, {0, 0}, {0, 0});
201 builder.CubicCurveTo({0, 0}, {0, 0}, {0, 0});
202 builder.Close();
203 flutter::DlPath path = builder.TakePath();
204
205 ::testing::StrictMock<MockSegmentReceiver> mock_receiver;
206 {
207 ::testing::InSequence sequence;
208
209 EXPECT_CALL(mock_receiver,
210 BeginContour(Point(0, 0), /*will_be_closed=*/true));
211 EXPECT_CALL(mock_receiver, EndContour(Point(0, 0), /*with_close=*/true));
212 }
213 PathTessellator::PathToFilledSegments(path, mock_receiver);
214
215 auto [points, contours] = PathTessellator::CountFillStorage(path, 1.0f);
216 EXPECT_EQ(points, 1u);
217 EXPECT_EQ(contours, 1u);
218
219 ::testing::StrictMock<MockPathVertexWriter> mock_writer;
220 {
221 ::testing::InSequence sequence;
222
223 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
224 EXPECT_CALL(mock_writer, EndContour());
225 }
226 PathTessellator::PathToFilledVertices(path, mock_writer, 1.0f);
227 }
228
229 TEST(PathTessellatorTest, QuadToLineToOptimization) {
230 flutter::DlPathBuilder builder;
231 builder.MoveTo({0, 0});
232 // CP == P1
233 builder.QuadraticCurveTo({0, 0}, {10, 10});
234 // CP == P2
235 builder.QuadraticCurveTo({20, 10}, {20, 10});
236 builder.Close();
237 flutter::DlPath path = builder.TakePath();
238
239 ::testing::StrictMock<MockSegmentReceiver> mock_receiver;
240 {
241 ::testing::InSequence sequence;
242
243 EXPECT_CALL(mock_receiver,
244 BeginContour(Point(0, 0), /*will_be_closed=*/true));
245 EXPECT_CALL(mock_receiver, RecordLine(Point(0, 0), Point(10, 10)));
246 EXPECT_CALL(mock_receiver, RecordLine(Point(10, 10), Point(20, 10)));
247 EXPECT_CALL(mock_receiver, RecordLine(Point(20, 10), Point(0, 0)));
248 EXPECT_CALL(mock_receiver, EndContour(Point(0, 0), /*with_close=*/true));
249 }
250 PathTessellator::PathToFilledSegments(path, mock_receiver);
251
252 auto [points, contours] = PathTessellator::CountFillStorage(path, 1.0f);
253 EXPECT_EQ(points, 4u);
254 EXPECT_EQ(contours, 1u);
255
256 ::testing::StrictMock<MockPathVertexWriter> mock_writer;
257 {
258 ::testing::InSequence sequence;
259
260 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
261 EXPECT_CALL(mock_writer, Write(Point(10, 10)));
262 EXPECT_CALL(mock_writer, Write(Point(20, 10)));
263 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
264 EXPECT_CALL(mock_writer, EndContour());
265 }
266 PathTessellator::PathToFilledVertices(path, mock_writer, 1.0f);
267 }
268
269 TEST(PathTessellatorTest, ConicToLineToOptimization) {
270 flutter::DlPathBuilder builder;
271 builder.MoveTo({0, 0});
272 // CP == P1
273 builder.ConicCurveTo({0, 0}, {10, 10}, 2.0f);
274 // CP == P2
275 builder.ConicCurveTo({20, 10}, {20, 10}, 2.0f);
276 // weight == 0
277 builder.ConicCurveTo({20, 0}, {10, 0}, 0.0f);
278 builder.Close();
279 flutter::DlPath path = builder.TakePath();
280
281 ::testing::StrictMock<MockSegmentReceiver> mock_receiver;
282 {
283 ::testing::InSequence sequence;
284
285 EXPECT_CALL(mock_receiver,
286 BeginContour(Point(0, 0), /*will_be_closed=*/true));
287 EXPECT_CALL(mock_receiver, RecordLine(Point(0, 0), Point(10, 10)));
288 EXPECT_CALL(mock_receiver, RecordLine(Point(10, 10), Point(20, 10)));
289 EXPECT_CALL(mock_receiver, RecordLine(Point(20, 10), Point(10, 0)));
290 EXPECT_CALL(mock_receiver, RecordLine(Point(10, 0), Point(0, 0)));
291 EXPECT_CALL(mock_receiver, EndContour(Point(0, 0), /*with_close=*/true));
292 }
293 PathTessellator::PathToFilledSegments(path, mock_receiver);
294
295 auto [points, contours] = PathTessellator::CountFillStorage(path, 1.0f);
296 EXPECT_EQ(points, 5u);
297 EXPECT_EQ(contours, 1u);
298
299 ::testing::StrictMock<MockPathVertexWriter> mock_writer;
300 {
301 ::testing::InSequence sequence;
302
303 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
304 EXPECT_CALL(mock_writer, Write(Point(10, 10)));
305 EXPECT_CALL(mock_writer, Write(Point(20, 10)));
306 EXPECT_CALL(mock_writer, Write(Point(10, 0)));
307 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
308 EXPECT_CALL(mock_writer, EndContour());
309 }
310 PathTessellator::PathToFilledVertices(path, mock_writer, 1.0f);
311 }
312
313 TEST(PathTessellatorTest, ConicToQuadToOptimization) {
314 // The conic below will simplify to this quad
315 PathTessellator::Quad quad{{0, 0}, {10, 0}, {0, 10}};
316
317 flutter::DlPathBuilder builder;
318 builder.MoveTo(quad.p1);
319 // weight == 1
320 builder.ConicCurveTo(quad.cp, quad.p2, 1.0f);
321 builder.Close();
322 flutter::DlPath path = builder.TakePath();
323
324 ::testing::StrictMock<MockSegmentReceiver> mock_receiver;
325 {
326 ::testing::InSequence sequence;
327
328 EXPECT_CALL(mock_receiver, BeginContour(quad.p1, /*will_be_closed=*/true));
329 EXPECT_CALL(mock_receiver, RecordQuad(quad.p1, quad.cp, quad.p2));
330 EXPECT_CALL(mock_receiver, RecordLine(quad.p2, quad.p1));
331 EXPECT_CALL(mock_receiver, EndContour(quad.p1, /*with_close=*/true));
332 }
333 PathTessellator::PathToFilledSegments(path, mock_receiver);
334
335 auto [points, contours] = PathTessellator::CountFillStorage(path, 1.0f);
336 EXPECT_EQ(points, 7u);
337 EXPECT_EQ(contours, 1u);
338
339 ::testing::StrictMock<MockPathVertexWriter> mock_writer;
340 {
341 ::testing::InSequence sequence;
342
343 EXPECT_CALL(mock_writer, Write(quad.p1));
344 {
345 EXPECT_CALL(mock_writer, Write(quad.Solve(1 / 5.0f)));
346 EXPECT_CALL(mock_writer, Write(quad.Solve(2 / 5.0f)));
347 EXPECT_CALL(mock_writer, Write(quad.Solve(3 / 5.0f)));
348 EXPECT_CALL(mock_writer, Write(quad.Solve(4 / 5.0f)));
349 EXPECT_CALL(mock_writer, Write(quad.p2));
350 }
351 EXPECT_CALL(mock_writer, Write(quad.p1));
352 EXPECT_CALL(mock_writer, EndContour());
353 }
354 PathTessellator::PathToFilledVertices(path, mock_writer, 1.0f);
355 }
356
357 TEST(PathTessellatorTest, SimplePathMultipleMoveTo) {
358 flutter::DlPathBuilder builder;
359 builder.MoveTo({500, 100});
360 builder.MoveTo({0, 0});
361 builder.LineTo({10, 10});
362 builder.LineTo({0, 20});
363 builder.Close();
364 flutter::DlPath path = builder.TakePath();
365
366 ::testing::StrictMock<MockSegmentReceiver> mock_receiver;
367 {
368 ::testing::InSequence sequence;
369
370 EXPECT_CALL(mock_receiver,
371 BeginContour(Point(0, 0), /*will_be_closed=*/true));
372 EXPECT_CALL(mock_receiver, RecordLine(Point(0, 0), Point(10, 10)));
373 EXPECT_CALL(mock_receiver, RecordLine(Point(10, 10), Point(0, 20)));
374 EXPECT_CALL(mock_receiver, RecordLine(Point(0, 20), Point(0, 0)));
375 EXPECT_CALL(mock_receiver, EndContour(Point(0, 0), /*with_close=*/true));
376 }
377 PathTessellator::PathToFilledSegments(path, mock_receiver);
378
379 auto [points, contours] = PathTessellator::CountFillStorage(path, 1.0f);
380 EXPECT_EQ(points, 4u);
381 EXPECT_EQ(contours, 1u);
382
383 ::testing::StrictMock<MockPathVertexWriter> mock_writer;
384 {
385 ::testing::InSequence sequence;
386
387 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
388 EXPECT_CALL(mock_writer, Write(Point(10, 10)));
389 EXPECT_CALL(mock_writer, Write(Point(0, 20)));
390 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
391 EXPECT_CALL(mock_writer, EndContour());
392 }
393 PathTessellator::PathToFilledVertices(path, mock_writer, 1.0f);
394 }
395
396 TEST(PathTessellatorTest, ComplexPath) {
397 PathTessellator::Quad quad{{10, 10}, {20, 20}, {20, 10}};
398 PathTessellator::Conic conic{{20, 10}, {30, 20}, {30, 10}, 2.0f};
399 PathTessellator::Cubic cubic{{30, 10}, {40, 20}, {40, 10}, {42, 15}};
400
401 flutter::DlPathBuilder builder;
402 builder.MoveTo({0, 0});
403 builder.LineTo({10, 10});
404 builder.QuadraticCurveTo(quad.cp, quad.p2);
405 builder.ConicCurveTo(conic.cp, conic.p2, conic.weight);
406 builder.CubicCurveTo(cubic.cp1, cubic.cp2, cubic.p2);
407 builder.Close();
408 flutter::DlPath path = builder.TakePath();
409
410 ::testing::StrictMock<MockSegmentReceiver> mock_receiver;
411 {
412 ::testing::InSequence sequence;
413
414 EXPECT_CALL(mock_receiver,
415 BeginContour(Point(0, 0), /*will_be_closed=*/true));
416 EXPECT_CALL(mock_receiver, RecordLine(Point(0, 0), Point(10, 10)));
417 EXPECT_CALL(mock_receiver, RecordQuad(quad.p1, quad.cp, quad.p2));
418 EXPECT_CALL(mock_receiver,
419 RecordConic(conic.p1, conic.cp, conic.p2, conic.weight));
420 EXPECT_CALL(mock_receiver,
421 RecordCubic(cubic.p1, cubic.cp1, cubic.cp2, cubic.p2));
422 EXPECT_CALL(mock_receiver, RecordLine(cubic.p2, Point(0, 0)));
423 EXPECT_CALL(mock_receiver, EndContour(Point(0, 0), /*with_close=*/true));
424 }
425 PathTessellator::PathToFilledSegments(path, mock_receiver);
426
427 auto [points, contours] = PathTessellator::CountFillStorage(path, 1.0f);
428 EXPECT_EQ(points, 25u);
429 EXPECT_EQ(contours, 1u);
430
431 ::testing::StrictMock<MockPathVertexWriter> mock_writer;
432 {
433 ::testing::InSequence sequence;
434
435 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
436 EXPECT_CALL(mock_writer, Write(Point(10, 10)));
437 {
438 EXPECT_CALL(mock_writer, Write(quad.Solve(1 / 5.0f)));
439 EXPECT_CALL(mock_writer, Write(quad.Solve(2 / 5.0f)));
440 EXPECT_CALL(mock_writer, Write(quad.Solve(3 / 5.0f)));
441 EXPECT_CALL(mock_writer, Write(quad.Solve(4 / 5.0f)));
442 EXPECT_CALL(mock_writer, Write(quad.p2));
443 }
444 {
445 EXPECT_CALL(mock_writer, Write(conic.Solve(1 / 8.0f)));
446 EXPECT_CALL(mock_writer, Write(conic.Solve(2 / 8.0f)));
447 EXPECT_CALL(mock_writer, Write(conic.Solve(3 / 8.0f)));
448 EXPECT_CALL(mock_writer, Write(conic.Solve(4 / 8.0f)));
449 EXPECT_CALL(mock_writer, Write(conic.Solve(5 / 8.0f)));
450 EXPECT_CALL(mock_writer, Write(conic.Solve(6 / 8.0f)));
451 EXPECT_CALL(mock_writer, Write(conic.Solve(7 / 8.0f)));
452 EXPECT_CALL(mock_writer, Write(conic.p2));
453 }
454 {
455 EXPECT_CALL(mock_writer, Write(cubic.Solve(1 / 9.0f)));
456 EXPECT_CALL(mock_writer, Write(cubic.Solve(2 / 9.0f)));
457 EXPECT_CALL(mock_writer, Write(cubic.Solve(3 / 9.0f)));
458 EXPECT_CALL(mock_writer, Write(cubic.Solve(4 / 9.0f)));
459 EXPECT_CALL(mock_writer, Write(cubic.Solve(5 / 9.0f)));
460 EXPECT_CALL(mock_writer, Write(cubic.Solve(6 / 9.0f)));
461 EXPECT_CALL(mock_writer, Write(cubic.Solve(7 / 9.0f)));
462 EXPECT_CALL(mock_writer, Write(cubic.Solve(8 / 9.0f)));
463 EXPECT_CALL(mock_writer, Write(cubic.p2));
464 }
465 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
466 EXPECT_CALL(mock_writer, EndContour());
467 }
468 PathTessellator::PathToFilledVertices(path, mock_writer, 1.0f);
469 }
470
471 TEST(PathTessellatorTest, ComplexPathTrailingMoveTo) {
472 PathTessellator::Quad quad{{10, 10}, {20, 20}, {20, 10}};
473 PathTessellator::Conic conic{{20, 10}, {30, 20}, {30, 10}, 2.0f};
474 PathTessellator::Cubic cubic{{30, 10}, {40, 20}, {40, 10}, {42, 15}};
475
476 flutter::DlPathBuilder builder;
477 builder.MoveTo({0, 0});
478 builder.LineTo({10, 10});
479 builder.QuadraticCurveTo(quad.cp, quad.p2);
480 builder.ConicCurveTo(conic.cp, conic.p2, conic.weight);
481 builder.CubicCurveTo(cubic.cp1, cubic.cp2, cubic.p2);
482 builder.Close();
483 builder.MoveTo({500, 100});
484 flutter::DlPath path = builder.TakePath();
485
486 ::testing::StrictMock<MockSegmentReceiver> mock_receiver;
487 {
488 ::testing::InSequence sequence;
489
490 EXPECT_CALL(mock_receiver,
491 BeginContour(Point(0, 0), /*will_be_closed=*/true));
492 EXPECT_CALL(mock_receiver, RecordLine(Point(0, 0), Point(10, 10)));
493 EXPECT_CALL(mock_receiver, RecordQuad(quad.p1, quad.cp, quad.p2));
494 EXPECT_CALL(mock_receiver,
495 RecordConic(conic.p1, conic.cp, conic.p2, conic.weight));
496 EXPECT_CALL(mock_receiver,
497 RecordCubic(cubic.p1, cubic.cp1, cubic.cp2, cubic.p2));
498 EXPECT_CALL(mock_receiver, RecordLine(cubic.p2, Point(0, 0)));
499 EXPECT_CALL(mock_receiver, EndContour(Point(0, 0), /*with_close=*/true));
500 }
501 PathTessellator::PathToFilledSegments(path, mock_receiver);
502
503 auto [points, contours] = PathTessellator::CountFillStorage(path, 1.0f);
504 EXPECT_EQ(points, 25u);
505 EXPECT_EQ(contours, 1u);
506
507 ::testing::StrictMock<MockPathVertexWriter> mock_writer;
508 {
509 ::testing::InSequence sequence;
510
511 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
512 EXPECT_CALL(mock_writer, Write(Point(10, 10)));
513 {
514 EXPECT_CALL(mock_writer, Write(quad.Solve(1 / 5.0f)));
515 EXPECT_CALL(mock_writer, Write(quad.Solve(2 / 5.0f)));
516 EXPECT_CALL(mock_writer, Write(quad.Solve(3 / 5.0f)));
517 EXPECT_CALL(mock_writer, Write(quad.Solve(4 / 5.0f)));
518 EXPECT_CALL(mock_writer, Write(quad.p2));
519 }
520 {
521 EXPECT_CALL(mock_writer, Write(conic.Solve(1 / 8.0f)));
522 EXPECT_CALL(mock_writer, Write(conic.Solve(2 / 8.0f)));
523 EXPECT_CALL(mock_writer, Write(conic.Solve(3 / 8.0f)));
524 EXPECT_CALL(mock_writer, Write(conic.Solve(4 / 8.0f)));
525 EXPECT_CALL(mock_writer, Write(conic.Solve(5 / 8.0f)));
526 EXPECT_CALL(mock_writer, Write(conic.Solve(6 / 8.0f)));
527 EXPECT_CALL(mock_writer, Write(conic.Solve(7 / 8.0f)));
528 EXPECT_CALL(mock_writer, Write(conic.p2));
529 }
530 {
531 EXPECT_CALL(mock_writer, Write(cubic.Solve(1 / 9.0f)));
532 EXPECT_CALL(mock_writer, Write(cubic.Solve(2 / 9.0f)));
533 EXPECT_CALL(mock_writer, Write(cubic.Solve(3 / 9.0f)));
534 EXPECT_CALL(mock_writer, Write(cubic.Solve(4 / 9.0f)));
535 EXPECT_CALL(mock_writer, Write(cubic.Solve(5 / 9.0f)));
536 EXPECT_CALL(mock_writer, Write(cubic.Solve(6 / 9.0f)));
537 EXPECT_CALL(mock_writer, Write(cubic.Solve(7 / 9.0f)));
538 EXPECT_CALL(mock_writer, Write(cubic.Solve(8 / 9.0f)));
539 EXPECT_CALL(mock_writer, Write(cubic.p2));
540 }
541 EXPECT_CALL(mock_writer, Write(Point(0, 0)));
542 EXPECT_CALL(mock_writer, EndContour());
543 }
544 PathTessellator::PathToFilledVertices(path, mock_writer, 1.0f);
545 }
546
547 TEST(PathTessellatorTest, LinearQuadToPointCount) {
548 flutter::DlPathBuilder builder;
549 builder.MoveTo({316.3, 121.5});
550 builder.QuadraticCurveTo({316.4, 121.5}, {316.5, 121.5});
551 builder.Close();
552 auto path = builder.TakePath();
553
554 auto [points, contours] = PathTessellator::CountFillStorage(path, 2.0f);
555 EXPECT_EQ(points, 3u);
556 EXPECT_EQ(contours, 1u);
557 }
558
559 TEST(PathTessellatorTest, LinearConicToPointCount) {
560 flutter::DlPathBuilder builder;
561 builder.MoveTo({316.3, 121.5});
562 builder.ConicCurveTo({316.4, 121.5}, {316.5, 121.5}, 2.0f);
563 builder.Close();
564 auto path = builder.TakePath();
565
566 auto [points, contours] = PathTessellator::CountFillStorage(path, 2.0f);
567 EXPECT_EQ(points, 3u);
568 EXPECT_EQ(contours, 1u);
569 }
570
571 TEST(PathTessellatorTest, LinearCubicToPointCount) {
572 flutter::DlPathBuilder builder;
573 builder.MoveTo({316.3, 121.5});
574 builder.CubicCurveTo({316.4, 121.5}, {316.5, 121.5}, {316.6, 121.5});
575 builder.Close();
576 auto path = builder.TakePath();
577
578 auto [points, contours] = PathTessellator::CountFillStorage(path, 2.0f);
579 EXPECT_EQ(points, 3u);
580 EXPECT_EQ(contours, 1u);
581 }
582
583 } // namespace testing
584 } // namespace impeller
impeller::PathTessellator::SegmentReceiver
An interface for receiving pruned path segments.
Definition: path_tessellator.h:28
impeller::PathTessellator::SegmentReceiver::RecordLine
virtual void RecordLine(Point p1, Point p2)=0
impeller::PathTessellator::SegmentReceiver::RecordCubic
virtual void RecordCubic(Point p1, Point cp1, Point cp2, Point p2)=0
impeller::PathTessellator::SegmentReceiver::RecordConic
virtual void RecordConic(Point p1, Point cp, Point p2, Scalar weight)=0
impeller::PathTessellator::SegmentReceiver::RecordQuad
virtual void RecordQuad(Point p1, Point cp, Point p2)=0
impeller::PathTessellator::SegmentReceiver::EndContour
virtual void EndContour(Point origin, bool with_close)=0
impeller::PathTessellator::SegmentReceiver::BeginContour
virtual void BeginContour(Point origin, bool will_be_closed)=0
impeller::PathTessellator::VertexWriter
An interface for generating a multi contour polyline as a triangle strip.
Definition: path_tessellator.h:21
impeller::PathTessellator::VertexWriter::EndContour
virtual void EndContour()=0
impeller::PathTessellator::VertexWriter::Write
virtual void Write(Point point)=0
impeller::PathTessellator::PathToFilledSegments
static void PathToFilledSegments(const PathSource &source, SegmentReceiver &receiver)
Definition: path_tessellator.cc:284
impeller::PathTessellator::PathToFilledVertices
static void PathToFilledVertices(const PathSource &source, VertexWriter &writer, Scalar scale)
Definition: path_tessellator.cc:308
impeller::PathTessellator::CountFillStorage
static std::pair< size_t, size_t > CountFillStorage(const PathSource &source, Scalar scale)
Definition: path_tessellator.cc:298
impeller::testing::MockPathVertexWriter
Definition: path_tessellator_unittests.cc:17
impeller::testing::MockPathVertexWriter::MOCK_METHOD
MOCK_METHOD(void, Write,(Point point),(override))
impeller::testing::MockPathVertexWriter::MOCK_METHOD
MOCK_METHOD(void, EndContour,(),(override))
impeller::testing::MockSegmentReceiver
Definition: path_tessellator_unittests.cc:23
impeller::testing::MockSegmentReceiver::MOCK_METHOD
MOCK_METHOD(void, RecordLine,(Point p1, Point p2),(override))
impeller::testing::MockSegmentReceiver::MOCK_METHOD
MOCK_METHOD(void, RecordCubic,(Point p1, Point cp1, Point cp2, Point p2),(override))
impeller::testing::MockSegmentReceiver::MOCK_METHOD
MOCK_METHOD(void, RecordQuad,(Point p1, Point cp, Point p2),(override))
impeller::testing::MockSegmentReceiver::MOCK_METHOD
MOCK_METHOD(void, EndContour,(Point origin, bool with_close),(override))
impeller::testing::MockSegmentReceiver::MOCK_METHOD
MOCK_METHOD(void, RecordConic,(Point p1, Point cp, Point p2, Scalar weight),(override))
impeller::testing::MockSegmentReceiver::MOCK_METHOD
MOCK_METHOD(void, BeginContour,(Point origin, bool will_be_closed),(override))
impeller::testing::TEST
TEST(AllocationSizeTest, CanCreateTypedAllocations)
Definition: allocation_size_unittests.cc:10
impeller
Definition: allocation.cc:12
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::Point
TPoint< Scalar > Point
Definition: point.h:425
impeller::DlPath
flutter::DlPath DlPath
Definition: dl_dispatcher.h:29
path_tessellator.h
impeller::PathTessellator::Conic
Definition: path_tessellator.h:98
impeller::PathTessellator::Cubic
Definition: path_tessellator.h:141
impeller::PathTessellator::Quad
Definition: path_tessellator.h:61
impeller::TPoint< Scalar >
points
std::vector< Point > points
Definition: tessellator_libtess.cc:76
contours
std::vector< Contour > contours
Definition: tessellator_libtess.cc:77