Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
PathOpsAsWindingTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 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
11#include "include/core/SkRect.h"
16#include "tests/Test.h"
17
18#include <initializer_list>
19#include <string>
20
22 SkPath path;
23 bool reverse = SkPathDirection::kCCW == dir;
24 switch (verb) {
26 path.addRect(rect, dir);
27 reverse = false;
28 break;
30 path.moveTo(rect.centerX(), rect.fTop);
31 path.quadTo(rect.fRight, rect.fTop, rect.fRight, rect.centerY());
32 path.quadTo(rect.fRight, rect.fBottom, rect.centerX(), rect.fBottom);
33 path.quadTo(rect.fLeft, rect.fBottom, rect.fLeft, rect.centerY());
34 path.quadTo(rect.fLeft, rect.fTop, rect.centerX(), rect.fTop);
35 break;
37 path.addCircle(rect.centerX(), rect.centerY(), rect.width() / 2, dir);
38 reverse = false;
39 break;
41 SkScalar aX14 = rect.fLeft + rect.width() * 1 / 4;
42 SkScalar aX34 = rect.fLeft + rect.width() * 3 / 4;
43 SkScalar aY14 = rect.fTop + rect.height() * 1 / 4;
44 SkScalar aY34 = rect.fTop + rect.height() * 3 / 4;
45 path.moveTo(rect.centerX(), rect.fTop);
46 path.cubicTo(aX34, rect.fTop, rect.fRight, aY14, rect.fRight, rect.centerY());
47 path.cubicTo(rect.fRight, aY34, aX34, rect.fBottom, rect.centerX(), rect.fBottom);
48 path.cubicTo(aX14, rect.fBottom, rect.fLeft, aY34, rect.fLeft, rect.centerY());
49 path.cubicTo(rect.fLeft, aY14, aX14, rect.fTop, rect.centerX(), rect.fTop);
50 } break;
51 default:
52 SkASSERT(0);
53 }
54 if (reverse) {
55 SkPath temp;
56 temp.reverseAddPath(path);
57 path.swap(temp);
58 }
59 return path;
60}
61
63 SkPath path;
64 path.setFillType(SkPathFillType::kWinding);
65 path.moveTo(375, -30);
66 path.cubicTo(578, -30, 749, 176, 749, 422);
67 path.cubicTo(749, 583, 666, 706, 518, 765);
68 path.lineTo(163, 611);
69 path.lineTo(163, 579);
70 path.lineTo(405, 684);
71 path.cubicTo(551, 609, 645, 468, 645, 322);
72 path.cubicTo(645, 183, 563, 82, 450, 82);
73 path.cubicTo(303, 82, 179, 249, 179, 446);
74 path.cubicTo(179, 579, 235, 689, 341, 768);
75 path.lineTo(327, 786);
76 path.cubicTo(165, 717, 56, 536, 56, 335);
77 path.cubicTo(56, 125, 192, -30, 375, -30);
78 path.close();
79 path.moveTo(214, 225);
80 path.cubicTo(333, 248, 396, 311, 396, 405);
81 path.lineTo(396, 695);
82 path.lineTo(267, 641);
83 path.lineTo(267, 395);
84 path.cubicTo(267, 324, 249, 285, 201, 254);
85 path.cubicTo(201, 254, 214, 225, 214, 225);
86 path.close();
87 path.moveTo(682, -106);
88 path.lineTo(832, 12);
89 path.lineTo(813, 33);
90 path.lineTo(772, 0);
91 path.cubicTo(716, 29, 668, 76, 628, 140);
92 path.lineTo(527, 44);
93 path.cubicTo(575, -26, 628, -77, 682, -106);
94 path.close();
95 path.moveTo(450, 59);
96 path.lineTo(480, 59);
97 path.lineTo(480, 678);
98 path.lineTo(450, 678);
99 path.cubicTo(450, 678, 450, 59, 450, 59);
100 path.close();
101 path.moveTo(463, 374);
102 path.lineTo(633, 459);
103 path.lineTo(633, 490);
104 path.lineTo(463, 406);
105 path.cubicTo(463, 406, 463, 374, 463, 374);
106 path.close();
107 path.moveTo(463, 269);
108 path.lineTo(667, 372);
109 path.lineTo(667, 403);
110 path.lineTo(463, 301);
111 path.cubicTo(463, 301, 463, 269, 463, 269);
112 path.close();
113
116 path2.moveTo(-83.5464f, 188);
117 path2.cubicTo(-83.5464f, 184.285f, -84.8599f, 181.114f, -87.4868f, 178.487f);
118 path2.cubicTo(-90.1138f, 175.86f, -93.2849f, 174.546f, -97, 174.546f);
119 path2.cubicTo(-100.715f, 174.546f, -103.886f, 175.86f, -106.513f, 178.487f);
120 path2.cubicTo(-109.14f, 181.114f, -110.454f, 184.285f, -110.454f, 188);
121 path2.cubicTo(-110.454f, 191.715f, -109.14f, 194.886f, -106.513f, 197.513f);
122 path2.cubicTo(-103.886f, 200.14f, -100.715f, 201.454f, -97, 201.454f);
123 path2.cubicTo(-93.2849f, 201.454f, -90.1138f, 200.14f, -87.4868f, 197.513f);
124 path2.cubicTo(-84.8599f, 194.886f, -83.5464f, 191.715f, -83.5464f, 188);
125 path2.close();
126
127 SkPath opResult;
128 Op(path, path2, kDifference_SkPathOp, &opResult);
129
130 SkPath winding;
131 REPORTER_ASSERT(reporter, AsWinding(opResult, &winding));
133
135 Op(winding, opResult, kXOR_SkPathOp, &difference);
137}
138
140 SkPath path;
141 path.setFillType(SkPathFillType::kWinding);
142 path.moveTo(375, -30);
143 path.cubicTo(578, -30, 749, 176, 749, 422);
144 path.cubicTo(749, 583, 666, 706, 518, 765);
145 path.lineTo(163, 611);
146 path.lineTo(163, 579);
147 path.lineTo(405, 684);
148 path.cubicTo(551, 609, 645, 468, 645, 322);
149 path.cubicTo(645, 183, 563, 82, 450, 82);
150 path.cubicTo(303, 82, 179, 249, 179, 446);
151 path.cubicTo(179, 579, 235, 689, 341, 768);
152 path.lineTo(327, 786);
153 path.cubicTo(165, 717, 56, 536, 56, 335);
154 path.cubicTo(56, 125, 192, -30, 375, -30);
155 path.close();
156 path.moveTo(214, 225);
157 path.cubicTo(333, 248, 396, 311, 396, 405);
158 path.lineTo(396, 695);
159 path.lineTo(267, 641);
160 path.lineTo(267, 395);
161 path.cubicTo(267, 324, 249, 285, 201, 254);
162 path.cubicTo(201, 254, 214, 225, 214, 225);
163 path.close();
164 path.moveTo(682, -106);
165 path.lineTo(832, 12);
166 path.lineTo(813, 33);
167 path.lineTo(772, 0);
168 path.cubicTo(716, 29, 668, 76, 628, 140);
169 path.lineTo(527, 44);
170 path.cubicTo(575, -26, 628, -77, 682, -106);
171 path.close();
172 path.moveTo(450, 59);
173 path.lineTo(480, 59);
174 path.lineTo(480, 678);
175 path.lineTo(450, 678);
176 path.cubicTo(450, 678, 450, 59, 450, 59);
177 path.close();
178 path.moveTo(463, 374);
179 path.lineTo(633, 459);
180 path.lineTo(633, 490);
181 path.lineTo(463, 406);
182 path.cubicTo(463, 406, 463, 374, 463, 374);
183 path.close();
184 path.moveTo(463, 269);
185 path.lineTo(667, 372);
186 path.lineTo(667, 403);
187 path.lineTo(463, 301);
188 path.cubicTo(463, 301, 463, 269, 463, 269);
189 path.close();
190
193 path2.moveTo(269.134f, 71.3392f);
194 path2.cubicTo(269.134f, 67.6241f, 267.82f, 64.453f, 265.193f, 61.826f);
195 path2.cubicTo(262.566f, 59.1991f, 259.395f, 57.8856f, 255.68f, 57.8856f);
196 path2.cubicTo(251.965f, 57.8856f, 248.794f, 59.1991f, 246.167f, 61.826f);
197 path2.cubicTo(243.54f, 64.453f, 242.226f, 67.6241f, 242.226f, 71.3392f);
198 path2.cubicTo(242.226f, 75.0543f, 243.54f, 78.2255f, 246.167f, 80.8524f);
199 path2.cubicTo(248.794f, 83.4794f, 251.965f, 84.7928f, 255.68f, 84.7928f);
200 path2.cubicTo(259.395f, 84.7928f, 262.566f, 83.4794f, 265.193f, 80.8524f);
201 path2.cubicTo(267.82f, 78.2255f, 269.134f, 75.0543f, 269.134f, 71.3392f);
202 path2.close();
203
204 SkPath opResult;
205 Op(path, path2, kDifference_SkPathOp, &opResult);
206
207 // This produces the correct result in all the cases I've tried.
208 // So it appears to be a winding issue.
209 // canvas->drawPath(opResult, p);
210
211 SkPath winding;
213 REPORTER_ASSERT(reporter, AsWinding(opResult, &winding));
215
217 Op(winding, opResult, kXOR_SkPathOp, &difference);
219}
220
222 SkPath path;
223 path.setFillType(SkPathFillType::kWinding);
224 path.moveTo(375, -30);
225 path.cubicTo(578, -30, 749, 176, 749, 422);
226 path.cubicTo(749, 583, 666, 706, 518, 765);
227 path.lineTo(163, 611);
228 path.lineTo(163, 579);
229 path.lineTo(405, 684);
230 path.cubicTo(551, 609, 645, 468, 645, 322);
231 path.cubicTo(645, 183, 563, 82, 450, 82);
232 path.cubicTo(303, 82, 179, 249, 179, 446);
233 path.cubicTo(179, 579, 235, 689, 341, 768);
234 path.lineTo(327, 786);
235 path.cubicTo(165, 717, 56, 536, 56, 335);
236 path.cubicTo(56, 125, 192, -30, 375, -30);
237 path.close();
238 path.moveTo(214, 225);
239 path.cubicTo(333, 248, 396, 311, 396, 405);
240 path.lineTo(396, 695);
241 path.lineTo(267, 641);
242 path.lineTo(267, 395);
243 path.cubicTo(267, 324, 249, 285, 201, 254);
244 path.cubicTo(201, 254, 214, 225, 214, 225);
245 path.close();
246 path.moveTo(682, -106);
247 path.lineTo(832, 12);
248 path.lineTo(813, 33);
249 path.lineTo(772, 0);
250 path.cubicTo(716, 29, 668, 76, 628, 140);
251 path.lineTo(527, 44);
252 path.cubicTo(575, -26, 628, -77, 682, -106);
253 path.close();
254 path.moveTo(450, 59);
255 path.lineTo(480, 59);
256 path.lineTo(480, 678);
257 path.lineTo(450, 678);
258 path.cubicTo(450, 678, 450, 59, 450, 59);
259 path.close();
260 path.moveTo(463, 374);
261 path.lineTo(633, 459);
262 path.lineTo(633, 490);
263 path.lineTo(463, 406);
264 path.cubicTo(463, 406, 463, 374, 463, 374);
265 path.close();
266 path.moveTo(463, 269);
267 path.lineTo(667, 372);
268 path.lineTo(667, 403);
269 path.lineTo(463, 301);
270 path.cubicTo(463, 301, 463, 269, 463, 269);
271 path.close();
272
275 path2.moveTo(492.041f, 525.339f);
276 path2.cubicTo(492.041f, 521.624f, 490.727f, 518.453f, 488.1f, 515.826f);
277 path2.cubicTo(485.473f, 513.199f, 482.302f, 511.886f, 478.587f, 511.886f);
278 path2.cubicTo(474.872f, 511.886f, 471.701f, 513.199f, 469.074f, 515.826f);
279 path2.cubicTo(466.447f, 518.453f, 465.134f, 521.624f, 465.134f, 525.339f);
280 path2.cubicTo(465.134f, 529.054f, 466.447f, 532.226f, 469.074f, 534.853f);
281 path2.cubicTo(471.701f, 537.479f, 474.872f, 538.793f, 478.587f, 538.793f);
282 path2.cubicTo(482.302f, 538.793f, 485.473f, 537.479f, 488.1f, 534.853f);
283 path2.cubicTo(490.727f, 532.226f, 492.041f, 529.054f, 492.041f, 525.339f);
284 path2.close();
285
286 SkPath opResult;
287 Op(path, path2, kDifference_SkPathOp, &opResult);
288
289 SkPath winding;
291 REPORTER_ASSERT(reporter, AsWinding(opResult, &winding));
293
295 Op(winding, opResult, kXOR_SkPathOp, &difference);
297}
298
300 for (int moveX = 199; moveX <= 201; ++moveX) {
301 for (int moveY = 299; moveY <= 301; ++moveY) {
302 for (int lineX = 199; lineX <= 201; ++lineX) {
303 for (int lineY = 199; lineY <= 201; ++lineY) {
304 SkPath path;
305 path.setFillType(SkPathFillType::kWinding);
306 path.addCircle(250, 250, 150);
307
310 path2.moveTo(moveX, moveY); // 200, 300 works... But not 200, 301!!
311 path2.lineTo(lineX, lineY); // 200, 200 works... But not 199, 200!!
312 path2.lineTo(300, 300);
313 path2.close();
314
315 SkPath opResult;
316 Op(path, path2, kDifference_SkPathOp, &opResult);
317
318 SkPath winding;
319 REPORTER_ASSERT(reporter, AsWinding(opResult, &winding));
321
323 Op(winding, opResult, kXOR_SkPathOp, &difference);
325 }
326 }
327 }
328 }
329}
330
332 for (int moveX = 199; moveX <= 201; ++moveX) {
333 for (int moveY = 299; moveY <= 301; ++moveY) {
334 for (int lineX = 199; lineX <= 201; ++lineX) {
335 for (int lineY = 199; lineY <= 201; ++lineY) {
336 SkPath path;
337 path.setFillType(SkPathFillType::kWinding);
338 path.addRect(100, 100, 400, 400);
339
342 path2.moveTo(moveX, moveY);
343 path2.lineTo(lineX, lineY); // 200, 200 works... But not 199, 200!!
344 path2.lineTo(300, 300);
345 path2.close();
346
347 SkPath opResult;
348 Op(path, path2, kDifference_SkPathOp, &opResult);
349
350 SkPath winding;
351 REPORTER_ASSERT(reporter, AsWinding(opResult, &winding));
353
355 Op(winding, opResult, kXOR_SkPathOp, &difference);
357 }
358 }
359 }
360 }
361}
362
364 std::string originalPathStr =
365 "M5.93 -3.12C5.93 -5.03 4.73 -6.06 3.5 -6.06C2.67 -6.06 1.98 -5.59 1.76 -5.34L1.67 "
366 "-5.93L0.75 -5.93L0.75 2.23L1.87 2.04L1.87 -0.12C2.12 -0.03 2.62 0.07 3.18 0.07C4.57 "
367 "0.07 5.93 -1.06 5.93 -3.12ZM4.81 -3.09C4.81 -1.51 4.18 -0.85 3.17 -0.85C2.57 -0.85 "
368 "2.15 -0.98 1.87 -1.12L1.87 -4.15C2.34 -4.73 2.75 -5.09 3.42 -5.09C4.31 -5.09 4.81 "
369 "-4.46 4.81 -3.09Z";
370
371 SkPath path;
372 SkParsePath::FromSVGString(originalPathStr.c_str(), &path);
373
374 SkPath simplifiedPath;
375 Simplify(path, &simplifiedPath);
376
377 SkPath windingPath;
378 REPORTER_ASSERT(reporter, AsWinding(simplifiedPath, &windingPath));
380
382 Op(windingPath, simplifiedPath, kXOR_SkPathOp, &difference);
384}
385
387 std::string originalPathStr =
388 "M4 0"
389 "L0 0"
390 "L0 5"
391 "L4 4"
392 "Z"
393 "M3 3"
394 "L1 3"
395 "L1 1"
396 "L3 1"
397 "Z";
398
399 SkPath path;
400 SkParsePath::FromSVGString(originalPathStr.c_str(), &path);
401
402 SkPath simplifiedPath;
403 Simplify(path, &simplifiedPath);
404
405 SkPath windingPath;
406 REPORTER_ASSERT(reporter, AsWinding(simplifiedPath, &windingPath));
408
410 Op(windingPath, simplifiedPath, kXOR_SkPathOp, &difference);
412}
413
415 std::string originalPathStr =
416 "M4 0"
417 "L0 0"
418 "L0 4"
419 "L4 4"
420 "Z"
421 "M3 3"
422 "L1 3"
423 "L1 1"
424 "L3 1"
425 "Z";
426
427 SkPath path;
428 SkParsePath::FromSVGString(originalPathStr.c_str(), &path);
429
430 SkPath simplifiedPath;
431 Simplify(path, &simplifiedPath);
432
433 SkPath windingPath;
434 REPORTER_ASSERT(reporter, AsWinding(simplifiedPath, &windingPath));
436
438 Op(windingPath, simplifiedPath, kXOR_SkPathOp, &difference);
440}
441
442DEF_TEST(PathOpsAsWinding, reporter) {
444 test.addRect({1, 2, 3, 4});
445 // if test is winding
448 // if test is empty
449 test.reset();
450 test.setFillType(SkPathFillType::kEvenOdd);
452 REPORTER_ASSERT(reporter, result.isEmpty());
454 // if test is convex
455 test.addCircle(5, 5, 10);
457 REPORTER_ASSERT(reporter, result.isConvex());
458 test.setFillType(SkPathFillType::kWinding);
460 // if test has infinity
461 test.reset();
462 test.addRect({1, 2, 3, SK_ScalarInfinity});
463 test.setFillType(SkPathFillType::kEvenOdd);
465 // if test has only one contour
466 test.reset();
467 SkPoint ell[] = {{0, 0}, {4, 0}, {4, 1}, {1, 1}, {1, 4}, {0, 4}};
468 test.addPoly(ell, std::size(ell), true);
469 test.setFillType(SkPathFillType::kEvenOdd);
471 REPORTER_ASSERT(reporter, !result.isConvex());
472 test.setFillType(SkPathFillType::kWinding);
474 // test two contours that do not overlap or share bounds
475 test.addRect({5, 2, 6, 3});
476 test.setFillType(SkPathFillType::kEvenOdd);
478 REPORTER_ASSERT(reporter, !result.isConvex());
479 test.setFillType(SkPathFillType::kWinding);
481 // test two contours that do not overlap but share bounds
482 test.reset();
483 test.addPoly(ell, std::size(ell), true);
484 test.addRect({2, 2, 3, 3});
485 test.setFillType(SkPathFillType::kEvenOdd);
487 REPORTER_ASSERT(reporter, !result.isConvex());
488 test.setFillType(SkPathFillType::kWinding);
490 // test two contours that partially overlap
491 test.reset();
492 test.addRect({0, 0, 3, 3});
493 test.addRect({1, 1, 4, 4});
494 test.setFillType(SkPathFillType::kEvenOdd);
496 REPORTER_ASSERT(reporter, !result.isConvex());
497 test.setFillType(SkPathFillType::kWinding);
499 // test that result may be input
500 SkPath copy = test;
501 test.setFillType(SkPathFillType::kEvenOdd);
503 REPORTER_ASSERT(reporter, !test.isConvex());
505 // test a in b, b in a, cw/ccw
506 constexpr SkRect rectA = {0, 0, 3, 3};
507 constexpr SkRect rectB = {1, 1, 2, 2};
508 const std::initializer_list<SkPoint> revBccw = {{1, 2}, {2, 2}, {2, 1}, {1, 1}};
509 const std::initializer_list<SkPoint> revBcw = {{2, 1}, {2, 2}, {1, 2}, {1, 1}};
510 for (bool aFirst : {false, true}) {
511 for (auto dirA : {SkPathDirection::kCW, SkPathDirection::kCCW}) {
512 for (auto dirB : {SkPathDirection::kCW, SkPathDirection::kCCW}) {
513 test.reset();
514 test.setFillType(SkPathFillType::kEvenOdd);
515 if (aFirst) {
516 test.addRect(rectA, dirA);
517 test.addRect(rectB, dirB);
518 } else {
519 test.addRect(rectB, dirB);
520 test.addRect(rectA, dirA);
521 }
522 SkPath original = test;
525 test.reset();
526 if (aFirst) {
527 test.addRect(rectA, dirA);
528 }
529 if (dirA != dirB) {
530 test.addRect(rectB, dirB);
531 } else {
532 test.addPoly(SkPathDirection::kCW == dirA ? revBccw : revBcw, true);
533 }
534 if (!aFirst) {
535 test.addRect(rectA, dirA);
536 }
538 // test that result may be input
539 REPORTER_ASSERT(reporter, AsWinding(original, &original));
541 REPORTER_ASSERT(reporter, original == result);
542 }
543 }
544 }
545 // Test curve types with donuts. Create a donut with outer and hole in all directions.
546 // After converting to winding, all donuts should have a hole in the middle.
547 for (bool aFirst : {false, true}) {
548 for (auto dirA : {SkPathDirection::kCW, SkPathDirection::kCCW}) {
549 for (auto dirB : {SkPathDirection::kCW, SkPathDirection::kCCW}) {
550 for (auto curveA : { SkPath::kLine_Verb, SkPath::kQuad_Verb,
552 SkPath pathA = build_squircle(curveA, rectA, dirA);
553 for (auto curveB : { SkPath::kLine_Verb, SkPath::kQuad_Verb,
555 test = aFirst ? pathA : SkPath();
556 test.addPath(build_squircle(curveB, rectB, dirB));
557 if (!aFirst) {
558 test.addPath(pathA);
559 }
560 test.setFillType(SkPathFillType::kEvenOdd);
563 for (SkScalar x = rectA.fLeft - 1; x <= rectA.fRight + 1; ++x) {
564 for (SkScalar y = rectA.fTop - 1; y <= rectA.fBottom + 1; ++y) {
565 bool evenOddContains = test.contains(x, y);
566 bool windingContains = result.contains(x, y);
567 REPORTER_ASSERT(reporter, evenOddContains == windingContains);
568 }
569 }
570 }
571 }
572 }
573 }
574 }
575 // test https://bugs.chromium.org/p/skia/issues/detail?id=12040
581 // test https://bugs.chromium.org/p/skia/issues/detail?id=13496
585}
#define test(name)
reporter
void bug12040_4(skiatest::Reporter *reporter)
void bug12040_3(skiatest::Reporter *reporter)
void bug13496_3(skiatest::Reporter *reporter)
void bug12040_2(skiatest::Reporter *reporter)
static SkPath build_squircle(SkPath::Verb verb, const SkRect &rect, SkPathDirection dir)
void bug13496_1(skiatest::Reporter *reporter)
void bug13496_2(skiatest::Reporter *reporter)
void bug12040_1(skiatest::Reporter *reporter)
void bug12040_5(skiatest::Reporter *reporter)
static SkPath path2()
#define SkASSERT(cond)
Definition SkAssert.h:116
static size_t difference(size_t minuend, size_t subtrahend)
bool SK_API AsWinding(const SkPath &path, SkPath *result)
@ kDifference_SkPathOp
subtract the op path from the first path
Definition SkPathOps.h:23
@ kXOR_SkPathOp
exclusive-or the two paths
Definition SkPathOps.h:26
bool SK_API Simplify(const SkPath &path, SkPath *result)
SkPathDirection
Definition SkPathTypes.h:34
#define SK_ScalarInfinity
Definition SkScalar.h:26
#define DEF_TEST(name, reporter)
Definition Test.h:312
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
static bool FromSVGString(const char str[], SkPath *)
SkPath & reverseAddPath(const SkPath &src)
Definition SkPath.cpp:1569
SkPath & moveTo(SkScalar x, SkScalar y)
Definition SkPath.cpp:678
SkPathFillType getFillType() const
Definition SkPath.h:230
void setFillType(SkPathFillType ft)
Definition SkPath.h:235
SkPath & lineTo(SkScalar x, SkScalar y)
Definition SkPath.cpp:718
@ kConic_Verb
Definition SkPath.h:1461
@ kCubic_Verb
Definition SkPath.h:1462
@ kQuad_Verb
Definition SkPath.h:1460
@ kLine_Verb
Definition SkPath.h:1459
SkPath & cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3)
Definition SkPath.cpp:789
SkPath & close()
Definition SkPath.cpp:813
float SkScalar
Definition extension.cpp:12
GAsyncResult * result
double y
double x
Definition copy.py:1
SkScalar fBottom
larger y-axis bounds
Definition extension.cpp:17
SkScalar fLeft
smaller x-axis bounds
Definition extension.cpp:14
SkScalar fRight
larger x-axis bounds
Definition extension.cpp:16
SkScalar fTop
smaller y-axis bounds
Definition extension.cpp:15