Flutter Engine
The Flutter Engine
StrokerTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2014 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
16#include "src/base/SkRandom.h"
25#include "tests/Test.h"
27
28#include <array>
29#include <cfloat>
30#include <cstddef>
31#include <cstdint>
32
34
35static DEFINE_bool(timeout, true, "run until alloted time expires");
36
37#define MS_TEST_DURATION 10
38
39const SkScalar widths[] = {-FLT_MAX, -1, -0.1f, -FLT_EPSILON, 0, FLT_EPSILON,
40 0.0000001f, 0.000001f, 0.00001f, 0.0001f, 0.001f, 0.01f,
41 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 1, 1.1f, 2, 10, 10e2f, 10e3f, 10e4f, 10e5f, 10e6f, 10e7f,
42 10e8f, 10e9f, 10e10f, 10e20f, FLT_MAX };
44
45static void pathTest(const SkPath& path) {
46 SkPaint p;
47 SkPath fill;
48 p.setStyle(SkPaint::kStroke_Style);
49 for (size_t index = 0; index < widths_count; ++index) {
50 p.setStrokeWidth(widths[index]);
52 }
53}
54
55static void cubicTest(const SkPoint c[4]) {
57 path.moveTo(c[0].fX, c[0].fY);
58 path.cubicTo(c[1].fX, c[1].fY, c[2].fX, c[2].fY, c[3].fX, c[3].fY);
60}
61
62static void quadTest(const SkPoint c[3]) {
64 path.moveTo(c[0].fX, c[0].fY);
65 path.quadTo(c[1].fX, c[1].fY, c[2].fX, c[2].fY);
67}
68
69static void cubicSetTest(const CubicPts* dCubic, size_t count) {
70 skiatest::Timer timer;
71 for (size_t index = 0; index < count; ++index) {
72 const CubicPts& dPts = dCubic[index];
73 SkDCubic d;
74 d.debugSet(dPts.fPts);
75 SkPoint c[4] = { {(float) d[0].fX, (float) d[0].fY}, {(float) d[1].fX, (float) d[1].fY},
76 {(float) d[2].fX, (float) d[2].fY}, {(float) d[3].fX, (float) d[3].fY} };
77 cubicTest(c);
78 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
79 return;
80 }
81 }
82}
83
84static void cubicPairSetTest(const CubicPts dCubic[][2], size_t count) {
85 skiatest::Timer timer;
86 for (size_t index = 0; index < count; ++index) {
87 for (int pair = 0; pair < 2; ++pair) {
88 const CubicPts& dPts = dCubic[index][pair];
89 SkDCubic d;
90 d.debugSet(dPts.fPts);
91 SkPoint c[4] = { {(float) d[0].fX, (float) d[0].fY}, {(float) d[1].fX, (float) d[1].fY},
92 {(float) d[2].fX, (float) d[2].fY}, {(float) d[3].fX, (float) d[3].fY} };
93 cubicTest(c);
94 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
95 return;
96 }
97 }
98 }
99}
100
101static void quadSetTest(const QuadPts* dQuad, size_t count) {
102 skiatest::Timer timer;
103 for (size_t index = 0; index < count; ++index) {
104 const QuadPts& dPts = dQuad[index];
105 SkDQuad d;
106 d.debugSet(dPts.fPts);
107 SkPoint c[3] = { {(float) d[0].fX, (float) d[0].fY}, {(float) d[1].fX, (float) d[1].fY},
108 {(float) d[2].fX, (float) d[2].fY} };
109 quadTest(c);
110 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
111 return;
112 }
113 }
114}
115
116static void quadPairSetTest(const QuadPts dQuad[][2], size_t count) {
117 skiatest::Timer timer;
118 for (size_t index = 0; index < count; ++index) {
119 for (int pair = 0; pair < 2; ++pair) {
120 const QuadPts& dPts = dQuad[index][pair];
121 SkDQuad d;
122 d.debugSet(dPts.fPts);
123 SkPoint c[3] = { {(float) d[0].fX, (float) d[0].fY}, {(float) d[1].fX, (float) d[1].fY},
124 {(float) d[2].fX, (float) d[2].fY} };
125 quadTest(c);
126 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
127 return;
128 }
129 }
130 }
131}
132
133DEF_TEST(QuadStrokerSet, reporter) {
138}
139
140DEF_TEST(CubicStrokerSet, reporter) {
149}
150
152 uint32_t val = r.nextU();
153 return SkBits2Float(val);
154}
155
157 uint32_t val = r.nextU() & 0x7fffffff;
158 return SkBits2Float(val);
159}
160
161DEF_TEST(QuadStrokerUnbounded, reporter) {
162 SkRandom r;
163 SkPaint p;
164 p.setStyle(SkPaint::kStroke_Style);
165#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
166 int best = 0;
167 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
168#endif
169 skiatest::Timer timer;
170 for (int i = 0; i < 1000000; ++i) {
171 SkPath path, fill;
172 path.moveTo(unbounded(r), unbounded(r));
173 path.quadTo(unbounded(r), unbounded(r), unbounded(r), unbounded(r));
174 p.setStrokeWidth(unboundedPos(r));
176#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
177 if (best < gMaxRecursion[2]) {
178 if (reporter->verbose()) {
179 SkDebugf("\n%s quad=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[2],
180 p.getStrokeWidth());
181 path.dumpHex();
182 SkDebugf("fill:\n");
183 fill.dumpHex();
184 }
185 best = gMaxRecursion[2];
186 }
187#endif
188 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
189 return;
190 }
191 }
192#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
193 if (reporter->verbose()) {
194 SkDebugf("\n%s max quad=%d\n", __FUNCTION__, best);
195 }
196#endif
197}
198
199DEF_TEST(CubicStrokerUnbounded, reporter) {
200 SkRandom r;
201 SkPaint p;
202 p.setStyle(SkPaint::kStroke_Style);
203#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
204 int bestTan = 0;
205 int bestCubic = 0;
206 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
207#endif
208 skiatest::Timer timer;
209 for (int i = 0; i < 1000000; ++i) {
210 SkPath path, fill;
211 path.moveTo(unbounded(r), unbounded(r));
212 path.cubicTo(unbounded(r), unbounded(r), unbounded(r), unbounded(r),
213 unbounded(r), unbounded(r));
214 p.setStrokeWidth(unboundedPos(r));
216 #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
217 if (bestTan < gMaxRecursion[0] || bestCubic < gMaxRecursion[1]) {
218 if (reporter->verbose()) {
219 SkDebugf("\n%s tan=%d cubic=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[0],
220 gMaxRecursion[1], p.getStrokeWidth());
221 path.dumpHex();
222 SkDebugf("fill:\n");
223 fill.dumpHex();
224 }
225 bestTan = std::max(bestTan, gMaxRecursion[0]);
226 bestCubic = std::max(bestCubic, gMaxRecursion[1]);
227 }
228 #endif
229 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
230 return;
231 }
232 }
233#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
234 if (reporter->verbose()) {
235 SkDebugf("\n%s max tan=%d cubic=%d\n", __FUNCTION__, bestTan, bestCubic);
236 }
237#endif
238}
239
240DEF_TEST(QuadStrokerConstrained, reporter) {
241 SkRandom r;
242 SkPaint p;
243 p.setStyle(SkPaint::kStroke_Style);
244#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
245 int best = 0;
246 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
247#endif
248 skiatest::Timer timer;
249 for (int i = 0; i < 1000000; ++i) {
250 SkPath path, fill;
251 SkPoint quad[3];
252 quad[0].fX = r.nextRangeF(0, 500);
253 quad[0].fY = r.nextRangeF(0, 500);
254 const SkScalar halfSquared = 0.5f * 0.5f;
255 do {
256 quad[1].fX = r.nextRangeF(0, 500);
257 quad[1].fY = r.nextRangeF(0, 500);
258 } while (SkPointPriv::DistanceToSqd(quad[0], quad[1]) < halfSquared);
259 do {
260 quad[2].fX = r.nextRangeF(0, 500);
261 quad[2].fY = r.nextRangeF(0, 500);
262 } while (SkPointPriv::DistanceToSqd(quad[0], quad[2]) < halfSquared
263 || SkPointPriv::DistanceToSqd(quad[1], quad[2]) < halfSquared);
264 path.moveTo(quad[0].fX, quad[0].fY);
265 path.quadTo(quad[1].fX, quad[1].fY, quad[2].fX, quad[2].fY);
266 p.setStrokeWidth(r.nextRangeF(0, 500));
268#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
269 if (best < gMaxRecursion[2]) {
270 if (reporter->verbose()) {
271 SkDebugf("\n%s quad=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[2],
272 p.getStrokeWidth());
273 path.dumpHex();
274 SkDebugf("fill:\n");
275 fill.dumpHex();
276 }
277 best = gMaxRecursion[2];
278 }
279#endif
280 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
281 return;
282 }
283 }
284#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
285 if (reporter->verbose()) {
286 SkDebugf("\n%s max quad=%d\n", __FUNCTION__, best);
287 }
288#endif
289}
290
291DEF_TEST(CubicStrokerConstrained, reporter) {
292 SkRandom r;
293 SkPaint p;
294 p.setStyle(SkPaint::kStroke_Style);
295#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
296 int bestTan = 0;
297 int bestCubic = 0;
298 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
299#endif
300 skiatest::Timer timer;
301 for (int i = 0; i < 1000000; ++i) {
302 SkPath path, fill;
303 SkPoint cubic[4];
304 cubic[0].fX = r.nextRangeF(0, 500);
305 cubic[0].fY = r.nextRangeF(0, 500);
306 const SkScalar halfSquared = 0.5f * 0.5f;
307 do {
308 cubic[1].fX = r.nextRangeF(0, 500);
309 cubic[1].fY = r.nextRangeF(0, 500);
310 } while (SkPointPriv::DistanceToSqd(cubic[0], cubic[1]) < halfSquared);
311 do {
312 cubic[2].fX = r.nextRangeF(0, 500);
313 cubic[2].fY = r.nextRangeF(0, 500);
314 } while ( SkPointPriv::DistanceToSqd(cubic[0], cubic[2]) < halfSquared
315 || SkPointPriv::DistanceToSqd(cubic[1], cubic[2]) < halfSquared);
316 do {
317 cubic[3].fX = r.nextRangeF(0, 500);
318 cubic[3].fY = r.nextRangeF(0, 500);
319 } while ( SkPointPriv::DistanceToSqd(cubic[0], cubic[3]) < halfSquared
320 || SkPointPriv::DistanceToSqd(cubic[1], cubic[3]) < halfSquared
321 || SkPointPriv::DistanceToSqd(cubic[2], cubic[3]) < halfSquared);
322 path.moveTo(cubic[0].fX, cubic[0].fY);
323 path.cubicTo(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY);
324 p.setStrokeWidth(r.nextRangeF(0, 500));
326#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
327 if (bestTan < gMaxRecursion[0] || bestCubic < gMaxRecursion[1]) {
328 if (reporter->verbose()) {
329 SkDebugf("\n%s tan=%d cubic=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[0],
330 gMaxRecursion[1], p.getStrokeWidth());
331 path.dumpHex();
332 SkDebugf("fill:\n");
333 fill.dumpHex();
334 }
335 bestTan = std::max(bestTan, gMaxRecursion[0]);
336 bestCubic = std::max(bestCubic, gMaxRecursion[1]);
337 }
338#endif
339 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
340 return;
341 }
342 }
343#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
344 if (reporter->verbose()) {
345 SkDebugf("\n%s max tan=%d cubic=%d\n", __FUNCTION__, bestTan, bestCubic);
346 }
347#endif
348}
349
350DEF_TEST(QuadStrokerRange, reporter) {
351 SkRandom r;
352 SkPaint p;
353 p.setStyle(SkPaint::kStroke_Style);
354#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
355 int best = 0;
356 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
357#endif
358 skiatest::Timer timer;
359 for (int i = 0; i < 1000000; ++i) {
360 SkPath path, fill;
361 SkPoint quad[3];
362 quad[0].fX = r.nextRangeF(0, 500);
363 quad[0].fY = r.nextRangeF(0, 500);
364 quad[1].fX = r.nextRangeF(0, 500);
365 quad[1].fY = r.nextRangeF(0, 500);
366 quad[2].fX = r.nextRangeF(0, 500);
367 quad[2].fY = r.nextRangeF(0, 500);
368 path.moveTo(quad[0].fX, quad[0].fY);
369 path.quadTo(quad[1].fX, quad[1].fY, quad[2].fX, quad[2].fY);
370 p.setStrokeWidth(r.nextRangeF(0, 500));
372#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
373 if (best < gMaxRecursion[2]) {
374 if (reporter->verbose()) {
375 SkDebugf("\n%s quad=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[2],
376 p.getStrokeWidth());
377 path.dumpHex();
378 SkDebugf("fill:\n");
379 fill.dumpHex();
380 }
381 best = gMaxRecursion[2];
382 }
383#endif
384 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
385 return;
386 }
387 }
388#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
389 if (reporter->verbose()) {
390 SkDebugf("\n%s max quad=%d\n", __FUNCTION__, best);
391 }
392#endif
393}
394
395DEF_TEST(CubicStrokerRange, reporter) {
396 SkRandom r;
397 SkPaint p;
398 p.setStyle(SkPaint::kStroke_Style);
399#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
400 int best[2] = { 0 };
401 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
402#endif
403 skiatest::Timer timer;
404 for (int i = 0; i < 1000000; ++i) {
405 SkPath path, fill;
406 path.moveTo(r.nextRangeF(0, 500), r.nextRangeF(0, 500));
407 path.cubicTo(r.nextRangeF(0, 500), r.nextRangeF(0, 500), r.nextRangeF(0, 500),
408 r.nextRangeF(0, 500), r.nextRangeF(0, 500), r.nextRangeF(0, 500));
409 p.setStrokeWidth(r.nextRangeF(0, 100));
411#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
412 if (best[0] < gMaxRecursion[0] || best[1] < gMaxRecursion[1]) {
413 if (reporter->verbose()) {
414 SkDebugf("\n%s tan=%d cubic=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[0],
415 gMaxRecursion[1], p.getStrokeWidth());
416 path.dumpHex();
417 SkDebugf("fill:\n");
418 fill.dumpHex();
419 }
420 best[0] = std::max(best[0], gMaxRecursion[0]);
421 best[1] = std::max(best[1], gMaxRecursion[1]);
422 }
423#endif
424 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
425 return;
426 }
427 }
428#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
429 if (reporter->verbose()) {
430 SkDebugf("\n%s max tan=%d cubic=%d\n", __FUNCTION__, best[0], best[1]);
431 }
432#endif
433}
434
435
436DEF_TEST(QuadStrokerOneOff, reporter) {
437#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
438 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
439#endif
440 SkPaint p;
441 p.setStyle(SkPaint::kStroke_Style);
442 p.setStrokeWidth(SkDoubleToScalar(164.683548));
443
444 SkPath path, fill;
445path.moveTo(SkBits2Float(0x43c99223), SkBits2Float(0x42b7417e));
446path.quadTo(SkBits2Float(0x4285d839), SkBits2Float(0x43ed6645), SkBits2Float(0x43c941c8), SkBits2Float(0x42b3ace3));
448 if (reporter->verbose()) {
449 SkDebugf("\n%s path\n", __FUNCTION__);
450 path.dump();
451 SkDebugf("fill:\n");
452 fill.dump();
453 }
454#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
455 if (reporter->verbose()) {
456 SkDebugf("max quad=%d\n", gMaxRecursion[2]);
457 }
458#endif
459}
460
461DEF_TEST(CubicStrokerOneOff, reporter) {
462#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
463 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
464#endif
465 SkPaint p;
466 p.setStyle(SkPaint::kStroke_Style);
467 p.setStrokeWidth(SkDoubleToScalar(42.835968));
468
469 SkPath path, fill;
470path.moveTo(SkBits2Float(0x433f5370), SkBits2Float(0x43d1f4b3));
471path.cubicTo(SkBits2Float(0x4331cb76), SkBits2Float(0x43ea3340), SkBits2Float(0x4388f498), SkBits2Float(0x42f7f08d), SkBits2Float(0x43f1cd32), SkBits2Float(0x42802ec1));
473 if (reporter->verbose()) {
474 SkDebugf("\n%s path\n", __FUNCTION__);
475 path.dump();
476 SkDebugf("fill:\n");
477 fill.dump();
478 }
479#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
480 if (reporter->verbose()) {
481 SkDebugf("max tan=%d cubic=%d\n", gMaxRecursion[0], gMaxRecursion[1]);
482 }
483#endif
484}
static BlurTest tests[]
Definition: BlurTest.cpp:84
sk_bzero(glyphs, sizeof(glyphs))
reporter
Definition: FontMgrTest.cpp:39
int count
Definition: FontMgrTest.cpp:50
const size_t quadraticLines_count
const QuadPts quadraticModEpsilonLines[]
const size_t quadraticPoints_count
const size_t quadraticModEpsilonLines_count
const QuadPts quadraticPoints[]
const QuadPts quadraticLines[]
const size_t quadraticTests_count
const QuadPts quadraticTests[][2]
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static float SkBits2Float(uint32_t bits)
Definition: SkFloatBits.h:48
#define SkDoubleToScalar(x)
Definition: SkScalar.h:64
static void quadSetTest(const QuadPts *dQuad, size_t count)
#define MS_TEST_DURATION
Definition: StrokerTest.cpp:37
static void cubicSetTest(const CubicPts *dCubic, size_t count)
Definition: StrokerTest.cpp:69
static void quadPairSetTest(const QuadPts dQuad[][2], size_t count)
static void quadTest(const SkPoint c[3])
Definition: StrokerTest.cpp:62
static SkScalar unbounded(SkRandom &r)
static SkScalar unboundedPos(SkRandom &r)
DEF_TEST(QuadStrokerSet, reporter)
size_t widths_count
Definition: StrokerTest.cpp:43
const SkScalar widths[]
Definition: StrokerTest.cpp:39
static DEFINE_bool(timeout, true, "run until alloted time expires")
static void cubicTest(const SkPoint c[4])
Definition: StrokerTest.cpp:55
static void pathTest(const SkPath &path)
Definition: StrokerTest.cpp:45
static void cubicPairSetTest(const CubicPts dCubic[][2], size_t count)
Definition: StrokerTest.cpp:84
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
Definition: SkPath.h:59
void dumpHex() const
Definition: SkPath.h:1735
void dump(SkWStream *stream, bool dumpAsHex) const
Definition: SkPath.cpp:2040
static SkScalar DistanceToSqd(const SkPoint &pt, const SkPoint &a)
Definition: SkPointPriv.h:48
uint32_t nextU()
Definition: SkRandom.h:42
float nextRangeF(float min, float max)
Definition: SkRandom.h:64
double elapsedMs() const
Definition: Test.cpp:80
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
float SkScalar
Definition: extension.cpp:12
static float max(float r, float g, float b)
Definition: hsl.cpp:49
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
def timeout(deadline, cmd)
AI float cubic(float precision, const SkPoint pts[], const VectorXform &vectorXform=VectorXform())
Definition: WangsFormula.h:195
SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst, const SkRect *cullRect, SkScalar resScale=1)
Definition: SkPathUtils.cpp:23
SkDPoint fPts[kPointCount]
SkDPoint fPts[kPointCount]
float fX
x-axis value
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165