blob: 9f129b806e915abd1053f326036493c5234a639a [file] [log] [blame]
Kevin Lubick22647d02018-07-06 14:31:23 -04001/*
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
Kevin Lubick92eaa3c2018-07-16 21:00:52 -04008#include "SkFloatBits.h"
Kevin Lubick22647d02018-07-06 14:31:23 -04009#include "SkFloatingPoint.h"
Kevin Lubick641bf872018-08-06 14:49:39 -040010#include "SkMatrix.h"
Kevin Lubick22647d02018-07-06 14:31:23 -040011#include "SkParsePath.h"
12#include "SkPath.h"
13#include "SkPathOps.h"
Kevin Lubick641bf872018-08-06 14:49:39 -040014#include "SkRect.h"
Kevin Lubick92eaa3c2018-07-16 21:00:52 -040015#include "SkRegion.h"
Kevin Lubick22647d02018-07-06 14:31:23 -040016#include "SkString.h"
17
18#include <emscripten/emscripten.h>
19#include <emscripten/bind.h>
20
21using namespace emscripten;
22
23static const int MOVE = 0;
24static const int LINE = 1;
25static const int QUAD = 2;
26static const int CUBIC = 4;
27static const int CLOSE = 5;
28
Kevin Lubick5f0e3a12018-08-07 11:30:12 -040029// Just for self-documenting purposes where the main thing being returned is an
30// SkPath, but in an error case, something of type val (e.g. null) could also be
31// returned;
32using SkPathOrVal = emscripten::val;
33
Kevin Lubick22647d02018-07-06 14:31:23 -040034// =================================================================================
Kevin Lubick641bf872018-08-06 14:49:39 -040035// Creating/Exporting Paths with cmd arrays
Kevin Lubick22647d02018-07-06 14:31:23 -040036// =================================================================================
37
Florin Malitae1824da2018-07-12 10:33:39 -040038template <typename VisitFunc>
39void VisitPath(const SkPath& p, VisitFunc&& f) {
40 SkPath::RawIter iter(p);
Kevin Lubick22647d02018-07-06 14:31:23 -040041 SkPoint pts[4];
42 SkPath::Verb verb;
Florin Malitae1824da2018-07-12 10:33:39 -040043 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
Kevin Lubick641bf872018-08-06 14:49:39 -040044 f(verb, pts, iter);
Kevin Lubick22647d02018-07-06 14:31:23 -040045 }
46}
47
Kevin Lubick641bf872018-08-06 14:49:39 -040048emscripten::val EMSCRIPTEN_KEEPALIVE ToCmds(const SkPath& path) {
Kevin Lubick5f0e3a12018-08-07 11:30:12 -040049 emscripten::val cmds = emscripten::val::array();
Kevin Lubick22647d02018-07-06 14:31:23 -040050
Kevin Lubick641bf872018-08-06 14:49:39 -040051 VisitPath(path, [&cmds](SkPath::Verb verb, const SkPoint pts[4], SkPath::RawIter iter) {
Kevin Lubick5f0e3a12018-08-07 11:30:12 -040052 emscripten::val cmd = emscripten::val::array();
Kevin Lubick22647d02018-07-06 14:31:23 -040053 switch (verb) {
Florin Malitae1824da2018-07-12 10:33:39 -040054 case SkPath::kMove_Verb:
55 cmd.call<void>("push", MOVE, pts[0].x(), pts[0].y());
56 break;
57 case SkPath::kLine_Verb:
58 cmd.call<void>("push", LINE, pts[1].x(), pts[1].y());
59 break;
60 case SkPath::kQuad_Verb:
61 cmd.call<void>("push", QUAD, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
62 break;
63 case SkPath::kConic_Verb:
Kevin Lubick641bf872018-08-06 14:49:39 -040064 SkPoint quads[5];
65 // approximate with 2^1=2 quads.
66 SkPath::ConvertConicToQuads(pts[0], pts[1], pts[2], iter.conicWeight(), quads, 1);
67 cmd.call<void>("push", MOVE, quads[0].x(), quads[0].y());
68 cmds.call<void>("push", cmd);
69 cmd = emscripten::val::array();
70 cmd.call<void>("push", QUAD, quads[1].x(), quads[1].y(), quads[2].x(), quads[2].y());
71 cmds.call<void>("push", cmd);
72 cmd = emscripten::val::array();
73 cmd.call<void>("push", QUAD, quads[3].x(), quads[3].y(), quads[4].x(), quads[4].y());
Florin Malitae1824da2018-07-12 10:33:39 -040074 break;
75 case SkPath::kCubic_Verb:
76 cmd.call<void>("push", CUBIC,
77 pts[1].x(), pts[1].y(),
78 pts[2].x(), pts[2].y(),
79 pts[3].x(), pts[3].y());
80 break;
81 case SkPath::kClose_Verb:
82 cmd.call<void>("push", CLOSE);
83 break;
84 case SkPath::kDone_Verb:
85 SkASSERT(false);
86 break;
Kevin Lubick22647d02018-07-06 14:31:23 -040087 }
88 cmds.call<void>("push", cmd);
Florin Malitae1824da2018-07-12 10:33:39 -040089 });
Kevin Lubick22647d02018-07-06 14:31:23 -040090 return cmds;
91}
92
93// This type signature is a mess, but it's necessary. See, we can't use "bind" (EMSCRIPTEN_BINDINGS)
94// and pointers to primitive types (Only bound types like SkPoint). We could if we used
95// cwrap (see https://becominghuman.ai/passing-and-returning-webassembly-array-parameters-a0f572c65d97)
96// but that requires us to stick to C code and, AFAIK, doesn't allow us to return nice things like
97// SkPath or SkOpBuilder.
98//
99// So, basically, if we are using C++ and EMSCRIPTEN_BINDINGS, we can't have primative pointers
100// in our function type signatures. (this gives an error message like "Cannot call foo due to unbound
101// types Pi, Pf"). But, we can just pretend they are numbers and cast them to be pointers and
102// the compiler is happy.
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400103SkPathOrVal EMSCRIPTEN_KEEPALIVE FromCmds(uintptr_t /* float* */ cptr, int numCmds) {
Florin Malitae1824da2018-07-12 10:33:39 -0400104 const auto* cmds = reinterpret_cast<const float*>(cptr);
Kevin Lubick22647d02018-07-06 14:31:23 -0400105 SkPath path;
106 float x1, y1, x2, y2, x3, y3;
107
108 // if there are not enough arguments, bail with the path we've constructed so far.
109 #define CHECK_NUM_ARGS(n) \
110 if ((i + n) > numCmds) { \
111 SkDebugf("Not enough args to match the verbs. Saw %d commands\n", numCmds); \
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400112 return emscripten::val::null(); \
Kevin Lubick22647d02018-07-06 14:31:23 -0400113 }
114
115 for(int i = 0; i < numCmds;){
116 switch (sk_float_floor2int(cmds[i++])) {
117 case MOVE:
118 CHECK_NUM_ARGS(2);
119 x1 = cmds[i++], y1 = cmds[i++];
120 path.moveTo(x1, y1);
121 break;
122 case LINE:
123 CHECK_NUM_ARGS(2);
124 x1 = cmds[i++], y1 = cmds[i++];
125 path.lineTo(x1, y1);
126 break;
127 case QUAD:
128 CHECK_NUM_ARGS(4);
129 x1 = cmds[i++], y1 = cmds[i++];
130 x2 = cmds[i++], y2 = cmds[i++];
131 path.quadTo(x1, y1, x2, y2);
132 break;
133 case CUBIC:
134 CHECK_NUM_ARGS(6);
135 x1 = cmds[i++], y1 = cmds[i++];
136 x2 = cmds[i++], y2 = cmds[i++];
137 x3 = cmds[i++], y3 = cmds[i++];
138 path.cubicTo(x1, y1, x2, y2, x3, y3);
139 break;
140 case CLOSE:
141 path.close();
142 break;
143 default:
144 SkDebugf(" path: UNKNOWN command %f, aborting dump...\n", cmds[i-1]);
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400145 return emscripten::val::null();
Kevin Lubick22647d02018-07-06 14:31:23 -0400146 }
147 }
148
149 #undef CHECK_NUM_ARGS
150
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400151 return emscripten::val(path);
Kevin Lubick22647d02018-07-06 14:31:23 -0400152}
153
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400154SkPath EMSCRIPTEN_KEEPALIVE NewPath() {
155 return SkPath();
156}
157
Kevin Lubick22647d02018-07-06 14:31:23 -0400158//========================================================================================
Kevin Lubick641bf872018-08-06 14:49:39 -0400159// SVG things
Kevin Lubick22647d02018-07-06 14:31:23 -0400160//========================================================================================
161
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400162emscripten::val EMSCRIPTEN_KEEPALIVE ToSVGString(const SkPath& path) {
Kevin Lubick22647d02018-07-06 14:31:23 -0400163 SkString s;
164 SkParsePath::ToSVGString(path, &s);
165 // Wrapping it in val automatically turns it into a JS string.
166 // Not too sure on performance implications, but is is simpler than
167 // returning a raw pointer to const char * and then using
168 // Pointer_stringify() on the calling side.
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400169 return emscripten::val(s.c_str());
Kevin Lubick22647d02018-07-06 14:31:23 -0400170}
171
172
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400173SkPathOrVal EMSCRIPTEN_KEEPALIVE FromSVGString(std::string str) {
Kevin Lubick22647d02018-07-06 14:31:23 -0400174 SkPath path;
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400175 if (SkParsePath::FromSVGString(str.c_str(), &path)) {
176 return emscripten::val(path);
177 }
178 return emscripten::val::null();
Kevin Lubick22647d02018-07-06 14:31:23 -0400179}
180
181//========================================================================================
Kevin Lubick641bf872018-08-06 14:49:39 -0400182// PATHOP things
Kevin Lubick22647d02018-07-06 14:31:23 -0400183//========================================================================================
184
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400185SkPathOrVal EMSCRIPTEN_KEEPALIVE SimplifyPath(const SkPath& path) {
Kevin Lubick22647d02018-07-06 14:31:23 -0400186 SkPath simple;
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400187 if (Simplify(path, &simple)) {
188 return emscripten::val(simple);
189 }
190 return emscripten::val::null();
Kevin Lubick22647d02018-07-06 14:31:23 -0400191}
192
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400193SkPathOrVal EMSCRIPTEN_KEEPALIVE ApplyPathOp(const SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
Kevin Lubick22647d02018-07-06 14:31:23 -0400194 SkPath path;
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400195 if (Op(pathOne, pathTwo, op, &path)) {
196 return emscripten::val(path);
197 }
198 return emscripten::val::null();
Kevin Lubick22647d02018-07-06 14:31:23 -0400199}
200
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400201SkPathOrVal EMSCRIPTEN_KEEPALIVE ResolveBuilder(SkOpBuilder& builder) {
Kevin Lubick22647d02018-07-06 14:31:23 -0400202 SkPath path;
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400203 if (builder.resolve(&path)) {
204 return emscripten::val(path);
205 }
206 return emscripten::val::null();
Kevin Lubick22647d02018-07-06 14:31:23 -0400207}
208
209//========================================================================================
Kevin Lubick641bf872018-08-06 14:49:39 -0400210// Canvas things
Kevin Lubick22647d02018-07-06 14:31:23 -0400211//========================================================================================
212
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400213void EMSCRIPTEN_KEEPALIVE ToCanvas(const SkPath& path, emscripten::val /* Path2D or Canvas*/ ctx) {
Kevin Lubick22647d02018-07-06 14:31:23 -0400214 SkPath::Iter iter(path, false);
215 SkPoint pts[4];
216 SkPath::Verb verb;
217 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
218 switch (verb) {
219 case SkPath::kMove_Verb:
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400220 ctx.call<void>("moveTo", pts[0].x(), pts[0].y());
Kevin Lubick22647d02018-07-06 14:31:23 -0400221 break;
222 case SkPath::kLine_Verb:
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400223 ctx.call<void>("lineTo", pts[1].x(), pts[1].y());
Kevin Lubick22647d02018-07-06 14:31:23 -0400224 break;
225 case SkPath::kQuad_Verb:
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400226 ctx.call<void>("quadraticCurveTo", pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
Kevin Lubick22647d02018-07-06 14:31:23 -0400227 break;
228 case SkPath::kConic_Verb:
Kevin Lubick641bf872018-08-06 14:49:39 -0400229 SkPoint quads[5];
230 // approximate with 2^1=2 quads.
231 SkPath::ConvertConicToQuads(pts[0], pts[1], pts[2], iter.conicWeight(), quads, 1);
232 ctx.call<void>("moveTo", quads[0].x(), quads[0].y());
233 ctx.call<void>("quadraticCurveTo", quads[1].x(), quads[1].y(), quads[2].x(), quads[2].y());
234 ctx.call<void>("quadraticCurveTo", quads[3].x(), quads[3].y(), quads[4].x(), quads[4].y());
Kevin Lubick22647d02018-07-06 14:31:23 -0400235 break;
236 case SkPath::kCubic_Verb:
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400237 ctx.call<void>("bezierCurveTo", pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y(),
Kevin Lubick22647d02018-07-06 14:31:23 -0400238 pts[3].x(), pts[3].y());
239 break;
240 case SkPath::kClose_Verb:
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400241 ctx.call<void>("closePath");
Kevin Lubick22647d02018-07-06 14:31:23 -0400242 break;
243 case SkPath::kDone_Verb:
244 break;
245 }
246 }
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400247}
248
249emscripten::val JSPath2D = emscripten::val::global("Path2D");
250
Kevin Lubick641bf872018-08-06 14:49:39 -0400251emscripten::val EMSCRIPTEN_KEEPALIVE ToPath2D(const SkPath& path) {
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400252 emscripten::val retVal = JSPath2D.new_();
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400253 ToCanvas(path, retVal);
Kevin Lubick22647d02018-07-06 14:31:23 -0400254 return retVal;
255}
256
Kevin Lubick641bf872018-08-06 14:49:39 -0400257// ======================================================================================
258// Path2D API things
259// ======================================================================================
260void Path2DAddRect(SkPath& path, SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
261 path.addRect(x, y, x+width, y+height);
262}
263
264void Path2DAddArc(SkPath& path, SkScalar x, SkScalar y, SkScalar radius,
265 SkScalar startAngle, SkScalar endAngle, bool ccw) {
266 SkPath temp;
267 SkRect bounds = SkRect::MakeLTRB(x-radius, y-radius, x+radius, y+radius);
268 const auto sweep = SkRadiansToDegrees(endAngle - startAngle) - 360 * ccw;
269 temp.addArc(bounds, SkRadiansToDegrees(startAngle), sweep);
270 path.addPath(temp, SkPath::kExtend_AddPathMode);
271}
272
273void Path2DAddArc(SkPath& path, SkScalar x, SkScalar y, SkScalar radius,
274 SkScalar startAngle, SkScalar endAngle) {
275 Path2DAddArc(path, x, y, radius, startAngle, endAngle, false);
276}
277
278void Path2DAddEllipse(SkPath& path, SkScalar x, SkScalar y, SkScalar radiusX, SkScalar radiusY,
279 SkScalar rotation, SkScalar startAngle, SkScalar endAngle, bool ccw) {
280 // This is easiest to do by making a new path and then extending the current path
281 // (this properly catches the cases of if there's a moveTo before this call or not).
282 SkRect bounds = SkRect::MakeLTRB(x-radiusX, y-radiusY, x+radiusX, y+radiusY);
283 SkPath temp;
284 const auto sweep = SkRadiansToDegrees(endAngle - startAngle) - (360 * ccw);
285 temp.addArc(bounds, SkRadiansToDegrees(startAngle), sweep);
286
287 SkMatrix m;
288 m.setRotate(SkRadiansToDegrees(rotation), x, y);
289 path.addPath(temp, m, SkPath::kExtend_AddPathMode);
290}
291
292void Path2DAddEllipse(SkPath& path, SkScalar x, SkScalar y, SkScalar radiusX, SkScalar radiusY,
293 SkScalar rotation, SkScalar startAngle, SkScalar endAngle) {
294 Path2DAddEllipse(path, x, y, radiusX, radiusY, rotation, startAngle, endAngle, false);
295}
296
297void Path2DAddPath(SkPath& orig, const SkPath& newPath) {
298 orig.addPath(newPath);
299}
300
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400301void Path2DAddPath(SkPath& orig, const SkPath& newPath, emscripten::val /* SVGMatrix*/ t) {
Kevin Lubick641bf872018-08-06 14:49:39 -0400302 SkMatrix m = SkMatrix::MakeAll(
303 t["a"].as<SkScalar>(), t["c"].as<SkScalar>(), t["e"].as<SkScalar>(),
304 t["b"].as<SkScalar>(), t["d"].as<SkScalar>(), t["f"].as<SkScalar>(),
305 0 , 0 , 1);
306 orig.addPath(newPath, m);
307}
308
309// Mimics the order of SVGMatrix, just w/o the SVG Matrix
310// This order is scaleX, skewY, skewX, scaleY, transX, transY
311// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform#Transform_functions
312void Path2DAddPath(SkPath& orig, const SkPath& newPath, SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar e, SkScalar f) {
313 SkMatrix m = SkMatrix::MakeAll(a, c, e,
314 b, d, f,
315 0, 0, 1);
316 orig.addPath(newPath, m);
317}
318
319// Allows for full matix control.
320void Path2DAddPath(SkPath& orig, const SkPath& newPath,
321 SkScalar scaleX, SkScalar skewX, SkScalar transX,
322 SkScalar skewY, SkScalar scaleY, SkScalar transY,
323 SkScalar pers0, SkScalar pers1, SkScalar pers2) {
324 SkMatrix m = SkMatrix::MakeAll(scaleX, skewX , transX,
325 skewY , scaleY, transY,
326 pers0 , pers1 , pers2);
327 orig.addPath(newPath, m);
328}
329
Kevin Lubick92eaa3c2018-07-16 21:00:52 -0400330//========================================================================================
331// Region things
332//========================================================================================
333
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400334#ifdef PATHKIT_TESTING
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400335SkPathOrVal GetBoundaryPathFromRegion(SkRegion& region) {
Kevin Lubick92eaa3c2018-07-16 21:00:52 -0400336 SkPath p;
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400337 if (region.getBoundaryPath(&p)) {
338 return emscripten::val(p);
339 }
340 return emscripten::val::null();
Kevin Lubick92eaa3c2018-07-16 21:00:52 -0400341}
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400342#endif
Kevin Lubick92eaa3c2018-07-16 21:00:52 -0400343
Kevin Lubick22647d02018-07-06 14:31:23 -0400344// Binds the classes to the JS
Kevin Lubick641bf872018-08-06 14:49:39 -0400345//
346// See https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html#non-member-functions-on-the-javascript-prototype
347// for more on binding non-member functions to the JS object, allowing us to rewire
348// various functions. That is, we can make the SkPath we expose appear to have methods
349// that the original SkPath does not, like rect(x, y, width, height) and toPath2D().
350//
351// An important detail for binding non-member functions is that the first argument
352// must be SkPath& (the reference part is very important).
Kevin Lubick22647d02018-07-06 14:31:23 -0400353EMSCRIPTEN_BINDINGS(skia) {
354 class_<SkPath>("SkPath")
355 .constructor<>()
356
Kevin Lubick641bf872018-08-06 14:49:39 -0400357 // Path2D API
358 .function("addPath",
359 select_overload<void(SkPath&, const SkPath&)>(&Path2DAddPath))
360 .function("addPath",
Kevin Lubick5f0e3a12018-08-07 11:30:12 -0400361 select_overload<void(SkPath&, const SkPath&, emscripten::val)>(&Path2DAddPath))
Kevin Lubick641bf872018-08-06 14:49:39 -0400362 .function("arc",
363 select_overload<void(SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&Path2DAddArc))
364 .function("arc",
365 select_overload<void(SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, bool)>(&Path2DAddArc))
366 .function("arcTo",
367 select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::arcTo))
368 .function("bezierCurveTo",
369 select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::cubicTo))
370 .function("closePath", &SkPath::close)
371 .function("ellipse",
372 select_overload<void(SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&Path2DAddEllipse))
373 .function("ellipse",
374 select_overload<void(SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, bool)>(&Path2DAddEllipse))
Kevin Lubick22647d02018-07-06 14:31:23 -0400375 .function("lineTo",
376 select_overload<void(SkScalar, SkScalar)>(&SkPath::lineTo))
Kevin Lubick641bf872018-08-06 14:49:39 -0400377 .function("moveTo",
378 select_overload<void(SkScalar, SkScalar)>(&SkPath::moveTo))
379 .function("quadraticCurveTo",
Kevin Lubick22647d02018-07-06 14:31:23 -0400380 select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::quadTo))
Kevin Lubick641bf872018-08-06 14:49:39 -0400381 .function("rect", &Path2DAddRect)
382
383 // Some shorthand helpers, to mirror SkPath.cpp's API
384 .function("addPath",
385 select_overload<void(SkPath&, const SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&Path2DAddPath))
386 .function("addPath",
387 select_overload<void(SkPath&, const SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&Path2DAddPath))
388 .function("close", &SkPath::close)
Kevin Lubick22647d02018-07-06 14:31:23 -0400389 .function("cubicTo",
390 select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::cubicTo))
Kevin Lubick641bf872018-08-06 14:49:39 -0400391 .function("quadTo",
392 select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::quadTo))
393
394 // PathOps
395 .function("simplify", &SimplifyPath)
396 .function("op", &ApplyPathOp)
397
398 // Exporting
399 .function("toCmds", &ToCmds)
400 .function("toPath2D", &ToPath2D)
401 .function("toCanvas", &ToCanvas)
402 .function("toSVGString", &ToSVGString)
403
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400404#ifdef PATHKIT_TESTING
405 .function("dump", select_overload<void() const>(&SkPath::dump))
406#endif
407 ;
Kevin Lubick22647d02018-07-06 14:31:23 -0400408
409 class_<SkOpBuilder>("SkOpBuilder")
410 .constructor<>()
411
Kevin Lubick641bf872018-08-06 14:49:39 -0400412 .function("add", &SkOpBuilder::add)
413 .function("resolve", &ResolveBuilder);
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400414
415 // Without these function() bindings, the function would be exposed but oblivious to
416 // our types (e.g. SkPath)
417
418 // Import
419 function("FromSVGString", &FromSVGString);
420 function("FromCmds", &FromCmds);
421 function("NewPath", &NewPath);
422 // Path2D is opaque, so we can't read in from it.
423
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400424 // PathOps
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400425 function("ApplyPathOp", &ApplyPathOp);
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400426
427 enum_<SkPathOp>("PathOp")
428 .value("DIFFERENCE", SkPathOp::kDifference_SkPathOp)
429 .value("INTERSECT", SkPathOp::kIntersect_SkPathOp)
430 .value("UNION", SkPathOp::kUnion_SkPathOp)
431 .value("XOR", SkPathOp::kXOR_SkPathOp)
432 .value("REVERSE_DIFFERENCE", SkPathOp::kReverseDifference_SkPathOp);
433
434 constant("MOVE_VERB", MOVE);
435 constant("LINE_VERB", LINE);
436 constant("QUAD_VERB", QUAD);
437 constant("CUBIC_VERB", CUBIC);
438 constant("CLOSE_VERB", CLOSE);
439
440 // coming soon - Stroke
441
442 // coming soon - Matrix
443
444 // coming soon - Bounds/Trim
445
446#ifdef PATHKIT_TESTING
447 function("SkBits2Float", &SkBits2Float);
448
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400449 enum_<SkRegion::Op>("RegionOp")
450 .value("DIFFERENCE", SkRegion::Op::kDifference_Op)
451 .value("INTERSECT", SkRegion::Op::kIntersect_Op)
452 .value("UNION", SkRegion::Op::kUnion_Op)
453 .value("XOR", SkRegion::Op::kXOR_Op)
454 .value("REVERSE_DIFFERENCE", SkRegion::Op::kReverseDifference_Op)
455 .value("REPLACE", SkRegion::Op::kReplace_Op);
456
Kevin Lubick92eaa3c2018-07-16 21:00:52 -0400457 class_<SkRegion>("SkRegion")
458 .constructor<>()
459
460 .function("setRect",
461 select_overload<bool(int32_t, int32_t, int32_t, int32_t)>(&SkRegion::setRect))
462 .function("setPath", &SkRegion::setPath)
463 .function("opLTRB",
464 select_overload<bool(int32_t, int32_t, int32_t, int32_t, SkRegion::Op)>(&SkRegion::op))
465 .function("opRegion",
466 select_overload<bool(const SkRegion&, SkRegion::Op)>(&SkRegion::op))
467 .function("opRegionAB",
Kevin Lubick641bf872018-08-06 14:49:39 -0400468 select_overload<bool(const SkRegion&, const SkRegion&, SkRegion::Op)>(&SkRegion::op))
469
470 .function("getBoundaryPath", &GetBoundaryPathFromRegion);
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400471#endif
Kevin Lubick22647d02018-07-06 14:31:23 -0400472}