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