Flutter Engine
The Flutter Engine
pathkit_wasm_bindings.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 Google LLC
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/SkPath.h"
14#include "include/core/SkRect.h"
24#include "src/core/SkPathPriv.h"
25
26#include <emscripten.h>
27#include <emscripten/bind.h>
28
29using namespace emscripten;
30
31static const int MOVE = 0;
32static const int LINE = 1;
33static const int QUAD = 2;
34static const int CONIC = 3;
35static const int CUBIC = 4;
36static const int CLOSE = 5;
37
38
39// Just for self-documenting purposes where the main thing being returned is an
40// SkPath, but in an error case, something of type null (which is val) could also be
41// returned;
42using SkPathOrNull = emscripten::val;
43// Self-documenting for when we return a string
44using JSString = emscripten::val;
45using JSArray = emscripten::val;
46
47// =================================================================================
48// Creating/Exporting Paths with cmd arrays
49// =================================================================================
50
51JSArray EMSCRIPTEN_KEEPALIVE ToCmds(const SkPath& path) {
52 JSArray cmds = emscripten::val::array();
53 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
54 JSArray cmd = emscripten::val::array();
55 switch (verb) {
57 cmd.call<void>("push", MOVE, pts[0].x(), pts[0].y());
58 break;
60 cmd.call<void>("push", LINE, pts[1].x(), pts[1].y());
61 break;
63 cmd.call<void>("push", QUAD, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
64 break;
66 cmd.call<void>("push", CONIC,
67 pts[1].x(), pts[1].y(),
68 pts[2].x(), pts[2].y(), *w);
69 break;
71 cmd.call<void>("push", CUBIC,
72 pts[1].x(), pts[1].y(),
73 pts[2].x(), pts[2].y(),
74 pts[3].x(), pts[3].y());
75 break;
77 cmd.call<void>("push", CLOSE);
78 break;
79 }
80 cmds.call<void>("push", cmd);
81 }
82 return cmds;
83}
84
85// This type signature is a mess, but it's necessary. See, we can't use "bind" (EMSCRIPTEN_BINDINGS)
86// and pointers to primitive types (Only bound types like SkPoint). We could if we used
87// cwrap (see https://becominghuman.ai/passing-and-returning-webassembly-array-parameters-a0f572c65d97)
88// but that requires us to stick to C code and, AFAIK, doesn't allow us to return nice things like
89// SkPath or SkOpBuilder.
90//
91// So, basically, if we are using C++ and EMSCRIPTEN_BINDINGS, we can't have primative pointers
92// in our function type signatures. (this gives an error message like "Cannot call foo due to unbound
93// types Pi, Pf"). But, we can just pretend they are numbers and cast them to be pointers and
94// the compiler is happy.
95SkPathOrNull EMSCRIPTEN_KEEPALIVE FromCmds(uintptr_t /* float* */ cptr, int numCmds) {
96 const auto* cmds = reinterpret_cast<const float*>(cptr);
98 float x1, y1, x2, y2, x3, y3;
99
100 // if there are not enough arguments, bail with the path we've constructed so far.
101 #define CHECK_NUM_ARGS(n) \
102 if ((i + n) > numCmds) { \
103 SkDebugf("Not enough args to match the verbs. Saw %d commands\n", numCmds); \
104 return emscripten::val::null(); \
105 }
106
107 for(int i = 0; i < numCmds;){
108 switch (sk_float_floor2int(cmds[i++])) {
109 case MOVE:
111 x1 = cmds[i++]; y1 = cmds[i++];
112 path.moveTo(x1, y1);
113 break;
114 case LINE:
116 x1 = cmds[i++]; y1 = cmds[i++];
117 path.lineTo(x1, y1);
118 break;
119 case QUAD:
121 x1 = cmds[i++]; y1 = cmds[i++];
122 x2 = cmds[i++]; y2 = cmds[i++];
123 path.quadTo(x1, y1, x2, y2);
124 break;
125 case CONIC:
127 x1 = cmds[i++]; y1 = cmds[i++];
128 x2 = cmds[i++]; y2 = cmds[i++];
129 x3 = cmds[i++]; // weight
130 path.conicTo(x1, y1, x2, y2, x3);
131 break;
132 case CUBIC:
134 x1 = cmds[i++]; y1 = cmds[i++];
135 x2 = cmds[i++]; y2 = cmds[i++];
136 x3 = cmds[i++]; y3 = cmds[i++];
137 path.cubicTo(x1, y1, x2, y2, x3, y3);
138 break;
139 case CLOSE:
140 path.close();
141 break;
142 default:
143 SkDebugf(" path: UNKNOWN command %f, aborting dump...\n", cmds[i-1]);
144 return emscripten::val::null();
145 }
146 }
147
148 #undef CHECK_NUM_ARGS
149
150 return emscripten::val(path);
151}
152
153SkPath EMSCRIPTEN_KEEPALIVE NewPath() {
154 return SkPath();
155}
156
157SkPath EMSCRIPTEN_KEEPALIVE CopyPath(const SkPath& a) {
158 SkPath copy(a);
159 return copy;
160}
161
162bool EMSCRIPTEN_KEEPALIVE Equals(const SkPath& a, const SkPath& b) {
163 return a == b;
164}
165
166//========================================================================================
167// Path things
168//========================================================================================
169
170// All these Apply* methods are simple wrappers to avoid returning an object.
171// The default WASM bindings produce code that will leak if a return value
172// isn't assigned to a JS variable and has delete() called on it.
173// These Apply methods, combined with the smarter binding code allow for chainable
174// commands that don't leak if the return value is ignored (i.e. when used intuitively).
175
177 SkScalar radius) {
178 p.arcTo(x1, y1, x2, y2, radius);
179}
180
182 p.close();
183}
184
186 SkScalar w) {
187 p.conicTo(x1, y1, x2, y2, w);
188}
189
191 SkScalar x3, SkScalar y3) {
192 p.cubicTo(x1, y1, x2, y2, x3, y3);
193}
194
196 p.lineTo(x, y);
197}
198
200 p.moveTo(x, y);
201}
202
204 p.quadTo(x1, y1, x2, y2);
205}
206
207bool EMSCRIPTEN_KEEPALIVE IsEmpty(const SkPath& path) {
208 return path.isEmpty();
209}
210
211
212
213//========================================================================================
214// SVG things
215//========================================================================================
216
217JSString EMSCRIPTEN_KEEPALIVE ToSVGString(const SkPath& path) {
218 // Wrapping it in val automatically turns it into a JS string.
219 // Not too sure on performance implications, but is is simpler than
220 // returning a raw pointer to const char * and then using
221 // UTF8ToString() on the calling side.
222 return emscripten::val(SkParsePath::ToSVGString(path).c_str());
223}
224
225
226SkPathOrNull EMSCRIPTEN_KEEPALIVE FromSVGString(std::string str) {
227 SkPath path;
228 if (SkParsePath::FromSVGString(str.c_str(), &path)) {
229 return emscripten::val(path);
230 }
231 return emscripten::val::null();
232}
233
234//========================================================================================
235// PATHOP things
236//========================================================================================
237
238bool EMSCRIPTEN_KEEPALIVE ApplySimplify(SkPath& path) {
239 return Simplify(path, &path);
240}
241
242bool EMSCRIPTEN_KEEPALIVE ApplyAsWinding(SkPath& path) {
243 return AsWinding(path, &path);
244}
245
246bool EMSCRIPTEN_KEEPALIVE ApplyPathOp(SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
247 return Op(pathOne, pathTwo, op, &pathOne);
248}
249
250SkPathOrNull EMSCRIPTEN_KEEPALIVE MakeFromOp(const SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
251 SkPath out;
252 if (Op(pathOne, pathTwo, op, &out)) {
253 return emscripten::val(out);
254 }
255 return emscripten::val::null();
256}
257
259 SkPath path;
260 if (builder.resolve(&path)) {
261 return emscripten::val(path);
262 }
263 return emscripten::val::null();
264}
265
266//========================================================================================
267// Canvas things
268//========================================================================================
269
270void EMSCRIPTEN_KEEPALIVE ToCanvas(const SkPath& path, emscripten::val /* Path2D or Canvas*/ ctx) {
271 SkPath::Iter iter(path, false);
272 SkPoint pts[4];
273 SkPath::Verb verb;
274 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
275 switch (verb) {
277 ctx.call<void>("moveTo", pts[0].x(), pts[0].y());
278 break;
280 ctx.call<void>("lineTo", pts[1].x(), pts[1].y());
281 break;
283 ctx.call<void>("quadraticCurveTo", pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
284 break;
286 SkPoint quads[5];
287 // approximate with 2^1=2 quads.
288 SkPath::ConvertConicToQuads(pts[0], pts[1], pts[2], iter.conicWeight(), quads, 1);
289 ctx.call<void>("quadraticCurveTo", quads[1].x(), quads[1].y(), quads[2].x(), quads[2].y());
290 ctx.call<void>("quadraticCurveTo", quads[3].x(), quads[3].y(), quads[4].x(), quads[4].y());
291 break;
293 ctx.call<void>("bezierCurveTo", pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y(),
294 pts[3].x(), pts[3].y());
295 break;
297 ctx.call<void>("closePath");
298 break;
300 break;
301 }
302 }
303}
304
305emscripten::val JSPath2D = emscripten::val::global("Path2D");
306
307emscripten::val EMSCRIPTEN_KEEPALIVE ToPath2D(const SkPath& path) {
308 emscripten::val retVal = JSPath2D.new_();
309 ToCanvas(path, retVal);
310 return retVal;
311}
312
313// ======================================================================================
314// Path2D API things
315// ======================================================================================
317 path.addRect(x, y, x+width, y+height);
318}
319
321 SkScalar startAngle, SkScalar endAngle, bool ccw) {
322 SkPath temp;
323 SkRect bounds = SkRect::MakeLTRB(x-radius, y-radius, x+radius, y+radius);
324 const auto sweep = SkRadiansToDegrees(endAngle - startAngle) - 360 * ccw;
326 path.addPath(temp, SkPath::kExtend_AddPathMode);
327}
328
330 SkScalar rotation, SkScalar startAngle, SkScalar endAngle, bool ccw) {
331 // This is easiest to do by making a new path and then extending the current path
332 // (this properly catches the cases of if there's a moveTo before this call or not).
333 SkRect bounds = SkRect::MakeLTRB(x-radiusX, y-radiusY, x+radiusX, y+radiusY);
334 SkPath temp;
335 const auto sweep = SkRadiansToDegrees(endAngle - startAngle) - (360 * ccw);
337
338 SkMatrix m;
339 m.setRotate(SkRadiansToDegrees(rotation), x, y);
340 path.addPath(temp, m, SkPath::kExtend_AddPathMode);
341}
342
343// Allows for full matix control.
344void ApplyAddPath(SkPath& orig, const SkPath& newPath,
345 SkScalar scaleX, SkScalar skewX, SkScalar transX,
346 SkScalar skewY, SkScalar scaleY, SkScalar transY,
347 SkScalar pers0, SkScalar pers1, SkScalar pers2) {
348 SkMatrix m = SkMatrix::MakeAll(scaleX, skewX , transX,
349 skewY , scaleY, transY,
350 pers0 , pers1 , pers2);
351 orig.addPath(newPath, m);
352}
353
354void ApplyReverseAddPath(SkPath& orig, const SkPath& newPath) {
355 orig.reverseAddPath(newPath);
356}
357
358
360 if (path.getFillType() == SkPathFillType::kWinding) {
361 return emscripten::val("nonzero");
362 } else if (path.getFillType() == SkPathFillType::kEvenOdd) {
363 return emscripten::val("evenodd");
364 } else {
365 SkDebugf("warning: can't translate inverted filltype to HTML Canvas\n");
366 return emscripten::val("nonzero"); //Use default
367 }
368}
369
370//========================================================================================
371// Path Effects
372//========================================================================================
373
375 SkScalar intervals[] = { on, off };
376 auto pe = SkDashPathEffect::Make(intervals, 2, phase);
377 if (!pe) {
378 SkDebugf("Invalid args to dash()\n");
379 return false;
380 }
381 SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle);
382 if (pe->filterPath(&path, path, &rec, nullptr)) {
383 return true;
384 }
385 SkDebugf("Could not make dashed path\n");
386 return false;
387}
388
389bool ApplyTrim(SkPath& path, SkScalar startT, SkScalar stopT, bool isComplement) {
391 auto pe = SkTrimPathEffect::Make(startT, stopT, mode);
392 if (!pe) {
393 SkDebugf("Invalid args to trim(): startT and stopT must be in [0,1]\n");
394 return false;
395 }
396 SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle);
397 if (pe->filterPath(&path, path, &rec, nullptr)) {
398 return true;
399 }
400 SkDebugf("Could not trim path\n");
401 return false;
402}
403
404struct StrokeOpts {
405 // Default values are set in chaining.js which allows clients
406 // to set any number of them. Otherwise, the binding code complains if
407 // any are omitted.
413};
414
416 SkPaint p;
417 p.setStyle(SkPaint::kStroke_Style);
418 p.setStrokeCap(opts.cap);
419 p.setStrokeJoin(opts.join);
420 p.setStrokeWidth(opts.width);
421 p.setStrokeMiter(opts.miter_limit);
422 // Default to 1.0 if 0 (or an invalid negative number)
423 if (opts.res_scale <= 0) {
424 opts.res_scale = 1.0;
425 }
426 return skpathutils::FillPathWithPaint(path, p, &path, nullptr, opts.res_scale);
427}
428
429//========================================================================================
430// Matrix things
431//========================================================================================
432
437};
438
440 return SkMatrix::MakeAll(sm.scaleX, sm.skewX , sm.transX,
441 sm.skewY , sm.scaleY, sm.transY,
442 sm.pers0 , sm.pers1 , sm.pers2);
443}
444
445void ApplyTransform(SkPath& orig, const SimpleMatrix& sm) {
446 orig.transform(toSkMatrix(sm));
447}
448
450 SkScalar scaleX, SkScalar skewX, SkScalar transX,
451 SkScalar skewY, SkScalar scaleY, SkScalar transY,
452 SkScalar pers0, SkScalar pers1, SkScalar pers2) {
453 SkMatrix m = SkMatrix::MakeAll(scaleX, skewX , transX,
454 skewY , scaleY, transY,
455 pers0 , pers1 , pers2);
456 orig.transform(m);
457}
458
459//========================================================================================
460// Testing things
461//========================================================================================
462
463// The use case for this is on the JS side is something like:
464// PathKit.SkBits2FloatUnsigned(parseInt("0xc0a00000"))
465// to have precise float values for tests. In the C++ tests, we can use SkBits2Float because
466// it takes int32_t, but the JS parseInt basically returns an unsigned int. So, we add in
467// this helper which casts for us on the way to SkBits2Float.
468float SkBits2FloatUnsigned(uint32_t floatAsBits) {
469 return SkBits2Float((int32_t) floatAsBits);
470}
471
472// Binds the classes to the JS
473//
474// See https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html#non-member-functions-on-the-javascript-prototype
475// for more on binding non-member functions to the JS object, allowing us to rewire
476// various functions. That is, we can make the SkPath we expose appear to have methods
477// that the original SkPath does not, like rect(x, y, width, height) and toPath2D().
478//
479// An important detail for binding non-member functions is that the first argument
480// must be SkPath& (the reference part is very important).
481//
482// Note that we can't expose default or optional arguments, but we can have multiple
483// declarations of the same function that take different amounts of arguments.
484// For example, see _transform
485// Additionally, we are perfectly happy to handle default arguments and function
486// overloads in the JS glue code (see chaining.js::addPath() for an example).
488 class_<SkPath>("SkPath")
489 .constructor<>()
490 .constructor<const SkPath&>()
491
492 // Path2D API
493 .function("_addPath", &ApplyAddPath)
494 .function("_reverseAddPath", &ApplyReverseAddPath)
495 // 3 additional overloads of addPath are handled in JS bindings
496 .function("_arc", &ApplyAddArc)
497 .function("_arcTo", &ApplyArcTo)
498 //"bezierCurveTo" alias handled in JS bindings
499 .function("_close", &ApplyClose)
500 //"closePath" alias handled in JS bindings
501 .function("_conicTo", &ApplyConicTo)
502 .function("_cubicTo", &ApplyCubicTo)
503
504 .function("_ellipse", &ApplyEllipse)
505 .function("_lineTo", &ApplyLineTo)
506 .function("_moveTo", &ApplyMoveTo)
507 // "quadraticCurveTo" alias handled in JS bindings
508 .function("_quadTo", &ApplyQuadTo)
509 .function("_rect", &ApplyAddRect)
510 .function("_isEmpty", &IsEmpty)
511
512 // Extra features
513 .function("setFillType", select_overload<void(SkPathFillType)>(&SkPath::setFillType))
514 .function("getFillType", &SkPath::getFillType)
515 .function("getFillTypeString", &GetFillTypeString)
516 .function("getBounds", &SkPath::getBounds)
517 .function("computeTightBounds", &SkPath::computeTightBounds)
518 .function("equals", &Equals)
519 .function("copy", &CopyPath)
520
521 // PathEffects
522 .function("_dash", &ApplyDash)
523 .function("_trim", &ApplyTrim)
524 .function("_stroke", &ApplyStroke)
525
526 // Matrix
527 .function("_transform", select_overload<void(SkPath& orig, const SimpleMatrix& sm)>(&ApplyTransform))
528 .function("_transform", select_overload<void(SkPath& orig, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&ApplyTransform))
529
530 // PathOps
531 .function("_simplify", &ApplySimplify)
532 .function("_asWinding", &ApplyAsWinding)
533 .function("_op", &ApplyPathOp)
534
535 // Exporting
536 .function("toCmds", &ToCmds)
537 .function("toPath2D", &ToPath2D)
538 .function("toCanvas", &ToCanvas)
539 .function("toSVGString", &ToSVGString)
540
541#ifdef PATHKIT_TESTING
542 .function("dump", select_overload<void() const>(&SkPath::dump))
543 .function("dumpHex", select_overload<void() const>(&SkPath::dumpHex))
544#endif
545 ;
546
547 class_<SkOpBuilder>("SkOpBuilder")
548 .constructor<>()
549
550 .function("add", &SkOpBuilder::add)
551 .function("make", &ResolveBuilder)
552 .function("resolve", &ResolveBuilder);
553
554 // Without these function() bindings, the function would be exposed but oblivious to
555 // our types (e.g. SkPath)
556
557 // Import
558 function("FromSVGString", &FromSVGString);
559 function("NewPath", &NewPath);
560 function("NewPath", &CopyPath);
561 // FromCmds is defined in helper.js to make use of TypedArrays transparent.
562 function("_FromCmds", &FromCmds);
563 // Path2D is opaque, so we can't read in from it.
564
565 // PathOps
566 function("MakeFromOp", &MakeFromOp);
567
568 enum_<SkPathOp>("PathOp")
569 .value("DIFFERENCE", SkPathOp::kDifference_SkPathOp)
570 .value("INTERSECT", SkPathOp::kIntersect_SkPathOp)
571 .value("UNION", SkPathOp::kUnion_SkPathOp)
572 .value("XOR", SkPathOp::kXOR_SkPathOp)
573 .value("REVERSE_DIFFERENCE", SkPathOp::kReverseDifference_SkPathOp);
574
575 enum_<SkPathFillType>("FillType")
576 .value("WINDING", SkPathFillType::kWinding)
577 .value("EVENODD", SkPathFillType::kEvenOdd)
578 .value("INVERSE_WINDING", SkPathFillType::kInverseWinding)
579 .value("INVERSE_EVENODD", SkPathFillType::kInverseEvenOdd);
580
581 constant("MOVE_VERB", MOVE);
582 constant("LINE_VERB", LINE);
583 constant("QUAD_VERB", QUAD);
584 constant("CONIC_VERB", CONIC);
585 constant("CUBIC_VERB", CUBIC);
586 constant("CLOSE_VERB", CLOSE);
587
588 // A value object is much simpler than a class - it is returned as a JS
589 // object and does not require delete().
590 // https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html#value-types
591 value_object<SkRect>("SkRect")
592 .field("fLeft", &SkRect::fLeft)
593 .field("fTop", &SkRect::fTop)
594 .field("fRight", &SkRect::fRight)
595 .field("fBottom", &SkRect::fBottom);
596
597 function("LTRBRect", &SkRect::MakeLTRB);
598
599 // Stroke
600 enum_<SkPaint::Join>("StrokeJoin")
601 .value("MITER", SkPaint::Join::kMiter_Join)
602 .value("ROUND", SkPaint::Join::kRound_Join)
603 .value("BEVEL", SkPaint::Join::kBevel_Join);
604
605 enum_<SkPaint::Cap>("StrokeCap")
606 .value("BUTT", SkPaint::Cap::kButt_Cap)
607 .value("ROUND", SkPaint::Cap::kRound_Cap)
608 .value("SQUARE", SkPaint::Cap::kSquare_Cap);
609
610 value_object<StrokeOpts>("StrokeOpts")
611 .field("width", &StrokeOpts::width)
612 .field("miter_limit", &StrokeOpts::miter_limit)
613 .field("res_scale", &StrokeOpts::res_scale)
614 .field("join", &StrokeOpts::join)
615 .field("cap", &StrokeOpts::cap);
616
617 // Matrix
618 // Allows clients to supply a 1D array of 9 elements and the bindings
619 // will automatically turn it into a 3x3 2D matrix.
620 // e.g. path.transform([0,1,2,3,4,5,6,7,8])
621 // This is likely simpler for the client than exposing SkMatrix
622 // directly and requiring them to do a lot of .delete().
623 value_array<SimpleMatrix>("SkMatrix")
624 .element(&SimpleMatrix::scaleX)
625 .element(&SimpleMatrix::skewX)
626 .element(&SimpleMatrix::transX)
627
628 .element(&SimpleMatrix::skewY)
629 .element(&SimpleMatrix::scaleY)
630 .element(&SimpleMatrix::transY)
631
632 .element(&SimpleMatrix::pers0)
633 .element(&SimpleMatrix::pers1)
634 .element(&SimpleMatrix::pers2);
635
636 value_array<SkPoint>("SkPoint")
637 .element(&SkPoint::fX)
638 .element(&SkPoint::fY);
639
640 // Not intended for external clients to call directly.
641 // See helper.js for the client-facing implementation.
642 class_<SkCubicMap>("_SkCubicMap")
643 .constructor<SkPoint, SkPoint>()
644
645 .function("computeYFromX", &SkCubicMap::computeYFromX)
646 .function("computePtFromT", &SkCubicMap::computeFromT);
647
648
649 // Test Utils
650 function("SkBits2FloatUnsigned", &SkBits2FloatUnsigned);
651}
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static float SkBits2Float(uint32_t bits)
Definition: SkFloatBits.h:48
#define sk_float_floor2int(x)
bool SK_API AsWinding(const SkPath &path, SkPath *result)
SkPathOp
Definition: SkPathOps.h:22
@ kReverseDifference_SkPathOp
subtract the first path from the op path
Definition: SkPathOps.h:27
@ kDifference_SkPathOp
subtract the op path from the first path
Definition: SkPathOps.h:23
@ kIntersect_SkPathOp
intersect the two paths
Definition: SkPathOps.h:24
@ kUnion_SkPathOp
union (inclusive-or) the two paths
Definition: SkPathOps.h:25
@ kXOR_SkPathOp
exclusive-or the two paths
Definition: SkPathOps.h:26
bool SK_API Simplify(const SkPath &path, SkPath *result)
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 SkRadiansToDegrees(radians)
Definition: SkScalar.h:78
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
Definition: SkSwizzler.cpp:31
emscripten::val SkPathOrNull
Definition: WasmCommon.h:30
emscripten::val JSString
Definition: WasmCommon.h:29
emscripten::val JSArray
Definition: WasmCommon.h:27
float computeYFromX(float x) const
Definition: SkCubicMap.cpp:61
SkPoint computeFromT(float t) const
Definition: SkCubicMap.cpp:108
static sk_sp< SkPathEffect > Make(const SkScalar intervals[], int count, SkScalar phase)
static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar pers0, SkScalar pers1, SkScalar pers2)
Definition: SkMatrix.h:179
void add(const SkPath &path, SkPathOp _operator)
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
static SkString ToSVGString(const SkPath &, PathEncoding=PathEncoding::Absolute)
static bool FromSVGString(const char str[], SkPath *)
Verb next(SkPoint pts[4])
Definition: SkPath.cpp:1901
SkScalar conicWeight() const
Definition: SkPath.h:1535
Definition: SkPath.h:59
SkPath & reverseAddPath(const SkPath &src)
Definition: SkPath.cpp:1633
SkPathFillType getFillType() const
Definition: SkPath.h:230
void setFillType(SkPathFillType ft)
Definition: SkPath.h:235
SkPath & addPath(const SkPath &src, SkScalar dx, SkScalar dy, AddPathMode mode=kAppend_AddPathMode)
Definition: SkPath.cpp:1506
SkRect computeTightBounds() const
Definition: SkPath.cpp:3446
void dump() const
Definition: SkPath.h:1734
SkPath & addArc(const SkRect &oval, SkScalar startAngle, SkScalar sweepAngle)
Definition: SkPath.cpp:1439
static int ConvertConicToQuads(const SkPoint &p0, const SkPoint &p1, const SkPoint &p2, SkScalar w, SkPoint pts[], int pow2)
Definition: SkPath.cpp:3238
const SkRect & getBounds() const
Definition: SkPath.cpp:430
@ kExtend_AddPathMode
Definition: SkPath.h:1293
void dumpHex() const
Definition: SkPath.h:1735
@ kClose_Verb
Definition: SkPath.h:1471
@ kMove_Verb
Definition: SkPath.h:1466
@ kConic_Verb
Definition: SkPath.h:1469
@ kDone_Verb
Definition: SkPath.h:1472
@ kCubic_Verb
Definition: SkPath.h:1470
@ kQuad_Verb
Definition: SkPath.h:1468
@ kLine_Verb
Definition: SkPath.h:1467
void transform(const SkMatrix &matrix, SkPath *dst, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkPath.cpp:1711
static sk_sp< SkPathEffect > Make(SkScalar startT, SkScalar stopT, Mode=Mode::kNormal)
float SkScalar
Definition: extension.cpp:12
static bool b
struct MyStruct a[10]
Dart_NativeFunction function
Definition: fuchsia.cc:51
double y
double x
Optional< SkRect > bounds
Definition: SkRecords.h:189
SkScalar startAngle
Definition: SkRecords.h:250
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 mode
Definition: switches.h:228
Definition: DartTypes.h:13
SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst, const SkRect *cullRect, SkScalar resScale=1)
Definition: SkPathUtils.cpp:23
SkPathOrNull EMSCRIPTEN_KEEPALIVE FromSVGString(std::string str)
bool EMSCRIPTEN_KEEPALIVE ApplySimplify(SkPath &path)
bool ApplyStroke(SkPath &path, StrokeOpts opts)
bool EMSCRIPTEN_KEEPALIVE ApplyAsWinding(SkPath &path)
static const int CLOSE
JSString EMSCRIPTEN_KEEPALIVE ToSVGString(const SkPath &path)
void ApplyReverseAddPath(SkPath &orig, const SkPath &newPath)
void ApplyClose(SkPath &p)
float SkBits2FloatUnsigned(uint32_t floatAsBits)
bool EMSCRIPTEN_KEEPALIVE ApplyPathOp(SkPath &pathOne, const SkPath &pathTwo, SkPathOp op)
SkPath EMSCRIPTEN_KEEPALIVE CopyPath(const SkPath &a)
JSArray EMSCRIPTEN_KEEPALIVE ToCmds(const SkPath &path)
void ApplyCubicTo(SkPath &p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3)
void ApplyMoveTo(SkPath &p, SkScalar x, SkScalar y)
static const int QUAD
void ApplyArcTo(SkPath &p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
void ApplyEllipse(SkPath &path, SkScalar x, SkScalar y, SkScalar radiusX, SkScalar radiusY, SkScalar rotation, SkScalar startAngle, SkScalar endAngle, bool ccw)
SkMatrix toSkMatrix(const SimpleMatrix &sm)
void ApplyConicTo(SkPath &p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w)
bool EMSCRIPTEN_KEEPALIVE IsEmpty(const SkPath &path)
static const int CUBIC
SkPathOrNull EMSCRIPTEN_KEEPALIVE MakeFromOp(const SkPath &pathOne, const SkPath &pathTwo, SkPathOp op)
bool ApplyDash(SkPath &path, SkScalar on, SkScalar off, SkScalar phase)
JSString GetFillTypeString(const SkPath &path)
static const int MOVE
static const int LINE
void ApplyTransform(SkPath &orig, const SimpleMatrix &sm)
bool EMSCRIPTEN_KEEPALIVE Equals(const SkPath &a, const SkPath &b)
#define CHECK_NUM_ARGS(n)
emscripten::val EMSCRIPTEN_KEEPALIVE ToPath2D(const SkPath &path)
SkPathOrNull EMSCRIPTEN_KEEPALIVE ResolveBuilder(SkOpBuilder &builder)
void EMSCRIPTEN_KEEPALIVE ToCanvas(const SkPath &path, emscripten::val ctx)
SkPathOrNull EMSCRIPTEN_KEEPALIVE FromCmds(uintptr_t cptr, int numCmds)
void ApplyQuadTo(SkPath &p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
EMSCRIPTEN_BINDINGS(skia)
void ApplyAddArc(SkPath &path, SkScalar x, SkScalar y, SkScalar radius, SkScalar startAngle, SkScalar endAngle, bool ccw)
bool ApplyTrim(SkPath &path, SkScalar startT, SkScalar stopT, bool isComplement)
static const int CONIC
void ApplyAddRect(SkPath &path, SkScalar x, SkScalar y, SkScalar width, SkScalar height)
void ApplyAddPath(SkPath &orig, const SkPath &newPath, SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar pers0, SkScalar pers1, SkScalar pers2)
emscripten::val JSPath2D
SkPath EMSCRIPTEN_KEEPALIVE NewPath()
void ApplyLineTo(SkPath &p, SkScalar x, SkScalar y)
SkScalar w
int32_t height
int32_t width
float fX
x-axis value
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165
constexpr float y() const
Definition: SkPoint_impl.h:187
constexpr float x() const
Definition: SkPoint_impl.h:181
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
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646
SkScalar fTop
smaller y-axis bounds
Definition: extension.cpp:15
SkPaint::Join join
SkPaint::Cap cap