Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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);
97 SkPath path;
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
207
208
209//========================================================================================
210// SVG things
211//========================================================================================
212
213JSString EMSCRIPTEN_KEEPALIVE ToSVGString(const SkPath& path) {
214 // Wrapping it in val automatically turns it into a JS string.
215 // Not too sure on performance implications, but is is simpler than
216 // returning a raw pointer to const char * and then using
217 // UTF8ToString() on the calling side.
218 return emscripten::val(SkParsePath::ToSVGString(path).c_str());
219}
220
221
222SkPathOrNull EMSCRIPTEN_KEEPALIVE FromSVGString(std::string str) {
223 SkPath path;
224 if (SkParsePath::FromSVGString(str.c_str(), &path)) {
225 return emscripten::val(path);
226 }
227 return emscripten::val::null();
228}
229
230//========================================================================================
231// PATHOP things
232//========================================================================================
233
234bool EMSCRIPTEN_KEEPALIVE ApplySimplify(SkPath& path) {
235 return Simplify(path, &path);
236}
237
238bool EMSCRIPTEN_KEEPALIVE ApplyPathOp(SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
239 return Op(pathOne, pathTwo, op, &pathOne);
240}
241
242SkPathOrNull EMSCRIPTEN_KEEPALIVE MakeFromOp(const SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
243 SkPath out;
244 if (Op(pathOne, pathTwo, op, &out)) {
245 return emscripten::val(out);
246 }
247 return emscripten::val::null();
248}
249
250SkPathOrNull EMSCRIPTEN_KEEPALIVE ResolveBuilder(SkOpBuilder& builder) {
251 SkPath path;
252 if (builder.resolve(&path)) {
253 return emscripten::val(path);
254 }
255 return emscripten::val::null();
256}
257
258//========================================================================================
259// Canvas things
260//========================================================================================
261
262void EMSCRIPTEN_KEEPALIVE ToCanvas(const SkPath& path, emscripten::val /* Path2D or Canvas*/ ctx) {
263 SkPath::Iter iter(path, false);
264 SkPoint pts[4];
265 SkPath::Verb verb;
266 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
267 switch (verb) {
269 ctx.call<void>("moveTo", pts[0].x(), pts[0].y());
270 break;
272 ctx.call<void>("lineTo", pts[1].x(), pts[1].y());
273 break;
275 ctx.call<void>("quadraticCurveTo", pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
276 break;
278 SkPoint quads[5];
279 // approximate with 2^1=2 quads.
280 SkPath::ConvertConicToQuads(pts[0], pts[1], pts[2], iter.conicWeight(), quads, 1);
281 ctx.call<void>("quadraticCurveTo", quads[1].x(), quads[1].y(), quads[2].x(), quads[2].y());
282 ctx.call<void>("quadraticCurveTo", quads[3].x(), quads[3].y(), quads[4].x(), quads[4].y());
283 break;
285 ctx.call<void>("bezierCurveTo", pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y(),
286 pts[3].x(), pts[3].y());
287 break;
289 ctx.call<void>("closePath");
290 break;
292 break;
293 }
294 }
295}
296
297emscripten::val JSPath2D = emscripten::val::global("Path2D");
298
299emscripten::val EMSCRIPTEN_KEEPALIVE ToPath2D(const SkPath& path) {
300 emscripten::val retVal = JSPath2D.new_();
301 ToCanvas(path, retVal);
302 return retVal;
303}
304
305// ======================================================================================
306// Path2D API things
307// ======================================================================================
309 path.addRect(x, y, x+width, y+height);
310}
311
313 SkScalar startAngle, SkScalar endAngle, bool ccw) {
314 SkPath temp;
315 SkRect bounds = SkRect::MakeLTRB(x-radius, y-radius, x+radius, y+radius);
316 const auto sweep = SkRadiansToDegrees(endAngle - startAngle) - 360 * ccw;
317 temp.addArc(bounds, SkRadiansToDegrees(startAngle), sweep);
318 path.addPath(temp, SkPath::kExtend_AddPathMode);
319}
320
321void ApplyEllipse(SkPath& path, SkScalar x, SkScalar y, SkScalar radiusX, SkScalar radiusY,
322 SkScalar rotation, SkScalar startAngle, SkScalar endAngle, bool ccw) {
323 // This is easiest to do by making a new path and then extending the current path
324 // (this properly catches the cases of if there's a moveTo before this call or not).
325 SkRect bounds = SkRect::MakeLTRB(x-radiusX, y-radiusY, x+radiusX, y+radiusY);
326 SkPath temp;
327 const auto sweep = SkRadiansToDegrees(endAngle - startAngle) - (360 * ccw);
328 temp.addArc(bounds, SkRadiansToDegrees(startAngle), sweep);
329
330 SkMatrix m;
331 m.setRotate(SkRadiansToDegrees(rotation), x, y);
332 path.addPath(temp, m, SkPath::kExtend_AddPathMode);
333}
334
335// Allows for full matix control.
336void ApplyAddPath(SkPath& orig, const SkPath& newPath,
337 SkScalar scaleX, SkScalar skewX, SkScalar transX,
338 SkScalar skewY, SkScalar scaleY, SkScalar transY,
339 SkScalar pers0, SkScalar pers1, SkScalar pers2) {
340 SkMatrix m = SkMatrix::MakeAll(scaleX, skewX , transX,
341 skewY , scaleY, transY,
342 pers0 , pers1 , pers2);
343 orig.addPath(newPath, m);
344}
345
347 if (path.getFillType() == SkPathFillType::kWinding) {
348 return emscripten::val("nonzero");
349 } else if (path.getFillType() == SkPathFillType::kEvenOdd) {
350 return emscripten::val("evenodd");
351 } else {
352 SkDebugf("warning: can't translate inverted filltype to HTML Canvas\n");
353 return emscripten::val("nonzero"); //Use default
354 }
355}
356
357//========================================================================================
358// Path Effects
359//========================================================================================
360
361bool ApplyDash(SkPath& path, SkScalar on, SkScalar off, SkScalar phase) {
362 SkScalar intervals[] = { on, off };
363 auto pe = SkDashPathEffect::Make(intervals, 2, phase);
364 if (!pe) {
365 SkDebugf("Invalid args to dash()\n");
366 return false;
367 }
369 if (pe->filterPath(&path, path, &rec, nullptr)) {
370 return true;
371 }
372 SkDebugf("Could not make dashed path\n");
373 return false;
374}
375
376bool ApplyTrim(SkPath& path, SkScalar startT, SkScalar stopT, bool isComplement) {
378 auto pe = SkTrimPathEffect::Make(startT, stopT, mode);
379 if (!pe) {
380 SkDebugf("Invalid args to trim(): startT and stopT must be in [0,1]\n");
381 return false;
382 }
384 if (pe->filterPath(&path, path, &rec, nullptr)) {
385 return true;
386 }
387 SkDebugf("Could not trim path\n");
388 return false;
389}
390
391struct StrokeOpts {
392 // Default values are set in chaining.js which allows clients
393 // to set any number of them. Otherwise, the binding code complains if
394 // any are omitted.
400};
401
402bool ApplyStroke(SkPath& path, StrokeOpts opts) {
403 SkPaint p;
404 p.setStyle(SkPaint::kStroke_Style);
405 p.setStrokeCap(opts.cap);
406 p.setStrokeJoin(opts.join);
407 p.setStrokeWidth(opts.width);
408 p.setStrokeMiter(opts.miter_limit);
409 // Default to 1.0 if 0 (or an invalid negative number)
410 if (opts.res_scale <= 0) {
411 opts.res_scale = 1.0;
412 }
413 return skpathutils::FillPathWithPaint(path, p, &path, nullptr, opts.res_scale);
414}
415
416//========================================================================================
417// Matrix things
418//========================================================================================
419
425
427 return SkMatrix::MakeAll(sm.scaleX, sm.skewX , sm.transX,
428 sm.skewY , sm.scaleY, sm.transY,
429 sm.pers0 , sm.pers1 , sm.pers2);
430}
431
432void ApplyTransform(SkPath& orig, const SimpleMatrix& sm) {
433 orig.transform(toSkMatrix(sm));
434}
435
437 SkScalar scaleX, SkScalar skewX, SkScalar transX,
438 SkScalar skewY, SkScalar scaleY, SkScalar transY,
439 SkScalar pers0, SkScalar pers1, SkScalar pers2) {
440 SkMatrix m = SkMatrix::MakeAll(scaleX, skewX , transX,
441 skewY , scaleY, transY,
442 pers0 , pers1 , pers2);
443 orig.transform(m);
444}
445
446//========================================================================================
447// Testing things
448//========================================================================================
449
450// The use case for this is on the JS side is something like:
451// PathKit.SkBits2FloatUnsigned(parseInt("0xc0a00000"))
452// to have precise float values for tests. In the C++ tests, we can use SkBits2Float because
453// it takes int32_t, but the JS parseInt basically returns an unsigned int. So, we add in
454// this helper which casts for us on the way to SkBits2Float.
455float SkBits2FloatUnsigned(uint32_t floatAsBits) {
456 return SkBits2Float((int32_t) floatAsBits);
457}
458
459// Binds the classes to the JS
460//
461// See https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html#non-member-functions-on-the-javascript-prototype
462// for more on binding non-member functions to the JS object, allowing us to rewire
463// various functions. That is, we can make the SkPath we expose appear to have methods
464// that the original SkPath does not, like rect(x, y, width, height) and toPath2D().
465//
466// An important detail for binding non-member functions is that the first argument
467// must be SkPath& (the reference part is very important).
468//
469// Note that we can't expose default or optional arguments, but we can have multiple
470// declarations of the same function that take different amounts of arguments.
471// For example, see _transform
472// Additionally, we are perfectly happy to handle default arguments and function
473// overloads in the JS glue code (see chaining.js::addPath() for an example).
475 class_<SkPath>("SkPath")
476 .constructor<>()
477 .constructor<const SkPath&>()
478
479 // Path2D API
480 .function("_addPath", &ApplyAddPath)
481 // 3 additional overloads of addPath are handled in JS bindings
482 .function("_arc", &ApplyAddArc)
483 .function("_arcTo", &ApplyArcTo)
484 //"bezierCurveTo" alias handled in JS bindings
485 .function("_close", &ApplyClose)
486 //"closePath" alias handled in JS bindings
487 .function("_conicTo", &ApplyConicTo)
488 .function("_cubicTo", &ApplyCubicTo)
489
490 .function("_ellipse", &ApplyEllipse)
491 .function("_lineTo", &ApplyLineTo)
492 .function("_moveTo", &ApplyMoveTo)
493 // "quadraticCurveTo" alias handled in JS bindings
494 .function("_quadTo", &ApplyQuadTo)
495 .function("_rect", &ApplyAddRect)
496
497 // Extra features
498 .function("setFillType", select_overload<void(SkPathFillType)>(&SkPath::setFillType))
499 .function("getFillType", &SkPath::getFillType)
500 .function("getFillTypeString", &GetFillTypeString)
501 .function("getBounds", &SkPath::getBounds)
502 .function("computeTightBounds", &SkPath::computeTightBounds)
503 .function("equals", &Equals)
504 .function("copy", &CopyPath)
505
506 // PathEffects
507 .function("_dash", &ApplyDash)
508 .function("_trim", &ApplyTrim)
509 .function("_stroke", &ApplyStroke)
510
511 // Matrix
512 .function("_transform", select_overload<void(SkPath& orig, const SimpleMatrix& sm)>(&ApplyTransform))
513 .function("_transform", select_overload<void(SkPath& orig, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&ApplyTransform))
514
515 // PathOps
516 .function("_simplify", &ApplySimplify)
517 .function("_op", &ApplyPathOp)
518
519 // Exporting
520 .function("toCmds", &ToCmds)
521 .function("toPath2D", &ToPath2D)
522 .function("toCanvas", &ToCanvas)
523 .function("toSVGString", &ToSVGString)
524
525#ifdef PATHKIT_TESTING
526 .function("dump", select_overload<void() const>(&SkPath::dump))
527 .function("dumpHex", select_overload<void() const>(&SkPath::dumpHex))
528#endif
529 ;
530
531 class_<SkOpBuilder>("SkOpBuilder")
532 .constructor<>()
533
534 .function("add", &SkOpBuilder::add)
535 .function("make", &ResolveBuilder)
536 .function("resolve", &ResolveBuilder);
537
538 // Without these function() bindings, the function would be exposed but oblivious to
539 // our types (e.g. SkPath)
540
541 // Import
542 function("FromSVGString", &FromSVGString);
543 function("NewPath", &NewPath);
544 function("NewPath", &CopyPath);
545 // FromCmds is defined in helper.js to make use of TypedArrays transparent.
546 function("_FromCmds", &FromCmds);
547 // Path2D is opaque, so we can't read in from it.
548
549 // PathOps
550 function("MakeFromOp", &MakeFromOp);
551
552 enum_<SkPathOp>("PathOp")
553 .value("DIFFERENCE", SkPathOp::kDifference_SkPathOp)
554 .value("INTERSECT", SkPathOp::kIntersect_SkPathOp)
555 .value("UNION", SkPathOp::kUnion_SkPathOp)
556 .value("XOR", SkPathOp::kXOR_SkPathOp)
557 .value("REVERSE_DIFFERENCE", SkPathOp::kReverseDifference_SkPathOp);
558
559 enum_<SkPathFillType>("FillType")
560 .value("WINDING", SkPathFillType::kWinding)
561 .value("EVENODD", SkPathFillType::kEvenOdd)
562 .value("INVERSE_WINDING", SkPathFillType::kInverseWinding)
563 .value("INVERSE_EVENODD", SkPathFillType::kInverseEvenOdd);
564
565 constant("MOVE_VERB", MOVE);
566 constant("LINE_VERB", LINE);
567 constant("QUAD_VERB", QUAD);
568 constant("CONIC_VERB", CONIC);
569 constant("CUBIC_VERB", CUBIC);
570 constant("CLOSE_VERB", CLOSE);
571
572 // A value object is much simpler than a class - it is returned as a JS
573 // object and does not require delete().
574 // https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html#value-types
575 value_object<SkRect>("SkRect")
576 .field("fLeft", &SkRect::fLeft)
577 .field("fTop", &SkRect::fTop)
578 .field("fRight", &SkRect::fRight)
579 .field("fBottom", &SkRect::fBottom);
580
581 function("LTRBRect", &SkRect::MakeLTRB);
582
583 // Stroke
584 enum_<SkPaint::Join>("StrokeJoin")
585 .value("MITER", SkPaint::Join::kMiter_Join)
586 .value("ROUND", SkPaint::Join::kRound_Join)
587 .value("BEVEL", SkPaint::Join::kBevel_Join);
588
589 enum_<SkPaint::Cap>("StrokeCap")
590 .value("BUTT", SkPaint::Cap::kButt_Cap)
591 .value("ROUND", SkPaint::Cap::kRound_Cap)
592 .value("SQUARE", SkPaint::Cap::kSquare_Cap);
593
594 value_object<StrokeOpts>("StrokeOpts")
595 .field("width", &StrokeOpts::width)
596 .field("miter_limit", &StrokeOpts::miter_limit)
597 .field("res_scale", &StrokeOpts::res_scale)
598 .field("join", &StrokeOpts::join)
599 .field("cap", &StrokeOpts::cap);
600
601 // Matrix
602 // Allows clients to supply a 1D array of 9 elements and the bindings
603 // will automatically turn it into a 3x3 2D matrix.
604 // e.g. path.transform([0,1,2,3,4,5,6,7,8])
605 // This is likely simpler for the client than exposing SkMatrix
606 // directly and requiring them to do a lot of .delete().
607 value_array<SimpleMatrix>("SkMatrix")
608 .element(&SimpleMatrix::scaleX)
609 .element(&SimpleMatrix::skewX)
610 .element(&SimpleMatrix::transX)
611
612 .element(&SimpleMatrix::skewY)
613 .element(&SimpleMatrix::scaleY)
614 .element(&SimpleMatrix::transY)
615
616 .element(&SimpleMatrix::pers0)
617 .element(&SimpleMatrix::pers1)
618 .element(&SimpleMatrix::pers2);
619
620 value_array<SkPoint>("SkPoint")
621 .element(&SkPoint::fX)
622 .element(&SkPoint::fY);
623
624 // Not intended for external clients to call directly.
625 // See helper.js for the client-facing implementation.
626 class_<SkCubicMap>("_SkCubicMap")
627 .constructor<SkPoint, SkPoint>()
628
629 .function("computeYFromX", &SkCubicMap::computeYFromX)
630 .function("computePtFromT", &SkCubicMap::computeFromT);
631
632
633 // Test Utils
634 function("SkBits2FloatUnsigned", &SkBits2FloatUnsigned);
635}
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)
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
emscripten::val SkPathOrNull
Definition WasmCommon.h:30
emscripten::val JSString
Definition WasmCommon.h:29
emscripten::val JSArray
Definition WasmCommon.h:27
SkPath CopyPath(const SkPath &a)
float computeYFromX(float x) const
SkPoint computeFromT(float t) const
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)
@ kRound_Cap
adds circle
Definition SkPaint.h:335
@ kButt_Cap
no stroke extension
Definition SkPaint.h:334
@ kSquare_Cap
adds square
Definition SkPaint.h:336
@ kStroke_Style
set to stroke geometry
Definition SkPaint.h:194
@ kRound_Join
adds circle
Definition SkPaint.h:360
@ kMiter_Join
extends to miter limit
Definition SkPaint.h:359
@ kBevel_Join
connects outside edges
Definition SkPaint.h:361
static SkString ToSVGString(const SkPath &, PathEncoding=PathEncoding::Absolute)
static bool FromSVGString(const char str[], SkPath *)
Verb next(SkPoint pts[4])
Definition SkPath.cpp:1837
SkScalar conicWeight() const
Definition SkPath.h:1527
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:1442
SkRect computeTightBounds() const
Definition SkPath.cpp:3378
void dump() const
Definition SkPath.h:1726
SkPath & addArc(const SkRect &oval, SkScalar startAngle, SkScalar sweepAngle)
Definition SkPath.cpp:1375
static int ConvertConicToQuads(const SkPoint &p0, const SkPoint &p1, const SkPoint &p2, SkScalar w, SkPoint pts[], int pow2)
Definition SkPath.cpp:3174
const SkRect & getBounds() const
Definition SkPath.cpp:420
@ kExtend_AddPathMode
Definition SkPath.h:1285
void dumpHex() const
Definition SkPath.h:1727
@ kClose_Verb
Definition SkPath.h:1463
@ kMove_Verb
Definition SkPath.h:1458
@ kConic_Verb
Definition SkPath.h:1461
@ kDone_Verb
Definition SkPath.h:1464
@ kCubic_Verb
Definition SkPath.h:1462
@ kQuad_Verb
Definition SkPath.h:1460
@ kLine_Verb
Definition SkPath.h:1459
void transform(const SkMatrix &matrix, SkPath *dst, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition SkPath.cpp:1647
@ kHairline_InitStyle
Definition SkStrokeRec.h:25
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
Definition copy.py:1
SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst, const SkRect *cullRect, SkScalar resScale=1)
SkPathOrNull EMSCRIPTEN_KEEPALIVE FromSVGString(std::string str)
bool EMSCRIPTEN_KEEPALIVE ApplySimplify(SkPath &path)
bool ApplyStroke(SkPath &path, StrokeOpts opts)
static const int CLOSE
JSString EMSCRIPTEN_KEEPALIVE ToSVGString(const SkPath &path)
void ApplyClose(SkPath &p)
float SkBits2FloatUnsigned(uint32_t floatAsBits)
bool EMSCRIPTEN_KEEPALIVE ApplyPathOp(SkPath &pathOne, const SkPath &pathTwo, SkPathOp op)
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)
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
float fY
y-axis value
constexpr float y() const
constexpr float x() const
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