Flutter Engine
The Flutter Engine
TriangulatingPathRendererTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
13#include "include/core/SkPath.h"
16#include "include/core/SkRect.h"
27#include "include/gpu/GrTypes.h"
32#include "src/base/SkRandom.h"
33#include "src/core/SkPathPriv.h"
53#include "tests/Test.h"
54#include "tools/ToolUtils.h"
55
56#include <cmath>
57#include <cstddef>
58#include <initializer_list>
59#include <map>
60#include <memory>
61#include <utility>
62
63using namespace skia_private;
64
66class SkShader;
67struct GrContextOptions;
68
69#if !defined(SK_ENABLE_OPTIMIZE_SIZE)
70
71/*
72 * These tests pass by not crashing, hanging or asserting in Debug.
73 */
74
75using CreatePathFn = SkPath(*)();
76
78 // Tests active edges made inactive by splitting.
79 // Also tests active edge list forced into an invalid ordering by
80 // splitting (mopped up in cleanup_active_edges()).
81 []() -> SkPath {
83 path.moveTo(229.127044677734375f, 67.34100341796875f);
84 path.lineTo(187.8097381591796875f, -6.7729740142822265625f);
85 path.lineTo(171.411407470703125f, 50.94266510009765625f);
86 path.lineTo(245.5253753662109375f, 9.6253643035888671875f);
87 path.moveTo(208.4683990478515625f, 30.284009933471679688f);
88 path.lineTo(171.411407470703125f, 50.94266510009765625f);
89 path.lineTo(187.8097381591796875f, -6.7729740142822265625f);
90 return path;
91 },
92
93 // Intersections which fall exactly on the current vertex, and require
94 // a restart of the intersection checking.
95 []() -> SkPath {
97 path.moveTo(314.483551025390625f, 486.246002197265625f);
98 path.lineTo(385.41949462890625f, 532.8087158203125f);
99 path.lineTo(373.232879638671875f, 474.05938720703125f);
100 path.lineTo(326.670166015625f, 544.995361328125f);
101 path.moveTo(349.951507568359375f, 509.52734375f);
102 path.lineTo(373.232879638671875f, 474.05938720703125f);
103 path.lineTo(385.41949462890625f, 532.8087158203125f);
104 return path;
105 },
106
107 // Tests active edges which are removed by splitting.
108 []() -> SkPath {
109 SkPath path;
110 path.moveTo(343.107391357421875f, 613.62176513671875f);
111 path.lineTo(426.632415771484375f, 628.5740966796875f);
112 path.lineTo(392.3460693359375f, 579.33544921875f);
113 path.lineTo(377.39373779296875f, 662.86041259765625f);
114 path.moveTo(384.869873046875f, 621.097900390625f);
115 path.lineTo(392.3460693359375f, 579.33544921875f);
116 path.lineTo(426.632415771484375f, 628.5740966796875f);
117 return path;
118 },
119
120 // Collinear edges merged in set_top().
121 // Also, an intersection between left and right enclosing edges which
122 // falls above the current vertex.
123 []() -> SkPath {
124 SkPath path;
125 path.moveTo(545.95751953125f, 791.69854736328125f);
126 path.lineTo(612.05816650390625f, 738.494140625f);
127 path.lineTo(552.4056396484375f, 732.0460205078125f);
128 path.lineTo(605.61004638671875f, 798.14666748046875f);
129 path.moveTo(579.00787353515625f, 765.0963134765625f);
130 path.lineTo(552.4056396484375f, 732.0460205078125f);
131 path.lineTo(612.05816650390625f, 738.494140625f);
132 return path;
133 },
134
135 // Tests active edges which are made inactive by set_top().
136 []() -> SkPath {
137 SkPath path;
138 path.moveTo(819.2725830078125f, 751.77447509765625f);
139 path.lineTo(820.70904541015625f, 666.933837890625f);
140 path.lineTo(777.57049560546875f, 708.63592529296875f);
141 path.lineTo(862.4111328125f, 710.0723876953125f);
142 path.moveTo(819.99078369140625f, 709.3541259765625f);
143 path.lineTo(777.57049560546875f, 708.63592529296875f);
144 path.lineTo(820.70904541015625f, 666.933837890625f);
145 return path;
146 },
147
148 []() -> SkPath {
149 SkPath path;
150 path.moveTo(823.33209228515625f, 749.052734375f);
151 path.lineTo(823.494873046875f, 664.20013427734375f);
152 path.lineTo(780.9871826171875f, 706.5450439453125f);
153 path.lineTo(865.8397216796875f, 706.70782470703125f);
154 path.moveTo(823.4134521484375f, 706.6263427734375f);
155 path.lineTo(780.9871826171875f, 706.5450439453125f);
156 path.lineTo(823.494873046875f, 664.20013427734375f);
157 return path;
158 },
159
160 []() -> SkPath {
161 SkPath path;
162 path.moveTo(954.862548828125f, 562.8349609375f);
163 path.lineTo(899.32818603515625f, 498.679443359375f);
164 path.lineTo(895.017578125f, 558.52435302734375f);
165 path.lineTo(959.17315673828125f, 502.990081787109375f);
166 path.moveTo(927.0953369140625f, 530.7572021484375f);
167 path.lineTo(895.017578125f, 558.52435302734375f);
168 path.lineTo(899.32818603515625f, 498.679443359375f);
169 return path;
170 },
171
172 []() -> SkPath {
173 SkPath path;
174 path.moveTo(958.5330810546875f, 547.35516357421875f);
175 path.lineTo(899.93109130859375f, 485.989013671875f);
176 path.lineTo(898.54901123046875f, 545.97308349609375f);
177 path.lineTo(959.9151611328125f, 487.37109375f);
178 path.moveTo(929.2320556640625f, 516.67205810546875f);
179 path.lineTo(898.54901123046875f, 545.97308349609375f);
180 path.lineTo(899.93109130859375f, 485.989013671875f);
181 return path;
182 },
183
184 []() -> SkPath {
185 SkPath path;
186 path.moveTo(389.8609619140625f, 369.326873779296875f);
187 path.lineTo(470.6290283203125f, 395.33697509765625f);
188 path.lineTo(443.250030517578125f, 341.9478759765625f);
189 path.lineTo(417.239959716796875f, 422.7159423828125f);
190 path.moveTo(430.244964599609375f, 382.3319091796875f);
191 path.lineTo(443.250030517578125f, 341.9478759765625f);
192 path.lineTo(470.6290283203125f, 395.33697509765625f);
193 return path;
194 },
195
196 []() -> SkPath {
197 SkPath path;
198 path.moveTo(20, 20);
199 path.lineTo(50, 80);
200 path.lineTo(20, 80);
201 path.moveTo(80, 50);
202 path.lineTo(50, 50);
203 path.lineTo(20, 50);
204 return path;
205 },
206
207 []() -> SkPath {
208 SkPath path;
209 path.moveTo(257.19439697265625f, 320.876617431640625f);
210 path.lineTo(190.113037109375f, 320.58978271484375f);
211 path.lineTo(203.64404296875f, 293.8145751953125f);
212 path.moveTo(203.357177734375f, 360.896026611328125f);
213 path.lineTo(216.88824462890625f, 334.120819091796875f);
214 path.lineTo(230.41925048828125f, 307.345611572265625f);
215 return path;
216 },
217
218 // A degenerate segments case, where both upper and lower segments of
219 // a split edge must remain active.
220 []() -> SkPath {
221 SkPath path;
222 path.moveTo(231.9331207275390625f, 306.2012939453125f);
223 path.lineTo(191.4859161376953125f, 306.04547119140625f);
224 path.lineTo(231.0659332275390625f, 300.2642822265625f);
225 path.moveTo(189.946807861328125f, 302.072265625f);
226 path.lineTo(179.79705810546875f, 294.859771728515625f);
227 path.lineTo(191.0016021728515625f, 296.165679931640625f);
228 path.moveTo(150.8942108154296875f, 304.900146484375f);
229 path.lineTo(179.708892822265625f, 297.849029541015625f);
230 path.lineTo(190.4742279052734375f, 299.11895751953125f);
231 return path;
232 },
233
234 // Handle the case where edge.dist(edge.fTop) != 0.0.
235 []() -> SkPath {
236 SkPath path;
237 path.moveTo( 0.0f, 400.0f);
238 path.lineTo( 138.0f, 202.0f);
239 path.lineTo( 0.0f, 202.0f);
240 path.moveTo( 12.62693023681640625f, 250.57464599609375f);
241 path.lineTo( 8.13896942138671875f, 254.556884765625f);
242 path.lineTo(-18.15641021728515625f, 220.40203857421875f);
243 path.lineTo(-15.986493110656738281f, 219.6513519287109375f);
244 path.moveTo( 36.931194305419921875f, 282.485504150390625f);
245 path.lineTo( 15.617521286010742188f, 261.2901611328125f);
246 path.lineTo( 10.3829498291015625f, 252.565765380859375f);
247 path.lineTo(-16.165292739868164062f, 222.646026611328125f);
248 return path;
249 },
250
251 // A degenerate segments case which exercises inactive edges being
252 // made active by splitting.
253 []() -> SkPath {
254 SkPath path;
255 path.moveTo(690.62127685546875f, 509.25555419921875f);
256 path.lineTo(99.336181640625f, 511.71405029296875f);
257 path.lineTo(708.362548828125f, 512.4349365234375f);
258 path.lineTo(729.9940185546875f, 516.3114013671875f);
259 path.lineTo(738.708984375f, 518.76995849609375f);
260 path.lineTo(678.3463134765625f, 510.0819091796875f);
261 path.lineTo(681.21795654296875f, 504.81378173828125f);
262 path.moveTo(758.52764892578125f, 521.55963134765625f);
263 path.lineTo(719.1549072265625f, 514.50372314453125f);
264 path.lineTo(689.59063720703125f, 512.0628662109375f);
265 path.lineTo(679.78216552734375f, 507.447845458984375f);
266 return path;
267 },
268
269 // Tests vertices which become "orphaned" (ie., no connected edges)
270 // after simplification.
271 []() -> SkPath {
272 SkPath path;
273 path.moveTo(217.326019287109375f, 166.4752960205078125f);
274 path.lineTo(226.279266357421875f, 170.929473876953125f);
275 path.lineTo(234.3973388671875f, 177.0623626708984375f);
276 path.lineTo(262.0921630859375f, 188.746124267578125f);
277 path.moveTo(196.23638916015625f, 174.0722198486328125f);
278 path.lineTo(416.15277099609375f, 180.138214111328125f);
279 path.lineTo(192.651947021484375f, 304.0228271484375f);
280 return path;
281 },
282
283 []() -> SkPath {
284 SkPath path;
285 path.moveTo( 0.0f, 0.0f);
286 path.lineTo(10000.0f, 0.0f);
287 path.lineTo( 0.0f, -1.0f);
288 path.lineTo(10000.0f, 0.000001f);
289 path.lineTo( 0.0f, -30.0f);
290 return path;
291 },
292
293 // Reduction of Nebraska-StateSeal.svg. Floating point error causes the
294 // same edge to be added to more than one poly on the same side.
295 []() -> SkPath {
296 SkPath path;
297 path.moveTo(170.8199920654296875, 491.86700439453125);
298 path.lineTo(173.7649993896484375, 489.7340087890625);
299 path.lineTo(174.1450958251953125, 498.545989990234375);
300 path.lineTo( 171.998992919921875, 500.88201904296875);
301 path.moveTo(168.2922515869140625, 498.66265869140625);
302 path.lineTo(169.8589935302734375, 497.94500732421875);
303 path.lineTo( 172, 500.88299560546875);
304 path.moveTo( 169.555267333984375, 490.70111083984375);
305 path.lineTo(173.7649993896484375, 489.7340087890625);
306 path.lineTo( 170.82000732421875, 491.86700439453125);
307 return path;
308 },
309
310 // A shape with a vertex collinear to the right hand edge.
311 // This messes up find_enclosing_edges.
312 []() -> SkPath {
313 SkPath path;
314 path.moveTo(80, 20);
315 path.lineTo(80, 60);
316 path.lineTo(20, 60);
317 path.moveTo(80, 50);
318 path.lineTo(80, 80);
319 path.lineTo(20, 80);
320 return path;
321 },
322
323 // Exercises the case where an edge becomes collinear with *two* of its
324 // adjacent neighbour edges after splitting.
325 // This is a reduction from
326 // http://mooooo.ooo/chebyshev-sine-approximation/horner_ulp.svg
327 []() -> SkPath {
328 SkPath path;
329 path.moveTo( 351.99298095703125, 348.23046875);
330 path.lineTo( 351.91876220703125, 347.33984375);
331 path.lineTo( 351.91876220703125, 346.1953125);
332 path.lineTo( 351.90313720703125, 347.734375);
333 path.lineTo( 351.90313720703125, 346.1328125);
334 path.lineTo( 351.87579345703125, 347.93359375);
335 path.lineTo( 351.87579345703125, 345.484375);
336 path.lineTo( 351.86407470703125, 347.7890625);
337 path.lineTo( 351.86407470703125, 346.2109375);
338 path.lineTo( 351.84844970703125, 347.63763427734375);
339 path.lineTo( 351.84454345703125, 344.19232177734375);
340 path.lineTo( 351.78204345703125, 346.9483642578125);
341 path.lineTo( 351.758636474609375, 347.18310546875);
342 path.lineTo( 351.75469970703125, 346.75);
343 path.lineTo( 351.75469970703125, 345.46875);
344 path.lineTo( 352.5546875, 345.46875);
345 path.lineTo( 352.55078125, 347.01953125);
346 path.lineTo( 351.75079345703125, 347.02313232421875);
347 path.lineTo( 351.74688720703125, 346.15203857421875);
348 path.lineTo( 351.74688720703125, 347.646148681640625);
349 path.lineTo( 352.5390625, 346.94140625);
350 path.lineTo( 351.73907470703125, 346.94268798828125);
351 path.lineTo( 351.73516845703125, 344.48565673828125);
352 path.lineTo( 352.484375, 346.73828125);
353 path.lineTo( 351.68438720703125, 346.7401123046875);
354 path.lineTo( 352.4765625, 346.546875);
355 path.lineTo( 351.67657470703125, 346.54937744140625);
356 path.lineTo( 352.47265625, 346.75390625);
357 path.lineTo( 351.67266845703125, 346.756622314453125);
358 path.lineTo( 351.66876220703125, 345.612091064453125);
359 return path;
360 },
361
362 // A path which contains out-of-range colinear intersections.
363 []() -> SkPath {
364 SkPath path;
365 path.moveTo( 0, 63.39080047607421875);
366 path.lineTo(-0.70804601907730102539, 63.14350128173828125);
367 path.lineTo(-7.8608899287380243391e-17, 64.14080047607421875);
368 path.moveTo( 0, 64.14080047607421875);
369 path.lineTo(44.285900115966796875, 64.14080047607421875);
370 path.lineTo( 0, 62.64080047607421875);
371 path.moveTo(21.434900283813476562, -0.24732701480388641357);
372 path.lineTo(-0.70804601907730102539, 63.14350128173828125);
373 path.lineTo(0.70804601907730102539, 63.6381988525390625);
374 return path;
375 },
376
377 // A path which results in infs and nans when conics are converted to quads.
378 []() -> SkPath {
379 SkPath path;
380 path.moveTo(-2.20883e+37f, -1.02892e+37f);
381 path.conicTo(-2.00958e+38f, -9.36107e+37f, -1.7887e+38f, -8.33215e+37f, 0.707107f);
382 path.conicTo(-1.56782e+38f, -7.30323e+37f, 2.20883e+37f, 1.02892e+37f, 0.707107f);
383 path.conicTo(2.00958e+38f, 9.36107e+37f, 1.7887e+38f, 8.33215e+37f, 0.707107f);
384 path.conicTo(1.56782e+38f, 7.30323e+37f, -2.20883e+37f, -1.02892e+37f, 0.707107f);
385 return path;
386 },
387
388 // A quad which generates a huge number of points (>2B) when uniformly
389 // linearized. This should not hang or OOM.
390 []() -> SkPath {
391 SkPath path;
392 path.moveTo(10, 0);
393 path.lineTo(0, 0);
394 path.quadTo(10, 0, 0, 8315084722602508288);
395 return path;
396 },
397
398 // A path which hangs during simplification. It produces an edge which is
399 // to the left of its own endpoints, which causes an infinite loop in the
400 // right-enclosing-edge splitting.
401 []() -> SkPath {
402 SkPath path;
403 path.moveTo(0.75001740455627441406, 23.051967620849609375);
404 path.lineTo(5.8471612930297851562, 22.731662750244140625);
405 path.lineTo(10.749670028686523438, 22.253145217895507812);
406 path.lineTo(13.115868568420410156, 22.180681228637695312);
407 path.lineTo(15.418928146362304688, 22.340015411376953125);
408 path.lineTo( 17.654022216796875, 22.82159423828125);
409 path.lineTo(19.81632232666015625, 23.715869903564453125);
410 path.lineTo(40, 0);
411 path.lineTo(5.5635203441547955577e-15, 0);
412 path.lineTo(5.5635203441547955577e-15, 47);
413 path.lineTo(-1.4210854715202003717e-14, 21.713298797607421875);
414 path.lineTo(0.75001740455627441406, 21.694292068481445312);
415 path.lineTo(0.75001740455627441406, 23.051967620849609375);
416 return path;
417 },
418
419 // Reduction from skbug.com/7911 that causes a crash due to splitting a
420 // zombie edge.
421 []() -> SkPath {
422 SkPath path;
423 path.moveTo( 0, 1.0927740941146660348e+24);
424 path.lineTo(2.9333931225865729333e+32, 16476101);
425 path.lineTo(1.0927731573659435417e+24, 1.0927740941146660348e+24);
426 path.lineTo(1.0927740941146660348e+24, 3.7616281094287041715e-37);
427 path.lineTo(1.0927740941146660348e+24, 1.0927740941146660348e+24);
428 path.lineTo(1.3061803026169399536e-33, 1.0927740941146660348e+24);
429 path.lineTo(4.7195362919941370727e-16, -8.4247545146051822591e+32);
430 return path;
431 },
432
433 // From crbug.com/844873. Crashes trying to merge a zombie edge.
434 []() -> SkPath {
435 SkPath path;
436 path.moveTo( 316.000579833984375, -4338355948977389568);
437 path.lineTo(1.5069369808623501312e+20, 75180972320904708096.0);
438 path.lineTo(1.5069369808623501312e+20, 75180972320904708096.0);
439 path.lineTo( 771.21014404296875, -4338355948977389568.0);
440 path.lineTo( 316.000579833984375, -4338355948977389568.0);
441 path.moveTo( 354.208984375, -4338355948977389568.0);
442 path.lineTo( 773.00177001953125, -4338355948977389568.0);
443 path.lineTo(1.5069369808623501312e+20, 75180972320904708096.0);
444 path.lineTo(1.5069369808623501312e+20, 75180972320904708096.0);
445 path.lineTo( 354.208984375, -4338355948977389568.0);
446 return path;
447 },
448
449 // From crbug.com/844873. Hangs repeatedly splitting alternate vertices.
450 []() -> SkPath {
451 SkPath path;
452 path.moveTo(10, -1e+20f);
453 path.lineTo(11, 25000);
454 path.lineTo(10, 25000);
455 path.lineTo(11, 25010);
456 return path;
457 },
458
459 // Reduction from circular_arcs_stroke_and_fill_round GM which
460 // repeatedly splits on the opposite edge from case 34 above.
461 []() -> SkPath {
462 SkPath path;
463 path.moveTo( 16.25, 26.495191574096679688);
464 path.lineTo(32.420825958251953125, 37.377376556396484375);
465 path.lineTo(25.176382064819335938, 39.31851959228515625);
466 path.moveTo( 20, 20);
467 path.lineTo(28.847436904907226562, 37.940830230712890625);
468 path.lineTo(25.17638397216796875, 39.31851959228515625);
469 return path;
470 },
471
472 // Reduction from crbug.com/843135 where an intersection is found
473 // below the bottom of both intersected edges.
474 []() -> SkPath {
475 SkPath path;
476 path.moveTo(-2791476679359332352, 2608107002026524672);
477 path.lineTo( 0, 11.95427703857421875);
478 path.lineTo(-2781824066779086848, 2599088532777598976);
479 path.lineTo( -7772.6875, 7274);
480 return path;
481 },
482
483 // Reduction from crbug.com/843135. Exercises a case where an intersection is missed.
484 // This causes bad ordering in the active edge list.
485 []() -> SkPath {
486 SkPath path;
487 path.moveTo(-1.0662557646016024569e+23, 9.9621425197286319718e+22);
488 path.lineTo( -121806400, 113805032);
489 path.lineTo( -120098872, 112209680);
490 path.lineTo( 6.2832999862817380468e-36, 2.9885697364807128906);
491 return path;
492 },
493
494 // Reduction from crbug.com/851409. Exercises collinear last vertex.
495 []() -> SkPath {
496 SkPath path;
497 path.moveTo(2072553216, 0);
498 path.lineTo(2072553216, 1);
499 path.lineTo(2072553472, -13.5);
500 path.lineTo(2072553216, 0);
501 path.lineTo(2072553472, -6.5);
502 return path;
503 },
504
505 // Another reduction from crbug.com/851409. Exercises two sequential collinear edges.
506 []() -> SkPath {
507 SkPath path;
508 path.moveTo(2072553216, 0);
509 path.lineTo(2072553216, 1);
510 path.lineTo(2072553472, -13);
511 path.lineTo(2072553216, 0);
512 path.lineTo(2072553472, -6);
513 path.lineTo(2072553472, -13);
514 return path;
515 },
516
517 // Reduction from crbug.com/860655. Cause is three collinear edges discovered during
518 // sanitize_contours pass, before the vertices have been found coincident.
519 []() -> SkPath {
520 SkPath path;
521 path.moveTo( 32572426382475264, -3053391034974208);
522 path.lineTo( 521289856, -48865776);
523 path.lineTo( 130322464, -12215873);
524 path.moveTo( 32572426382475264, -3053391034974208);
525 path.lineTo( 521289856, -48865776);
526 path.lineTo( 130322464, -12215873);
527 path.moveTo( 32572426382475264, -3053391034974208);
528 path.lineTo( 32114477642022912, -3010462031544320);
529 path.lineTo( 32111784697528320, -3010209702215680);
530 return path;
531 },
532};
533
534#if defined(SK_GANESH)
535
536// A simple concave path. Test this with a non-invertible matrix.
537static SkPath create_path_17() {
538 SkPath path;
539 path.moveTo(20, 20);
540 path.lineTo(80, 20);
541 path.lineTo(30, 30);
542 path.lineTo(20, 80);
543 return path;
544}
545
546// An intersection above the first vertex in the mesh.
547// Reduction from http://crbug.com/730687
548static SkPath create_path_20() {
549 SkPath path;
550 path.moveTo( 2822128.5, 235.026336669921875);
551 path.lineTo( 2819349.25, 235.3623504638671875);
552 path.lineTo( -340558688, 23.83478546142578125);
553 path.lineTo( -340558752, 25.510419845581054688);
554 path.lineTo( -340558720, 27.18605804443359375);
555 return path;
556}
557
558// An intersection whose result is NaN (due to rounded-to-inf endpoint).
559static SkPath create_path_21() {
560 SkPath path;
561 path.moveTo(1.7889142061167663539e+38, 39338463358011572224.0);
562 path.lineTo( 1647.4193115234375, -522.603515625);
563 path.lineTo( 1677.74560546875, -529.0028076171875);
564 path.lineTo( 1678.29541015625, -528.7847900390625);
565 path.lineTo( 1637.5167236328125, -519.79266357421875);
566 path.lineTo( 1647.4193115234375, -522.603515625);
567 return path;
568}
569
570// An edge collapse event which also collapses a neighbour, requiring
571// its event to be removed.
572static SkPath create_path_25() {
573 SkPath path;
574 path.moveTo( 43.44110107421875, 148.15106201171875);
575 path.lineTo( 44.64471435546875, 148.16748046875);
576 path.lineTo( 46.35009765625, 147.403076171875);
577 path.lineTo( 46.45404052734375, 148.34906005859375);
578 path.lineTo( 45.0400390625, 148.54205322265625);
579 path.lineTo( 44.624053955078125, 148.9810791015625);
580 path.lineTo( 44.59405517578125, 149.16107177734375);
581 path.lineTo( 44.877044677734375, 149.62005615234375);
582 path.lineTo(144.373016357421875, 68.8070068359375);
583 return path;
584}
585
586// An edge collapse event causes an edge to become collinear, requiring
587// its event to be removed.
588static SkPath create_path_26() {
589 SkPath path;
590 path.moveTo( 43.44110107421875, 148.15106201171875);
591 path.lineTo( 44.64471435546875, 148.16748046875);
592 path.lineTo( 46.35009765625, 147.403076171875);
593 path.lineTo( 46.45404052734375, 148.34906005859375);
594 path.lineTo( 45.0400390625, 148.54205322265625);
595 path.lineTo( 44.624053955078125, 148.9810791015625);
596 path.lineTo( 44.59405517578125, 149.16107177734375);
597 path.lineTo( 44.877044677734375, 149.62005615234375);
598 path.lineTo(144.373016357421875, 68.8070068359375);
599 return path;
600}
601
602// A path which results in non-finite points when stroked and bevelled for AA.
603static SkPath create_path_27() {
604 SkPath path;
605 path.moveTo(8.5027233009104409507e+37, 1.7503381025241130639e+37);
606 path.lineTo(7.0923661737711584874e+37, 1.4600074517285415699e+37);
607 path.lineTo(7.0848733446033294691e+37, 1.4584649744781838604e+37);
608 path.lineTo(-2.0473916115129349496e+37, -4.2146796450364162012e+36);
609 path.lineTo(2.0473912312177548811e+37, 4.2146815465123165435e+36);
610 return path;
611}
612
613// AA stroking this path produces intersection failures on bevelling.
614// This should skip the point, but not assert.
615static SkPath create_path_28() {
616 SkPath path;
617 path.moveTo(-7.5952312625177475154e+21, -2.6819185100266674911e+24);
618 path.lineTo( 1260.3787841796875, 1727.7947998046875);
619 path.lineTo( 1260.5567626953125, 1728.0386962890625);
620 path.lineTo(1.1482511310557754163e+21, 4.054538502765980051e+23);
621 path.lineTo(-7.5952312625177475154e+21, -2.6819185100266674911e+24);
622 return path;
623}
624
625// A path with vertices which become infinite on AA stroking. Should not crash or assert.
626static SkPath create_path_31() {
627 SkPath path;
628 path.moveTo(2.0257809259190991347e+36, -1244080640);
629 path.conicTo(2.0257809259190991347e+36, -1244080640,
630 2.0257809259190991347e+36, 0.10976474732160568237, 0.70710676908493041992);
631 path.lineTo(-10036566016, -1954718402215936);
632 path.conicTo(-1.1375507718551896064e+20, -1954721086570496,
633 10036566016, -1954721086570496, 0.70710676908493041992);
634 return path;
635}
636
637// Reduction from crbug.com/851914.
638static SkPath create_path_38() {
639 SkPath path;
640 path.moveTo(14.400531768798828125, 17.711114883422851562);
641 path.lineTo(14.621990203857421875, 171563104293879808);
642 path.lineTo(14.027951240539550781, 872585759381520384);
643 path.lineTo( 14.0216827392578125, 872665817571917824);
644 path.lineTo(7.699314117431640625, -3417320793833472);
645 path.moveTo(11.606547355651855469, 17.40966796875);
646 path.lineTo( 7642114886926860288, 21.08358001708984375);
647 path.lineTo(11.606547355651855469, 21.08358001708984375);
648 return path;
649}
650
651// Reduction from crbug.com/860453. Tests a case where a "missing" intersection
652// requires the active edge list to go out-of-order.
653static SkPath create_path_41() {
654 SkPath path;
655 path.moveTo(72154931603311689728.0, 330.95965576171875);
656 path.lineTo(24053266013925408768.0, 78.11376953125);
657 path.lineTo(1.2031099003292404941e+20, 387.168731689453125);
658 path.lineTo(68859835992355373056.0, 346.55047607421875);
659 path.lineTo(76451708695451009024.0, 337.780029296875);
660 path.moveTo(-20815817797613387776.0, 18065700622522384384.0);
661 path.lineTo(-72144121204987396096.0, 142.855804443359375);
662 path.lineTo(72144121204987396096.0, 325.184783935546875);
663 path.lineTo(1.2347242901040791552e+20, 18065700622522384384.0);
664 return path;
665}
666
667// Reduction from crbug.com/866319. Cause is edges that are collinear when tested from
668// one side, but non-collinear when tested from the other.
669static SkPath create_path_43() {
670 SkPath path;
671 path.moveTo( 307316821852160, -28808363114496);
672 path.lineTo( 307165222928384, -28794154909696);
673 path.lineTo( 307013691113472, -28779948802048);
674 path.lineTo( 306862159298560, -28765744791552);
675 path.lineTo( 306870313025536, -28766508154880);
676 path.lineTo( 307049695019008, -28783327313920);
677 path.lineTo( 307408660332544, -28816974020608);
678 return path;
679}
680
681// Reduction from crbug.com/966696
682static SkPath create_path_44() {
683 SkPath path;
684 path.moveTo(114.4606170654296875, 186.443878173828125);
685 path.lineTo( 91.5394744873046875, 185.4189453125);
686 path.lineTo(306.45538330078125, 3203.986083984375);
687 path.moveTo(16276206965409972224.0, 815.59393310546875);
688 path.lineTo(-3.541605062372533207e+20, 487.7236328125);
689 path.lineTo(-3.541605062372533207e+20, 168.204071044921875);
690 path.lineTo(16276206965409972224.0, 496.07427978515625);
691 path.moveTo(-3.541605062372533207e+20, 167.00958251953125);
692 path.lineTo(-3.541605062372533207e+20, 488.32086181640625);
693 path.lineTo(16276206965409972224.0, 816.78839111328125);
694 path.lineTo(16276206965409972224.0, 495.47705078125);
695 return path;
696}
697
698// Reduction from crbug.com/966274.
699static SkPath create_path_45() {
700 SkPath path;
701 path.moveTo( 706471854080, 379003666432);
702 path.lineTo( 706503180288, 379020443648);
703 path.lineTo( 706595717120, 379070087168);
704 path.lineTo( 706626060288, 379086372864);
705 path.lineTo( 706656141312, 379102527488);
706 path.lineTo( 706774171648, 379165835264);
707 path.lineTo( 706803073024, 379181334528);
708 path.lineTo( 706831712256, 379196702720);
709 path.lineTo( 706860154880, 379211939840);
710 path.lineTo( 706888335360, 379227078656);
711 path.lineTo( 706916253696, 379242053632);
712 path.lineTo( 706956820480, 379263811584);
713 path.lineTo( 706929098752, 379248934912);
714 path.lineTo( 706901114880, 379233927168);
715 path.lineTo( 706872934400, 379218821120);
716 path.lineTo( 706844491776, 379203551232);
717 path.lineTo( 706815787008, 379188183040);
718 path.lineTo( 706786885632, 379172651008);
719 path.lineTo( 706757722112, 379156987904);
720 path.lineTo( 706728296448, 379141226496);
721 path.lineTo( 706698608640, 379125301248);
722 path.lineTo( 706668724224, 379109244928);
723 path.lineTo( 706638577664, 379093090304);
724 path.lineTo( 706608168960, 379076771840);
725 path.lineTo( 706484174848, 379010252800);
726 return path;
727}
728
729// Reduction from crbug.com/969359. Inf generated by intersections
730// causes NaN in subsequent intersections, leading to assert or hang.
731
732static SkPath create_path_46() {
733 SkPath path;
734 path.moveTo(1.0321827899075254821e+37, -5.1199920965387697886e+37);
735 path.lineTo(-1.0321827899075254821e+37, 5.1199920965387697886e+37);
736 path.lineTo(-1.0425214946728668754e+37, 4.5731834042267216669e+37);
737 path.moveTo(-9.5077331762291841872e+36, 8.1304868292377430302e+37);
738 path.lineTo(9.5077331762291841872e+36, -8.1304868292377430302e+37);
739 path.lineTo(1.0795449417808426232e+37, 1.2246856113744539311e+37);
740 path.moveTo(-165.8018341064453125, -44.859375);
741 path.lineTo(-9.558702871563160835e+36, -7.9814405281448285475e+37);
742 path.lineTo(-9.4147814283168490381e+36, -8.3935116522790983488e+37);
743 return path;
744}
745
746// Reduction from crbug.com/1245359
747static SkPath create_path_47() {
748 SkPath path;
749 path.setFillType(SkPathFillType::kWinding);
750 path.moveTo(SkBits2Float(0xdfb80000), SkBits2Float(0x4cb9b4a5)); // -2.65172e+19f, 9.73632e+07f
751 path.lineTo(SkBits2Float(0xdfb80000), SkBits2Float(0xe396b530)); // -2.65172e+19f, -5.56014e+21f
752 path.lineTo(SkBits2Float(0x5fb80000), SkBits2Float(0xe396b530)); // 2.65172e+19f, -5.56014e+21f
753 path.lineTo(SkBits2Float(0x5fb80000), SkBits2Float(0x6396b530)); // 2.65172e+19f, 5.56014e+21f
754 path.lineTo(SkBits2Float(0x4cc07742), SkBits2Float(0x6396b530)); // 1.00908e+08f, 5.56014e+21f
755 path.lineTo(SkBits2Float(0xdfb80000), SkBits2Float(0x6396b530)); // -2.65172e+19f, 5.56014e+21f
756 path.lineTo(SkBits2Float(0xdfb80000), SkBits2Float(0xe396b530)); // -2.65172e+19f, -5.56014e+21f
757 path.lineTo(SkBits2Float(0x4cc07742), SkBits2Float(0xe396b530)); // 1.00908e+08f, -5.56014e+21f
758 path.lineTo(SkBits2Float(0x4cc079c8), SkBits2Float(0xe396b530)); // 1.00913e+08f, -5.56014e+21f
759 path.lineTo(SkBits2Float(0x4cc079c8), SkBits2Float(0x4cb9b4a5)); // 1.00913e+08f, 9.73632e+07f
760 path.lineTo(SkBits2Float(0xdfb80000), SkBits2Float(0x4cb9b4a5)); // -2.65172e+19f, 9.73632e+07f
761 path.lineTo(SkBits2Float(0xdfb80000), SkBits2Float(0x4cb74d74)); // -2.65172e+19f, 9.61033e+07f
762 path.lineTo(SkBits2Float(0x4cc079c8), SkBits2Float(0x4cb74d74)); // 1.00913e+08f, 9.61033e+07f
763 path.lineTo(SkBits2Float(0x4cc079c8), SkBits2Float(0x6396b530)); // 1.00913e+08f, 5.56014e+21f
764 path.lineTo(SkBits2Float(0x4cc07742), SkBits2Float(0x6396b530)); // 1.00908e+08f, 5.56014e+21f
765 path.lineTo(SkBits2Float(0x4cc07742), SkBits2Float(0x4cb74d74)); // 1.00908e+08f, 9.61033e+07f
766 path.lineTo(SkBits2Float(0x5fb80000), SkBits2Float(0x4cb74d74)); // 2.65172e+19f, 9.61033e+07f
767 path.lineTo(SkBits2Float(0x5fb80000), SkBits2Float(0x6396b530)); // 2.65172e+19f, 5.56014e+21f
768 path.lineTo(SkBits2Float(0xdfb80000), SkBits2Float(0x6396b530)); // -2.65172e+19f, 5.56014e+21f
769 path.lineTo(SkBits2Float(0xdfb80000), SkBits2Float(0x4cb9b4a5)); // -2.65172e+19f, 9.73632e+07f
770 path.close();
771
772 path.moveTo(SkBits2Float(0xdfb39e51), SkBits2Float(0xe282c5bd)); // -2.58857e+19f, -1.20616e+21f
773 path.lineTo(SkBits2Float(0xdf8a47ec), SkBits2Float(0xe3b90de5)); // -1.99284e+19f, -6.8273e+21f
774 path.lineTo(SkBits2Float(0x5eb8b548), SkBits2Float(0xe391e278)); // 6.65481e+18f, -5.38219e+21f
775 path.quadTo(SkBits2Float(0x5eaa9855), SkBits2Float(0xe392a246), // 6.14633e+18f, -5.40984e+21f
776 SkBits2Float(0x5e9c5925), SkBits2Float(0xe39344a0)); // 5.63304e+18f, -5.43323e+21f
777 path.quadTo(SkBits2Float(0x5e89eefd), SkBits2Float(0xe3941678), // 4.96958e+18f, -5.46347e+21f
778 SkBits2Float(0x5e6ead5a), SkBits2Float(0xe394b6a4)); // 4.29963e+18f, -5.48656e+21f
779 path.quadTo(SkBits2Float(0x5e6c0307), SkBits2Float(0xe394c21f), // 4.25161e+18f, -5.48821e+21f
780 SkBits2Float(0x5e694ef2), SkBits2Float(0xe394cd7f)); // 4.20291e+18f, -5.48985e+21f
781 path.quadTo(SkBits2Float(0x5e67eeaa), SkBits2Float(0xe394d349), // 4.17812e+18f, -5.49069e+21f
782 SkBits2Float(0x5e669614), SkBits2Float(0xe394d8e2)); // 4.15387e+18f, -5.49149e+21f
783 path.quadTo(SkBits2Float(0x5e6534d4), SkBits2Float(0xe394de9e), // 4.12901e+18f, -5.49232e+21f
784 SkBits2Float(0x5e63d6a7), SkBits2Float(0xe394e43c)); // 4.10437e+18f, -5.49313e+21f
785 path.quadTo(SkBits2Float(0x5e610d59), SkBits2Float(0xe394efad), // 4.05418e+18f, -5.49478e+21f
786 SkBits2Float(0x5e5e43cb), SkBits2Float(0xe394fad6)); // 4.00397e+18f, -5.49639e+21f
787 path.quadTo(SkBits2Float(0x5e5b6ac0), SkBits2Float(0xe395063d), // 3.95267e+18f, -5.49803e+21f
788 SkBits2Float(0x5e5895ab), SkBits2Float(0xe3951148)); // 3.90164e+18f, -5.49962e+21f
789 path.quadTo(SkBits2Float(0x5e55b52e), SkBits2Float(0xe3951c7f), // 3.84982e+18f, -5.50124e+21f
790 SkBits2Float(0x5e52cb8e), SkBits2Float(0xe395278b)); // 3.79735e+18f, -5.50283e+21f
791 path.quadTo(SkBits2Float(0x5e514f61), SkBits2Float(0xe3952d2d), // 3.7706e+18f, -5.50364e+21f
792 SkBits2Float(0x5e4fdbc5), SkBits2Float(0xe395329a)); // 3.74445e+18f, -5.50442e+21f
793 path.lineTo(SkBits2Float(0x5e4fdbc5), SkBits2Float(0xe395329a)); // 3.74445e+18f, -5.50442e+21f
794 path.lineTo(SkBits2Float(0x5e4fdbc5), SkBits2Float(0xe395329a)); // 3.74445e+18f, -5.50442e+21f
795 path.lineTo(SkBits2Float(0x5e4fdbc5), SkBits2Float(0xe395329a)); // 3.74445e+18f, -5.50442e+21f
796 path.lineTo(SkBits2Float(0x5e4fdbc5), SkBits2Float(0xe395329a)); // 3.74445e+18f, -5.50442e+21f
797 path.lineTo(SkBits2Float(0x5e4fdbc5), SkBits2Float(0xe395329a)); // 3.74445e+18f, -5.50442e+21f
798 path.lineTo(SkBits2Float(0x5e4fdbc5), SkBits2Float(0xe395329a)); // 3.74445e+18f, -5.50442e+21f
799 path.lineTo(SkBits2Float(0x5e4fdbc5), SkBits2Float(0xe395329a)); // 3.74445e+18f, -5.50442e+21f
800 path.lineTo(SkBits2Float(0x5e4fdbc5), SkBits2Float(0xe395329a)); // 3.74445e+18f, -5.50442e+21f
801 path.lineTo(SkBits2Float(0x5e4fdbc5), SkBits2Float(0xe395329a)); // 3.74445e+18f, -5.50442e+21f
802 path.lineTo(SkBits2Float(0xdfb80000), SkBits2Float(0xe396b530)); // -2.65172e+19f, -5.56014e+21f
803 path.lineTo(SkBits2Float(0x5fb80000), SkBits2Float(0xe396b530)); // 2.65172e+19f, -5.56014e+21f
804 path.lineTo(SkBits2Float(0x5fb80000), SkBits2Float(0x4cc8d35d)); // 2.65172e+19f, 1.0529e+08f
805 path.lineTo(SkBits2Float(0xdfe2ba48), SkBits2Float(0x63512f2f)); // -3.26749e+19f, 3.85877e+21f
806 path.lineTo(SkBits2Float(0xdf7f64f6), SkBits2Float(0xe3b9b457)); // -1.84031e+19f, -6.85129e+21f
807 path.lineTo(SkBits2Float(0xdfb80000), SkBits2Float(0x4cc8d35d)); // -2.65172e+19f, 1.0529e+08f
808 path.lineTo(SkBits2Float(0xdfb80000), SkBits2Float(0x4cbbf2a2)); // -2.65172e+19f, 9.85388e+07f
809 path.lineTo(SkBits2Float(0x4cc079c8), SkBits2Float(0x4cbbf2a2)); // 1.00913e+08f, 9.85388e+07f
810 path.lineTo(SkBits2Float(0x4cc079c8), SkBits2Float(0x6396b530)); // 1.00913e+08f, 5.56014e+21f
811 path.lineTo(SkBits2Float(0x4cc07742), SkBits2Float(0x6396b530)); // 1.00908e+08f, 5.56014e+21f
812 path.lineTo(SkBits2Float(0x4cc07742), SkBits2Float(0x4cbbf2a2)); // 1.00908e+08f, 9.85388e+07f
813 path.lineTo(SkBits2Float(0x5fb80000), SkBits2Float(0x4cbbf2a2)); // 2.65172e+19f, 9.85388e+07f
814 path.lineTo(SkBits2Float(0xdeb8b548), SkBits2Float(0x6391e278)); // -6.65481e+18f, 5.38219e+21f
815 path.lineTo(SkBits2Float(0x4cc07488), SkBits2Float(0x4ccb2302)); // 1.00902e+08f, 1.06502e+08f
816 path.lineTo(SkBits2Float(0x5fb39e51), SkBits2Float(0x6282c5bd)); // 2.58857e+19f, 1.20616e+21f
817 path.lineTo(SkBits2Float(0x5fb39e51), SkBits2Float(0x6282c5bd)); // 2.58857e+19f, 1.20616e+21f
818 path.lineTo(SkBits2Float(0x5f8bb406), SkBits2Float(0x63b3cfe4)); // 2.01334e+19f, 6.63389e+21f
819 path.lineTo(SkBits2Float(0xdfdb889b), SkBits2Float(0x6364da0b)); // -3.16381e+19f, 4.22157e+21f
820 path.lineTo(SkBits2Float(0xdfb39e51), SkBits2Float(0xe282c5bd)); // -2.58857e+19f, -1.20616e+21f
821 path.close();
822 return path;
823}
824
825static std::unique_ptr<GrFragmentProcessor>
826create_linear_gradient_processor(GrRecordingContext* rContext, const SkMatrix& ctm) {
827 SkPoint pts[2] = { {0, 0}, {1, 1} };
830 pts, colors, nullptr, std::size(colors), SkTileMode::kClamp);
832 SkSurfaceProps props; // default props for testing
834 shader.get(), {rContext, &colorInfo, props, GrFPArgs::Scope::kDefault}, ctm);
835}
836
837static void test_path(GrRecordingContext* rContext,
839 const SkPath& path,
840 const SkMatrix& matrix = SkMatrix::I(),
841 GrAAType aaType = GrAAType::kNone,
842 std::unique_ptr<GrFragmentProcessor> fp = nullptr) {
844 pr.setMaxVerbCount(100);
845
848 if (fp) {
849 paint.setColorFragmentProcessor(std::move(fp));
850 }
851
852 SkIRect clipConservativeBounds = SkIRect::MakeWH(sdc->width(), sdc->height());
854 GrStyledShape shape(path, style);
856 std::move(paint),
858 sdc,
859 nullptr,
860 &clipConservativeBounds,
861 &matrix,
862 &shape,
863 aaType,
864 false};
865 pr.drawPath(args);
866}
867
868DEF_GANESH_TEST_FOR_ALL_CONTEXTS(TriangulatingPathRendererTests,
869 reporter,
870 ctxInfo,
872 auto ctx = ctxInfo.directContext();
875 nullptr,
877 {800, 800},
879 /*label=*/{},
880 /* sampleCnt= */ 1,
884 if (!sdc) {
885 return;
886 }
887
888 ctx->flushAndSubmit();
889 // Adding discard to appease vulkan validation warning about loading uninitialized data on draw
890 sdc->discard();
891
892 for (CreatePathFn createPath : kNonEdgeAAPaths) {
893 test_path(ctx, sdc.get(), createPath());
894 }
895 SkMatrix nonInvertibleMatrix = SkMatrix::Scale(0, 0);
896 std::unique_ptr<GrFragmentProcessor> fp(create_linear_gradient_processor(ctx, SkMatrix()));
897 test_path(ctx, sdc.get(), create_path_17(), nonInvertibleMatrix, GrAAType::kCoverage,
898 std::move(fp));
899 test_path(ctx, sdc.get(), create_path_20(), SkMatrix(), GrAAType::kCoverage);
900 test_path(ctx, sdc.get(), create_path_21(), SkMatrix(), GrAAType::kCoverage);
901 test_path(ctx, sdc.get(), create_path_25(), SkMatrix(), GrAAType::kCoverage);
902 test_path(ctx, sdc.get(), create_path_26(), SkMatrix(), GrAAType::kCoverage);
903 test_path(ctx, sdc.get(), create_path_27(), SkMatrix(), GrAAType::kCoverage);
904 test_path(ctx, sdc.get(), create_path_28(), SkMatrix(), GrAAType::kCoverage);
905 test_path(ctx, sdc.get(), create_path_31(), SkMatrix(), GrAAType::kCoverage);
906 test_path(ctx, sdc.get(), create_path_38(), SkMatrix(), GrAAType::kCoverage);
907 test_path(ctx, sdc.get(), create_path_41(), SkMatrix(), GrAAType::kCoverage);
908 test_path(ctx, sdc.get(), create_path_43(), SkMatrix(), GrAAType::kCoverage);
909 test_path(ctx, sdc.get(), create_path_44(), SkMatrix(), GrAAType::kCoverage);
910 test_path(ctx, sdc.get(), create_path_45(), SkMatrix(), GrAAType::kCoverage);
911 test_path(ctx, sdc.get(), create_path_46(), SkMatrix(), GrAAType::kCoverage);
912 test_path(ctx, sdc.get(), create_path_47(), SkMatrix(), GrAAType::kCoverage);
913}
914
915#endif // defined(SK_GANESH)
916
917namespace {
918
919class SimpleVertexAllocator : public GrEagerVertexAllocator {
920public:
921 void* lock(size_t stride, int eagerCount) override {
922 SkASSERT(!fPoints);
923 SkASSERT(stride == sizeof(SkPoint));
924 fPoints.reset(eagerCount);
925 return fPoints;
926 }
927 void unlock(int actualCount) override {}
928 SkPoint operator[](int idx) const { return fPoints[idx]; }
929 AutoTMalloc<SkPoint> fPoints;
930};
931
932class SimplerVertexAllocator : public GrEagerVertexAllocator {
933public:
934 void* lock(size_t stride, int eagerCount) override {
935 size_t allocSize = eagerCount * stride;
936 if (allocSize > fVertexAllocSize) {
937 fVertexData.reset(allocSize);
938 }
939 return fVertexData;
940 }
941
942 void unlock(int) override {}
943
944 AutoTMalloc<char> fVertexData;
945 size_t fVertexAllocSize = 0;
946};
947
948} // namespace
949
950struct Edge {
951 Edge reverse() const { return {fP1, fP0}; }
953};
954
955static bool operator<(const Edge& a, const Edge& b) {
956 if (a.fP0.fX != b.fP0.fX) {
957 return a.fP0.fX < b.fP0.fX;
958 }
959 if (a.fP0.fY != b.fP0.fY) {
960 return a.fP0.fY < b.fP0.fY;
961 }
962 if (a.fP1.fX != b.fP1.fX) {
963 return a.fP1.fX < b.fP1.fX;
964 }
965 if (a.fP1.fY != b.fP1.fY) {
966 return a.fP1.fY < b.fP1.fY;
967 }
968 return false;
969}
970
971using EdgeMap = std::map<Edge, int>;
972
973static void add_edge(EdgeMap& edgeMap, SkPoint p0, SkPoint p1) {
974 Edge edge{p0, p1};
975 // First check if this edge already exists in reverse.
976 auto reverseIter = edgeMap.find(edge.reverse());
977 if (reverseIter != edgeMap.end()) {
978 --reverseIter->second;
979 } else {
980 ++edgeMap[edge];
981 }
982}
983
984static void add_tri_edges(skiatest::Reporter* r, EdgeMap& edgeMap, const SkPoint pts[3]) {
985 for (int i = 0; i < 3; ++i) {
986 SkPoint p0=pts[i], p1=pts[(i+1)%3];
987 // The triangulator shouldn't output degenerate triangles.
988 REPORTER_ASSERT(r, p0 != p1);
989 add_edge(edgeMap, p0, p1);
990 }
991}
992
993static EdgeMap simplify(const EdgeMap& edges, SkPathFillType fillType) {
994 // Prune out the edges whose count went to zero, and reverse the edges whose count is negative.
995 EdgeMap simplifiedEdges;
996 for (auto [edge, count] : edges) {
997 // We should only have one ordering of any given edge.
998 SkASSERT(edges.find(edge.reverse()) == edges.end());
999 if (fillType == SkPathFillType::kEvenOdd) {
1000 count = abs(count) & 1;
1001 }
1002 if (count > 0) {
1003 simplifiedEdges[edge] = count;
1004 } else if (count < 0) {
1005 simplifiedEdges[edge.reverse()] = -count;
1006 }
1007 }
1008 return simplifiedEdges;
1009}
1010
1011static void verify_simple_inner_polygons(skiatest::Reporter* r, const char* shapeName,
1012 SkPath path) {
1013 for (auto fillType : {SkPathFillType::kWinding}) {
1014 path.setFillType(fillType);
1017 SimpleVertexAllocator vertexAlloc;
1018 int vertexCount;
1019 {
1020 bool isLinear;
1021 GrInnerFanTriangulator triangulator(path, &arena);
1022 vertexCount = triangulator.pathToTriangles(&vertexAlloc, &breadcrumbs, &isLinear);
1023 }
1024
1025 // Count up all the triangulated edges.
1026 EdgeMap trianglePlusBreadcrumbEdges;
1027 for (int i = 0; i < vertexCount; i += 3) {
1028 add_tri_edges(r, trianglePlusBreadcrumbEdges, vertexAlloc.fPoints.data() + i);
1029 }
1030 // Count up all the breadcrumb edges.
1031 int breadcrumbCount = 0;
1032 for (const auto* node = breadcrumbs.head(); node; node = node->fNext) {
1033 add_tri_edges(r, trianglePlusBreadcrumbEdges, node->fPts);
1034 ++breadcrumbCount;
1035 }
1036 REPORTER_ASSERT(r, breadcrumbCount == breadcrumbs.count());
1037 // The triangulated + breadcrumb edges should cancel out to the inner polygon edges.
1038 trianglePlusBreadcrumbEdges = simplify(trianglePlusBreadcrumbEdges, path.getFillType());
1039
1040 // Build the inner polygon edges.
1041 EdgeMap innerFanEdges;
1042 SkPoint startPoint{}, lastPoint{};
1043 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
1044 switch (verb) {
1045 case SkPathVerb::kMove:
1046 if (lastPoint != startPoint) {
1047 add_edge(innerFanEdges, lastPoint, startPoint);
1048 }
1049 lastPoint = startPoint = pts[0];
1050 continue;
1051 case SkPathVerb::kClose:
1052 lastPoint = startPoint;
1053 break;
1054 case SkPathVerb::kLine:
1055 lastPoint = pts[1];
1056 break;
1057 case SkPathVerb::kQuad:
1058 case SkPathVerb::kConic:
1059 lastPoint = pts[2];
1060 break;
1061 case SkPathVerb::kCubic:
1062 lastPoint = pts[3];
1063 break;
1064 }
1065 if (pts[0] != lastPoint) {
1066 add_edge(innerFanEdges, pts[0], lastPoint);
1067 }
1068 }
1069 if (lastPoint != startPoint) {
1070 add_edge(innerFanEdges, lastPoint, startPoint);
1071 }
1072 innerFanEdges = simplify(innerFanEdges, path.getFillType());
1073
1074 // The triangulated + breadcrumb edges should cancel out to the inner polygon edges. First
1075 // verify that every inner polygon edge can be found in the triangulation.
1076 for (auto [edge, count] : innerFanEdges) {
1077 auto it = trianglePlusBreadcrumbEdges.find(edge);
1078 if (it != trianglePlusBreadcrumbEdges.end()) {
1079 it->second -= count;
1080 if (it->second == 0) {
1081 trianglePlusBreadcrumbEdges.erase(it);
1082 }
1083 continue;
1084 }
1085 it = trianglePlusBreadcrumbEdges.find(edge.reverse());
1086 if (it != trianglePlusBreadcrumbEdges.end()) {
1087 it->second += count;
1088 if (it->second == 0) {
1089 trianglePlusBreadcrumbEdges.erase(it);
1090 }
1091 continue;
1092 }
1093 ERRORF(r, "error: %s: edge [%g,%g]:[%g,%g] not found in triangulation.",
1094 shapeName, edge.fP0.fX, edge.fP0.fY, edge.fP1.fX, edge.fP1.fY);
1095 return;
1096 }
1097 // Now verify that there are no spurious edges in the triangulation.
1098 //
1099 // NOTE: The triangulator's definition of wind isn't always correct for edges that run
1100 // exactly parallel to the sweep (either vertical or horizontal edges). This doesn't
1101 // actually matter though because T-junction artifacts don't happen on axis-aligned edges.
1102 // Tolerate spurious edges that (1) come in pairs of 2, and (2) are either exactly
1103 // horizontal or exactly vertical exclusively.
1104 bool hasSpuriousHorz=false, hasSpuriousVert=false;
1105 for (auto [edge, count] : trianglePlusBreadcrumbEdges) {
1106 if (count % 2 == 0) {
1107 if (edge.fP0.fX == edge.fP1.fX && !hasSpuriousVert) {
1108 hasSpuriousHorz = true;
1109 continue;
1110 }
1111 if (edge.fP0.fY == edge.fP1.fY && !hasSpuriousHorz) {
1112 hasSpuriousVert = true;
1113 continue;
1114 }
1115 }
1116 ERRORF(r, "error: %s: spurious edge [%g,%g]:[%g,%g] found in triangulation.",
1117 shapeName, edge.fP0.fX, edge.fP0.fY, edge.fP1.fX, edge.fP1.fY);
1118 return;
1119 }
1120 }
1121}
1122
1124 verify_simple_inner_polygons(r, "simple triangle", SkPath().lineTo(1,0).lineTo(0,1));
1125 verify_simple_inner_polygons(r, "simple square", SkPath().lineTo(1,0).lineTo(1,1).lineTo(0,1));
1126 verify_simple_inner_polygons(r, "concave polygon", SkPath()
1127 .lineTo(1,0).lineTo(.5f,.5f).lineTo(1,1).lineTo(0,1));
1128 verify_simple_inner_polygons(r, "double wound triangle", SkPath()
1129 .lineTo(1,0).lineTo(0,1).lineTo(0,0).lineTo(1,0).lineTo(0,1));
1130 verify_simple_inner_polygons(r, "self-intersecting bowtie", SkPath()
1131 .lineTo(1,0).lineTo(0,1).lineTo(1,1));
1132 verify_simple_inner_polygons(r, "asymmetrical bowtie", SkPath()
1133 .lineTo(1,0).lineTo(0,1).lineTo(.1f,-.1f));
1134 verify_simple_inner_polygons(r, "bowtie with extremely small section", SkPath()
1135 .lineTo(1,0).lineTo(0,1).lineTo(1e-6f,-1e-6f));
1136 verify_simple_inner_polygons(r, "intersecting squares", SkPath()
1137 .lineTo(1,0).lineTo(1,1).lineTo(0,1)
1138 .moveTo(.5f,.5f).lineTo(1.5f,.5f).lineTo(1.5f,1.5f).lineTo(.5f,1.5f).close());
1139 verify_simple_inner_polygons(r, "6-point \"Star of David\"", SkPath()
1140 .moveTo(cosf(-SK_ScalarPI/3), sinf(-SK_ScalarPI/3))
1141 .lineTo(cosf(SK_ScalarPI/3), sinf(SK_ScalarPI/3))
1142 .lineTo(cosf(SK_ScalarPI), sinf(SK_ScalarPI))
1143 .moveTo(cosf(0), sinf(0))
1144 .lineTo(cosf(2*SK_ScalarPI/3), sinf(2*SK_ScalarPI/3))
1145 .lineTo(cosf(-2*SK_ScalarPI/3), sinf(-2*SK_ScalarPI/3)));
1146 verify_simple_inner_polygons(r, "double wound \"Star of David\"", SkPath()
1147 .moveTo(cosf(-SK_ScalarPI/3), sinf(-SK_ScalarPI/3))
1148 .lineTo(cosf(SK_ScalarPI/3), sinf(SK_ScalarPI/3))
1149 .lineTo(cosf(SK_ScalarPI), sinf(SK_ScalarPI))
1150 .lineTo(cosf(-SK_ScalarPI/3), sinf(-SK_ScalarPI/3))
1151 .lineTo(cosf(SK_ScalarPI/3), sinf(SK_ScalarPI/3))
1152 .lineTo(cosf(SK_ScalarPI), sinf(SK_ScalarPI))
1153 .moveTo(cosf(0), sinf(0))
1154 .lineTo(cosf(2*SK_ScalarPI/3), sinf(2*SK_ScalarPI/3))
1155 .lineTo(cosf(-2*SK_ScalarPI/3), sinf(-2*SK_ScalarPI/3)));
1157 verify_simple_inner_polygons(r, "\"pointy\" intersecting triangles", SkPath()
1158 .moveTo(0,-100).lineTo(-1e-6f,100).lineTo(1e-6f,100)
1159 .moveTo(-100,0).lineTo(100,1e-6f).lineTo(100,-1e-6f));
1160 verify_simple_inner_polygons(r, "overlapping rects with vertical collinear edges", SkPath()
1161 .moveTo(0,0).lineTo(0,2).lineTo(1,2).lineTo(1,0)
1162 .moveTo(0,1).lineTo(0,3).lineTo(1,3).lineTo(1,1));
1163 verify_simple_inner_polygons(r, "overlapping rects with horizontal collinear edges", SkPath()
1164 .lineTo(2,0).lineTo(2,1).lineTo(0,1)
1165 .moveTo(1,0).lineTo(3,0).lineTo(3,1).lineTo(1,1).close());
1166 for (int i = 0; i < (int)std::size(kNonEdgeAAPaths); ++i) {
1167 verify_simple_inner_polygons(r, SkStringPrintf("kNonEdgeAAPaths[%i]", i).c_str(),
1168 kNonEdgeAAPaths[i]());
1169 }
1170 SkRandom rand;
1171 for (int i = 0; i < 50; ++i) {
1172 auto randomPath = SkPath().moveTo(rand.nextF(), rand.nextF());
1173 for (int j = 0; j < i; ++j) {
1174 randomPath.lineTo(rand.nextF(), rand.nextF());
1175 }
1176 verify_simple_inner_polygons(r, SkStringPrintf("random_path_%i", i).c_str(), randomPath);
1177 }
1178}
1179
1180DEF_TEST(Triangulator_Crbug1262444, r) {
1181 SkPath path;
1182
1183 path.setFillType(SkPathFillType::kWinding);
1184 path.moveTo(SkBits2Float(0x3fe0633f), SkBits2Float(0x3d04a60d)); // 1.75303f, 0.0323849f
1185 path.cubicTo(SkBits2Float(0x3fe27540), SkBits2Float(0x3dff593f), SkBits2Float(0x3fe45241),
1186 SkBits2Float(0x3e5e2fbb), SkBits2Float(0x3fe55b41), SkBits2Float(
1187 0x3e9e596d)); // 1.7692f, 0.124682f, 1.78376f, 0.216979f, 1.79185f, 0.309276f
1188 path.cubicTo(SkBits2Float(0x3fe5fa41), SkBits2Float(0x3eb3e79c), SkBits2Float(0x3fe62f41),
1189 SkBits2Float(0x3ec975cb), SkBits2Float(0x3fe69941), SkBits2Float(
1190 0x3edfd837)); // 1.7967f, 0.351376f, 1.79832f, 0.393477f, 1.80155f, 0.437196f
1191 path.cubicTo(SkBits2Float(0x3fe70341), SkBits2Float(0x3f064e87), SkBits2Float(0x3fe6ce41),
1192 SkBits2Float(0x3f1cb0f2), SkBits2Float(0x3fe59041), SkBits2Float(
1193 0x3f33135e)); // 1.80479f, 0.524636f, 1.80317f, 0.612075f, 1.79346f, 0.699514f
1194 path.cubicTo(SkBits2Float(0x3fe48740), SkBits2Float(0x3f468ef5), SkBits2Float(0x3fe2df40),
1195 SkBits2Float(0x3f59a06d), SkBits2Float(0x3fe02e3f), SkBits2Float(
1196 0x3f6cb1e6)); // 1.78538f, 0.775619f, 1.77244f, 0.850104f, 1.75141f, 0.92459f
1197 path.cubicTo(SkBits2Float(0x3fde863f), SkBits2Float(0x3f78b759), SkBits2Float(0x3fdc743e),
1198 SkBits2Float(0x3f822957), SkBits2Float(0x3fd9c33e), SkBits2Float(
1199 0x3f87f701)); // 1.73847f, 0.971548f, 1.7223f, 1.01689f, 1.70127f, 1.06223f
1200 path.cubicTo(SkBits2Float(0x3fd98e3e), SkBits2Float(0x3f88611f), SkBits2Float(0x3fd9593e),
1201 SkBits2Float(0x3f88cb3e), SkBits2Float(0x3fd9243d), SkBits2Float(
1202 0x3f896a6b)); // 1.69965f, 1.06546f, 1.69804f, 1.0687f, 1.69642f, 1.07356f
1203 path.cubicTo(SkBits2Float(0x3fd63e3c), SkBits2Float(0x3f8fa234), SkBits2Float(0x3fd2ee3b),
1204 SkBits2Float(0x3f95d9fd), SkBits2Float(0x3fd2ee3b), SkBits2Float(
1205 0x3f9ce602)); // 1.67377f, 1.12214f, 1.6479f, 1.17071f, 1.6479f, 1.22577f
1206 path.cubicTo(SkBits2Float(0x3fd3233b), SkBits2Float(0x3f9cb0f3), SkBits2Float(0x3fd3583b),
1207 SkBits2Float(0x3f9cb0f3), SkBits2Float(0x3fd3c23c), SkBits2Float(
1208 0x3f9c7be4)); // 1.64951f, 1.22415f, 1.65113f, 1.22415f, 1.65437f, 1.22253f
1209 path.cubicTo(SkBits2Float(0x3fd3c23c), SkBits2Float(0x3f9cb0f3), SkBits2Float(0x3fd3c23c),
1210 SkBits2Float(0x3f9cb0f3), SkBits2Float(0x3fd3c23c), SkBits2Float(
1211 0x3f9ce602)); // 1.65437f, 1.22415f, 1.65437f, 1.22415f, 1.65437f, 1.22577f
1212 path.cubicTo(SkBits2Float(0x3fd5353c), SkBits2Float(0x3f9c46d4), SkBits2Float(0x3fd6dd3d),
1213 SkBits2Float(0x3f9bdcb6), SkBits2Float(0x3fd7b13d), SkBits2Float(
1214 0x3f9ad36a)); // 1.66569f, 1.22091f, 1.67863f, 1.21767f, 1.6851f, 1.20958f
1215 path.cubicTo(SkBits2Float(0x3fda623e), SkBits2Float(0x3f96ae3a), SkBits2Float(0x3fdca93f),
1216 SkBits2Float(0x3f921eeb), SkBits2Float(0x3fdf253f), SkBits2Float(
1217 0x3f8dc4ab)); // 1.70612f, 1.17719f, 1.72391f, 1.14157f, 1.74332f, 1.10756f
1218 path.cubicTo(SkBits2Float(0x3fe0983f), SkBits2Float(0x3f8b12e5), SkBits2Float(0x3fe1d640),
1219 SkBits2Float(0x3f87f700), SkBits2Float(0x3fe3b340), SkBits2Float(
1220 0x3f857a4a)); // 1.75465f, 1.08651f, 1.76435f, 1.06223f, 1.77891f, 1.04279f
1221 path.cubicTo(SkBits2Float(0x3fe48740), SkBits2Float(0x3f8470fe), SkBits2Float(0x3fe62f40),
1222 SkBits2Float(0x3f8470fe), SkBits2Float(0x3fe7d741), SkBits2Float(
1223 0x3f843bef)); // 1.78538f, 1.0347f, 1.79832f, 1.0347f, 1.81126f, 1.03308f
1224 path.cubicTo(SkBits2Float(0x3fe2aa40), SkBits2Float(0x3f943182), SkBits2Float(0x3fda623d),
1225 SkBits2Float(0x3fa2498e), SkBits2Float(0x3fceff3a), SkBits2Float(
1226 0x3fae4f01)); // 1.77082f, 1.15776f, 1.70612f, 1.26787f, 1.61716f, 1.36179f
1227 path.cubicTo(SkBits2Float(0x3fce6039), SkBits2Float(0x3faf233e), SkBits2Float(0x3fcd2239),
1228 SkBits2Float(0x3faf584d), SkBits2Float(0x3fcc1939), SkBits2Float(
1229 0x3fafc26b)); // 1.61231f, 1.36826f, 1.60261f, 1.36988f, 1.59452f, 1.37312f
1230 path.cubicTo(SkBits2Float(0x3fcc1939), SkBits2Float(0x3faff77a), SkBits2Float(0x3fcc1939),
1231 SkBits2Float(0x3faff77a), SkBits2Float(0x3fcc4e39), SkBits2Float(
1232 0x3fb02c89)); // 1.59452f, 1.37474f, 1.59452f, 1.37474f, 1.59614f, 1.37636f
1233 path.cubicTo(SkBits2Float(0x3fcc1939), SkBits2Float(0x3fb02c89), SkBits2Float(0x3fcc1939),
1234 SkBits2Float(0x3fb02c89), SkBits2Float(0x3fcbe439), SkBits2Float(
1235 0x3fb02c89)); // 1.59452f, 1.37636f, 1.59452f, 1.37636f, 1.5929f, 1.37636f
1236 path.cubicTo(SkBits2Float(0x3fcbe439), SkBits2Float(0x3fb20a12), SkBits2Float(0x3fcb4539),
1237 SkBits2Float(0x3fb37d7d), SkBits2Float(0x3fc99d39), SkBits2Float(
1238 0x3fb3b28c)); // 1.5929f, 1.39093f, 1.58805f, 1.40227f, 1.57511f, 1.40389f
1239 path.cubicTo(SkBits2Float(0x3fc93339), SkBits2Float(0x3fb3e79b), SkBits2Float(0x3fc8c938),
1240 SkBits2Float(0x3fb41caa), SkBits2Float(0x3fc7f538), SkBits2Float(
1241 0x3fb41caa)); // 1.57188f, 1.40551f, 1.56864f, 1.40712f, 1.56217f, 1.40712f
1242 path.cubicTo(SkBits2Float(0x3fc7f538), SkBits2Float(0x3fb3e79b), SkBits2Float(0x3fc7f538),
1243 SkBits2Float(0x3fb3e79b), SkBits2Float(0x3fc7f538), SkBits2Float(
1244 0x3fb3b28c)); // 1.56217f, 1.40551f, 1.56217f, 1.40551f, 1.56217f, 1.40389f
1245 path.lineTo(SkBits2Float(0x3fc7c038), SkBits2Float(0x3fb3b28c)); // 1.56055f, 1.40389f
1246 path.cubicTo(SkBits2Float(0x3fc7c038), SkBits2Float(0x3fb4f0e7), SkBits2Float(0x3fc7f538),
1247 SkBits2Float(0x3fb66452), SkBits2Float(0x3fc78b38), SkBits2Float(
1248 0x3fb76d9e)); // 1.56055f, 1.4136f, 1.56217f, 1.42494f, 1.55894f, 1.43303f
1249 path.cubicTo(SkBits2Float(0x3fc3d137), SkBits2Float(0x3fbe4495), SkBits2Float(0x3fbf4336),
1250 SkBits2Float(0x3fc4123e), SkBits2Float(0x3fb80434), SkBits2Float(
1251 0x3fc76331)); // 1.52982f, 1.48647f, 1.49424f, 1.53181f, 1.43763f, 1.55771f
1252 path.cubicTo(SkBits2Float(0x3fb47f33), SkBits2Float(0x3fc90bac), SkBits2Float(0x3fb19932),
1253 SkBits2Float(0x3fcb5353), SkBits2Float(0x3faf1d31), SkBits2Float(
1254 0x3fce6f37)); // 1.41013f, 1.57067f, 1.38749f, 1.58848f, 1.36808f, 1.61277f
1255 path.cubicTo(SkBits2Float(0x3fa4592e), SkBits2Float(0x3fdb13d7), SkBits2Float(0x3f974e2a),
1256 SkBits2Float(0x3fe53bc1), SkBits2Float(0x3f896f25), SkBits2Float(
1257 0x3fee5a5f)); // 1.28397f, 1.71154f, 1.18207f, 1.79089f, 1.0737f, 1.86213f
1258 path.cubicTo(SkBits2Float(0x3f6b883f), SkBits2Float(0x3ffb691f), SkBits2Float(0x3f42f434),
1259 SkBits2Float(0x400367b2), SkBits2Float(0x3f184e28), SkBits2Float(
1260 0x4008611f)); // 0.920048f, 1.96415f, 0.761539f, 2.0532f, 0.594943f, 2.13093f
1261 path.cubicTo(SkBits2Float(0x3f184e28), SkBits2Float(0x4008611f), SkBits2Float(0x3f17e428),
1262 SkBits2Float(0x4008611f), SkBits2Float(0x3f17e428), SkBits2Float(
1263 0x40087ba7)); // 0.594943f, 2.13093f, 0.593325f, 2.13093f, 0.593325f, 2.13255f
1264 path.cubicTo(SkBits2Float(0x3effc044), SkBits2Float(0x400b47f5), SkBits2Float(0x3ed08c36),
1265 SkBits2Float(0x400e2eca), SkBits2Float(0x3e9edc28), SkBits2Float(
1266 0x401090f9)); // 0.499514f, 2.17627f, 0.40732f, 2.22161f, 0.310273f, 2.25885f
1267 path.cubicTo(SkBits2Float(0x3e5a5832), SkBits2Float(0x4012f328), SkBits2Float(0x3de40030),
1268 SkBits2Float(0x4014811a), SkBits2Float(0x3c1a7f9e), SkBits2Float(
1269 0x40158a66)); // 0.213227f, 2.29609f, 0.111328f, 2.32038f, 0.00942984f, 2.33657f
1270 path.lineTo(SkBits2Float(0x3c1a7f9e), SkBits2Float(0x401bf73d)); // 0.00942984f, 2.43697f
1271 path.cubicTo(SkBits2Float(0x3dc98028), SkBits2Float(0x401b580f), SkBits2Float(0x3e3fd82e),
1272 SkBits2Float(0x401a694b), SkBits2Float(0x3e8ca424), SkBits2Float(
1273 0x40191068)); // 0.098389f, 2.42725f, 0.187348f, 2.41268f, 0.27469f, 2.39163f
1274 path.cubicTo(SkBits2Float(0x3e94ec27), SkBits2Float(0x4018db59), SkBits2Float(0x3e9d3429),
1275 SkBits2Float(0x40188bc2), SkBits2Float(0x3ea4a82b), SkBits2Float(
1276 0x401856b3)); // 0.290864f, 2.38839f, 0.307039f, 2.38353f, 0.321596f, 2.38029f
1277 path.cubicTo(SkBits2Float(0x3eae982e), SkBits2Float(0x4018071c), SkBits2Float(0x3eb95c31),
1278 SkBits2Float(0x40179cfe), SkBits2Float(0x3ec34c34), SkBits2Float(
1279 0x40174d67)); // 0.341005f, 2.37543f, 0.362031f, 2.36896f, 0.381441f, 2.3641f
1280 path.cubicTo(SkBits2Float(0x3ec9ec36), SkBits2Float(0x40171858), SkBits2Float(0x3ed08c38),
1281 SkBits2Float(0x4016c8c1), SkBits2Float(0x3ed8003a), SkBits2Float(
1282 0x401693b2)); // 0.39438f, 2.36086f, 0.40732f, 2.356f, 0.421877f, 2.35276f
1283 path.cubicTo(SkBits2Float(0x3eda7c3a), SkBits2Float(0x4016792a), SkBits2Float(0x3eddcc3c),
1284 SkBits2Float(0x40165ea3), SkBits2Float(0x3ee0483c), SkBits2Float(
1285 0x4016441b)); // 0.426729f, 2.35115f, 0.433199f, 2.34953f, 0.438051f, 2.34791f
1286 path.cubicTo(SkBits2Float(0x3ee2c43d), SkBits2Float(0x40162993), SkBits2Float(0x3ee5403e),
1287 SkBits2Float(0x40160f0c), SkBits2Float(0x3ee8903f), SkBits2Float(
1288 0x4015f484)); // 0.442903f, 2.34629f, 0.447756f, 2.34467f, 0.454226f, 2.34305f
1289 path.cubicTo(SkBits2Float(0x3f1c082a), SkBits2Float(0x4012be17), SkBits2Float(0x3f422036),
1290 SkBits2Float(0x400e63d8), SkBits2Float(0x3f66fa40), SkBits2Float(
1291 0x40096a6a)); // 0.6095f, 2.29285f, 0.758304f, 2.22484f, 0.902256f, 2.14712f
1292 path.cubicTo(SkBits2Float(0x3f6a4a41), SkBits2Float(0x4009004c), SkBits2Float(0x3f6d3042),
1293 SkBits2Float(0x4008962d), SkBits2Float(0x3f708043), SkBits2Float(
1294 0x40081187)); // 0.915196f, 2.14064f, 0.926518f, 2.13417f, 0.939457f, 2.12607f
1295 path.cubicTo(SkBits2Float(0x3f7efe47), SkBits2Float(0x4005feef), SkBits2Float(0x3f868925),
1296 SkBits2Float(0x4003b748), SkBits2Float(0x3f8d5e28), SkBits2Float(
1297 0x40015519)); // 0.996067f, 2.09368f, 1.05106f, 2.05806f, 1.10444f, 2.02082f
1298 path.cubicTo(SkBits2Float(0x3f97b82b), SkBits2Float(0x3ffb691d), SkBits2Float(0x3fa1a82e),
1299 SkBits2Float(0x3ff388da), SkBits2Float(0x3fab9830), SkBits2Float(
1300 0x3feb7389)); // 1.18531f, 1.96415f, 1.26294f, 1.90261f, 1.34058f, 1.83946f
1301 path.cubicTo(SkBits2Float(0x3fb20332), SkBits2Float(0x3fe6450c), SkBits2Float(0x3fb80434),
1302 SkBits2Float(0x3fe0e181), SkBits2Float(0x3fbd6635), SkBits2Float(
1303 0x3fda3f99)); // 1.39072f, 1.79898f, 1.43763f, 1.75688f, 1.47968f, 1.70507f
1304 path.cubicTo(SkBits2Float(0x3fbf4336), SkBits2Float(0x3fd7f7f2), SkBits2Float(0x3fc12037),
1305 SkBits2Float(0x3fd5b04b), SkBits2Float(0x3fc2fd36), SkBits2Float(
1306 0x3fd33394)); // 1.49424f, 1.68725f, 1.5088f, 1.66944f, 1.52335f, 1.65001f
1307 path.cubicTo(SkBits2Float(0x3fc5e337), SkBits2Float(0x3fcf7881), SkBits2Float(0x3fc8c938),
1308 SkBits2Float(0x3fcbbd70), SkBits2Float(0x3fcbaf38), SkBits2Float(
1309 0x3fc8025d)); // 1.546f, 1.62086f, 1.56864f, 1.59172f, 1.59128f, 1.56257f
1310 path.cubicTo(SkBits2Float(0x3fceff39), SkBits2Float(0x3fc3a81e), SkBits2Float(0x3fd2843b),
1311 SkBits2Float(0x3fbf18cf), SkBits2Float(0x3fd5d43b), SkBits2Float(
1312 0x3fbabe8f)); // 1.61716f, 1.52857f, 1.64466f, 1.49294f, 1.67054f, 1.45894f
1313 path.cubicTo(SkBits2Float(0x3fd8503c), SkBits2Float(0x3fb7a2ab), SkBits2Float(0x3fda973d),
1314 SkBits2Float(0x3fb486c7), SkBits2Float(0x3fdca93e), SkBits2Float(
1315 0x3fb135d3)); // 1.68995f, 1.43465f, 1.70774f, 1.41036f, 1.72391f, 1.38446f
1316 path.cubicTo(SkBits2Float(0x3fe5c541), SkBits2Float(0x3fa2b3aa), SkBits2Float(0x3feb5c42),
1317 SkBits2Float(0x3f92be16), SkBits2Float(0x3ff15d44), SkBits2Float(
1318 0x3f82c882)); // 1.79508f, 1.27111f, 1.83875f, 1.14643f, 1.88566f, 1.02174f
1319 path.cubicTo(SkBits2Float(0x3ff1fc44), SkBits2Float(0x3f812008), SkBits2Float(0x3ff23144),
1320 SkBits2Float(0x3f7e1adf), SkBits2Float(0x3ff29b44), SkBits2Float(
1321 0x3f7a5fcc)); // 1.89051f, 1.00879f, 1.89213f, 0.992598f, 1.89536f, 0.978024f
1322 path.cubicTo(SkBits2Float(0x3ff47845), SkBits2Float(0x3f5fd830), SkBits2Float(0x3ff65545),
1323 SkBits2Float(0x3f455094), SkBits2Float(0x3ff6bf45), SkBits2Float(
1324 0x3f2a5ed9)); // 1.90992f, 0.874393f, 1.92448f, 0.770761f, 1.92771f, 0.66551f
1325 path.cubicTo(SkBits2Float(0x3ff33a44), SkBits2Float(0x3f0d5a87), SkBits2Float(0x3ff08943),
1326 SkBits2Float(0x3edf03ee), SkBits2Float(0x3fee7743), SkBits2Float(
1327 0x3ea352cf)); // 1.90022f, 0.552163f, 1.87919f, 0.435577f, 1.86301f, 0.318991f
1328 path.cubicTo(SkBits2Float(0x3feccf42), SkBits2Float(0x3e5c872d), SkBits2Float(0x3feb9142),
1329 SkBits2Float(0x3de4d179), SkBits2Float(0x3feaf242), SkBits2Float(
1330 0x3c04a4ae)); // 1.85008f, 0.215359f, 1.84037f, 0.111728f, 1.83552f, 0.0080959f
1331 path.lineTo(SkBits2Float(0x3fe02e3f), SkBits2Float(0x3c04a4ae)); // 1.75141f, 0.0080959f
1332 path.cubicTo(SkBits2Float(0x3fdff93f), SkBits2Float(0x3c6ec47e), SkBits2Float(0x3fe02e3f),
1333 SkBits2Float(0x3cb9b545), SkBits2Float(0x3fe0633f), SkBits2Float(
1334 0x3d04a60d)); // 1.74979f, 0.0145732f, 1.75141f, 0.0226694f, 1.75303f, 0.0323849f
1335 path.close();
1336 path.moveTo(SkBits2Float(0x3fe97f42), SkBits2Float(0x3f7b9e2e)); // 1.8242f, 0.982882f
1337 path.cubicTo(SkBits2Float(0x3fe91542), SkBits2Float(0x3f7eef21), SkBits2Float(0x3fe87642),
1338 SkBits2Float(0x3f81551a), SkBits2Float(0x3fe7d741), SkBits2Float(
1339 0x3f82fd94)); // 1.82096f, 0.995836f, 1.81611f, 1.01041f, 1.81126f, 1.02336f
1340 path.cubicTo(SkBits2Float(0x3fe6ce41), SkBits2Float(0x3f81bf39), SkBits2Float(0x3fe66441),
1341 SkBits2Float(0x3f8080dd), SkBits2Float(0x3fe66441), SkBits2Float(
1342 0x3f7e1ae4)); // 1.80317f, 1.01365f, 1.79993f, 1.00393f, 1.79993f, 0.992598f
1343 path.cubicTo(SkBits2Float(0x3fe66441), SkBits2Float(0x3f7c726a), SkBits2Float(0x3fe69941),
1344 SkBits2Float(0x3f7b340e), SkBits2Float(0x3fe6ce41), SkBits2Float(
1345 0x3f798b95)); // 1.79993f, 0.986121f, 1.80155f, 0.981263f, 1.80317f, 0.974786f
1346 path.cubicTo(SkBits2Float(0x3fe70341), SkBits2Float(0x3f78b758), SkBits2Float(0x3fe76d41),
1347 SkBits2Float(0x3f770edf), SkBits2Float(0x3fe7d741), SkBits2Float(
1348 0x3f770edf)); // 1.80479f, 0.971548f, 1.80802f, 0.965071f, 1.81126f, 0.965071f
1349 path.cubicTo(SkBits2Float(0x3fe84141), SkBits2Float(0x3f770edf), SkBits2Float(0x3fe8ab42),
1350 SkBits2Float(0x3f770edf), SkBits2Float(0x3fe8e041), SkBits2Float(
1351 0x3f7778fd)); // 1.81449f, 0.965071f, 1.81773f, 0.965071f, 1.81934f, 0.96669f
1352 path.cubicTo(SkBits2Float(0x3fe97f42), SkBits2Float(0x3f77e31b), SkBits2Float(0x3fe9e942),
1353 SkBits2Float(0x3f798b95), SkBits2Float(0x3fe97f42), SkBits2Float(
1354 0x3f7b9e2e)); // 1.8242f, 0.968309f, 1.82743f, 0.974786f, 1.8242f, 0.982882f
1355 path.close();
1356
1357 float kTol = 0.25f;
1358 SkRect clipBounds = SkRect::MakeLTRB(0, 0, 14, 14);
1359 SimplerVertexAllocator alloc;
1360
1361 int vertexCount = GrAATriangulator::PathToAATriangles(path, kTol, clipBounds, &alloc);
1362 REPORTER_ASSERT(r, vertexCount == 0);
1363}
1364
1365DEF_TEST(Triangulator_Crbug337080025, r) {
1366 SkPath path;
1367
1368 path.setFillType(SkPathFillType::kWinding);
1369 path.moveTo(SkBits2Float(0x71ec7478),
1370 SkBits2Float(0xe18cc1ac)); // 2.34173646e+30f, -3.24562462e+20f
1371 path.lineTo(SkBits2Float(0x71ec7478),
1372 SkBits2Float(0xe189ac7b)); // 2.34173646e+30f, -3.17454058e+20f
1373 path.lineTo(SkBits2Float(0x71ec7478),
1374 SkBits2Float(0x618fd6dd)); // 2.34173646e+30f, 3.31670867e+20f
1375 path.lineTo(SkBits2Float(0x71ec7478),
1376 SkBits2Float(0x6192ec0e)); // 2.34173646e+30f, 3.38779271e+20f
1377 path.conicTo(SkBits2Float(0x71ec7478),
1378 SkBits2Float(0x71ec7478),
1379 SkBits2Float(0xe18cc1ac),
1380 SkBits2Float(0x71ec7478),
1381 SkBits2Float(0x3f3504f3)); // 2.34173646e+30f, 2.34173646e+30f,
1382 // -3.24562462e+20f, 2.34173646e+30f, 0.707106769f
1383 path.conicTo(SkBits2Float(0xf1ec7478),
1384 SkBits2Float(0x71ec7478),
1385 SkBits2Float(0xf1ec7478),
1386 SkBits2Float(0x6192ec0e),
1387 SkBits2Float(0x3f3504f3)); // -2.34173646e+30f, 2.34173646e+30f,
1388 // -2.34173646e+30f, 3.38779271e+20f, 0.707106769f
1389 path.lineTo(SkBits2Float(0xf1ec7478),
1390 SkBits2Float(0x618fd6dd)); // -2.34173646e+30f, 3.31670867e+20f
1391 path.lineTo(SkBits2Float(0xf1ec7478),
1392 SkBits2Float(0xe189ac7b)); // -2.34173646e+30f, -3.17454058e+20f
1393 path.lineTo(SkBits2Float(0xf1ec7478),
1394 SkBits2Float(0xe18cc1ac)); // -2.34173646e+30f, -3.24562462e+20f
1395 path.conicTo(SkBits2Float(0xf1ec7478),
1396 SkBits2Float(0xf1ec7478),
1397 SkBits2Float(0x4e775b1f),
1398 SkBits2Float(0xf1ec7478),
1399 SkBits2Float(0x3f3504f3)); // -2.34173646e+30f, -2.34173646e+30f, 1.03748602e+09f,
1400 // -2.34173646e+30f, 0.707106769f
1401 path.lineTo(SkBits2Float(0x4e775b20),
1402 SkBits2Float(0xf1ec7478)); // 1.03748608e+09f, -2.34173646e+30f
1403 path.lineTo(SkBits2Float(0x71ec7478),
1404 SkBits2Float(0xe18cc1ac)); // 2.34173646e+30f, -3.24562462e+20f
1405 path.close();
1406 path.moveTo(SkBits2Float(0xf1ec7478),
1407 SkBits2Float(0x618cc1ac)); // -2.34173646e+30f, 3.24562462e+20f
1408 path.lineTo(SkBits2Float(0x4e775b20),
1409 SkBits2Float(0x02230001)); // 1.03748608e+09f, 1.19753498e-37f
1410 path.lineTo(SkBits2Float(0x4e775b20),
1411 SkBits2Float(0x71ec7478)); // 1.03748608e+09f, 2.34173646e+30f
1412 path.lineTo(SkBits2Float(0x4e775b1f),
1413 SkBits2Float(0x71ec7478)); // 1.03748602e+09f, 2.34173646e+30f
1414 path.lineTo(SkBits2Float(0x4e775b1f), SkBits2Float(0x00000000)); // 1.03748602e+09f, 0
1415 path.lineTo(SkBits2Float(0x71ec7478),
1416 SkBits2Float(0x618cc1ac)); // 2.34173646e+30f, 3.24562462e+20f
1417 path.lineTo(SkBits2Float(0x71ec7478),
1418 SkBits2Float(0x618fd6dd)); // 2.34173646e+30f, 3.31670867e+20f
1419 path.lineTo(SkBits2Float(0x4c476265), SkBits2Float(0x5ec54c47)); // 52267412, 7.10840809e+18f
1420 path.lineTo(SkBits2Float(0x71ec7478),
1421 SkBits2Float(0xe189ac7b)); // 2.34173646e+30f, -3.17454058e+20f
1422 path.lineTo(SkBits2Float(0x71ec7478),
1423 SkBits2Float(0xe186974a)); // 2.34173646e+30f, -3.10345654e+20f
1424 path.lineTo(SkBits2Float(0x4e775b20),
1425 SkBits2Float(0x5f454c47)); // 1.03748608e+09f, 1.42168162e+19f
1426 path.lineTo(SkBits2Float(0xf1ec7478),
1427 SkBits2Float(0xe186974a)); // -2.34173646e+30f, -3.10345654e+20f
1428 path.lineTo(SkBits2Float(0xf1ec7478),
1429 SkBits2Float(0xe189ac7b)); // -2.34173646e+30f, -3.17454058e+20f
1430 path.lineTo(SkBits2Float(0x4ef1200d),
1431 SkBits2Float(0x5ec54c47)); // 2.02270477e+09f, 7.10840809e+18f
1432 path.lineTo(SkBits2Float(0xf1ec7478),
1433 SkBits2Float(0x618fd6dd)); // -2.34173646e+30f, 3.31670867e+20f
1434 path.lineTo(SkBits2Float(0xf1ec7478),
1435 SkBits2Float(0x618cc1ac)); // -2.34173646e+30f, 3.24562462e+20f
1436 path.close();
1437 path.moveTo(SkBits2Float(0x4e775b20),
1438 SkBits2Float(0x02230001)); // 1.03748608e+09f, 1.19753498e-37f
1439 path.conicTo(SkBits2Float(0x4ef1200d),
1440 SkBits2Float(0x02230001),
1441 SkBits2Float(0x4ef1200d),
1442 SkBits2Float(0x5ec54c47),
1443 SkBits2Float(0x3f3504f3)); // 2.02270477e+09f, 1.19753498e-37f, 2.02270477e+09f,
1444 // 7.10840809e+18f, 0.707106769f
1445 path.conicTo(SkBits2Float(0x4ef1200d),
1446 SkBits2Float(0x5f454c47),
1447 SkBits2Float(0x4e775b20),
1448 SkBits2Float(0x5f454c47),
1449 SkBits2Float(0x3f3504f3)); // 2.02270477e+09f, 1.42168162e+19f, 1.03748608e+09f,
1450 // 1.42168162e+19f,0.707106769f
1451 path.conicTo(SkBits2Float(0x4c476265),
1452 SkBits2Float(0x5f454c47),
1453 SkBits2Float(0x4c476265),
1454 SkBits2Float(0x5ec54c47),
1455 SkBits2Float(0x3f3504f3)); // 52267412, 1.42168162e+19f, 52267412,
1456 // 7.10840809e+18f, 0.707106769f
1457 path.conicTo(SkBits2Float(0x4c476265),
1458 SkBits2Float(0x02230001),
1459 SkBits2Float(0x4e775b20),
1460 SkBits2Float(0x02230001),
1461 SkBits2Float(0x3f3504f3)); // 52267412, 1.19753498e-37f, 1.03748608e+09f,
1462 // 1.19753498e-37f, 0.707106769f
1463 path.close();
1464
1465 SkRect clipBounds = SkRect::MakeLTRB(0, 0, 256, 256);
1466 SimplerVertexAllocator alloc;
1467
1468 int vertexCount = GrAATriangulator::PathToAATriangles(
1469 path, GrPathUtils::kDefaultTolerance, clipBounds, &alloc);
1470 REPORTER_ASSERT(r, vertexCount == 0);
1471}
1472
1473#endif // SK_ENABLE_OPTIMIZE_SIZE
reporter
Definition: FontMgrTest.cpp:39
int count
Definition: FontMgrTest.cpp:50
GrAAType
Definition: GrTypesPriv.h:200
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
static float SkBits2Float(uint32_t bits)
Definition: SkFloatBits.h:48
SkPathFillType
Definition: SkPathTypes.h:11
@ kClose
SkPath::RawIter returns 0 points.
@ kCubic
SkPath::RawIter returns 4 points.
@ kConic
SkPath::RawIter returns 3 points + 1 weight.
@ kQuad
SkPath::RawIter returns 3 points.
@ kMove
SkPath::RawIter returns 1 point.
@ kLine
SkPath::RawIter returns 2 points.
#define SK_ScalarPI
Definition: SkScalar.h:21
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
#define ERRORF(r,...)
Definition: Test.h:293
#define DEF_GANESH_TEST_FOR_ALL_CONTEXTS(name, reporter, context_info, ctsEnforcement)
Definition: Test.h:431
static void add_edge(EdgeMap &edgeMap, SkPoint p0, SkPoint p1)
static bool operator<(const Edge &a, const Edge &b)
static EdgeMap simplify(const EdgeMap &edges, SkPathFillType fillType)
CreatePathFn kNonEdgeAAPaths[]
DEF_TEST(GrInnerFanTriangulator, r)
static void verify_simple_inner_polygons(skiatest::Reporter *r, const char *shapeName, SkPath path)
static void add_tri_edges(skiatest::Reporter *r, EdgeMap &edgeMap, const SkPoint pts[3])
std::map< Edge, int > EdgeMap
SkPath(*)() CreatePathFn
static int PathToAATriangles(const SkPath &path, SkScalar tolerance, const SkRect &clipBounds, GrEagerVertexAllocator *vertexAllocator)
int pathToTriangles(GrEagerVertexAllocator *vertexAlloc, BreadcrumbTriangleList *breadcrumbList, bool *isLinear)
static const GrXPFactory * Get(SkBlendMode blendMode)
static constexpr int kArenaDefaultChunkSize
static sk_sp< SkShader > MakeLinear(const SkPoint pts[2], const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
Definition: SkPath.h:59
SkPath & moveTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:688
SkPath & lineTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:728
float nextF()
Definition: SkRandom.h:55
T * get() const
Definition: SkRefCnt.h:303
bool drawPath(const DrawPathArgs &args)
static std::unique_ptr< SurfaceDrawContext > Make(GrRecordingContext *, GrColorType, sk_sp< GrSurfaceProxy >, sk_sp< SkColorSpace >, GrSurfaceOrigin, const SkSurfaceProps &)
const Paint & paint
Definition: color_source.cc:38
static bool b
struct MyStruct a[10]
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
std::unique_ptr< GrFragmentProcessor > Make(const SkMaskFilter *maskfilter, const GrFPArgs &args, const SkMatrix &ctm)
static const SkScalar kDefaultTolerance
Definition: GrPathUtils.h:32
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
PODArray< SkColor > colors
Definition: SkRecords.h:276
SkPath make_star(const SkRect &bounds, int numPts, int step)
Definition: ToolUtils.cpp:269
const uint32_t fp
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: switches.h:57
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition: SkVx.h:707
static void test_path(SkCanvas *canvas, const SkPath &path)
Definition: pathreverse.cpp:53
SkScalar w
static const GrUserStencilSettings & kUnused
Definition: SkRect.h:32
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition: SkRect.h:56
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646