blob: 4dc52d6d7d258b50abbb00cbe619376052ee2262 [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
29// =================================================================================
Kevin Lubick641bf872018-08-06 14:49:39 -040030// Creating/Exporting Paths with cmd arrays
Kevin Lubick22647d02018-07-06 14:31:23 -040031// =================================================================================
32
Florin Malitae1824da2018-07-12 10:33:39 -040033template <typename VisitFunc>
34void VisitPath(const SkPath& p, VisitFunc&& f) {
35 SkPath::RawIter iter(p);
Kevin Lubick22647d02018-07-06 14:31:23 -040036 SkPoint pts[4];
37 SkPath::Verb verb;
Florin Malitae1824da2018-07-12 10:33:39 -040038 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
Kevin Lubick641bf872018-08-06 14:49:39 -040039 f(verb, pts, iter);
Kevin Lubick22647d02018-07-06 14:31:23 -040040 }
41}
42
Kevin Lubick641bf872018-08-06 14:49:39 -040043emscripten::val EMSCRIPTEN_KEEPALIVE ToCmds(const SkPath& path) {
44 val cmds = emscripten::val::array();
Kevin Lubick22647d02018-07-06 14:31:23 -040045
Kevin Lubick641bf872018-08-06 14:49:39 -040046 VisitPath(path, [&cmds](SkPath::Verb verb, const SkPoint pts[4], SkPath::RawIter iter) {
47 val cmd = emscripten::val::array();
Kevin Lubick22647d02018-07-06 14:31:23 -040048 switch (verb) {
Florin Malitae1824da2018-07-12 10:33:39 -040049 case SkPath::kMove_Verb:
50 cmd.call<void>("push", MOVE, pts[0].x(), pts[0].y());
51 break;
52 case SkPath::kLine_Verb:
53 cmd.call<void>("push", LINE, pts[1].x(), pts[1].y());
54 break;
55 case SkPath::kQuad_Verb:
56 cmd.call<void>("push", QUAD, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
57 break;
58 case SkPath::kConic_Verb:
Kevin Lubick641bf872018-08-06 14:49:39 -040059 SkPoint quads[5];
60 // approximate with 2^1=2 quads.
61 SkPath::ConvertConicToQuads(pts[0], pts[1], pts[2], iter.conicWeight(), quads, 1);
62 cmd.call<void>("push", MOVE, quads[0].x(), quads[0].y());
63 cmds.call<void>("push", cmd);
64 cmd = emscripten::val::array();
65 cmd.call<void>("push", QUAD, quads[1].x(), quads[1].y(), quads[2].x(), quads[2].y());
66 cmds.call<void>("push", cmd);
67 cmd = emscripten::val::array();
68 cmd.call<void>("push", QUAD, quads[3].x(), quads[3].y(), quads[4].x(), quads[4].y());
Florin Malitae1824da2018-07-12 10:33:39 -040069 break;
70 case SkPath::kCubic_Verb:
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;
76 case SkPath::kClose_Verb:
77 cmd.call<void>("push", CLOSE);
78 break;
79 case SkPath::kDone_Verb:
80 SkASSERT(false);
81 break;
Kevin Lubick22647d02018-07-06 14:31:23 -040082 }
83 cmds.call<void>("push", cmd);
Florin Malitae1824da2018-07-12 10:33:39 -040084 });
Kevin Lubick22647d02018-07-06 14:31:23 -040085 return cmds;
86}
87
88// This type signature is a mess, but it's necessary. See, we can't use "bind" (EMSCRIPTEN_BINDINGS)
89// and pointers to primitive types (Only bound types like SkPoint). We could if we used
90// cwrap (see https://becominghuman.ai/passing-and-returning-webassembly-array-parameters-a0f572c65d97)
91// but that requires us to stick to C code and, AFAIK, doesn't allow us to return nice things like
92// SkPath or SkOpBuilder.
93//
94// So, basically, if we are using C++ and EMSCRIPTEN_BINDINGS, we can't have primative pointers
95// in our function type signatures. (this gives an error message like "Cannot call foo due to unbound
96// types Pi, Pf"). But, we can just pretend they are numbers and cast them to be pointers and
97// the compiler is happy.
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040098SkPath EMSCRIPTEN_KEEPALIVE FromCmds(uintptr_t /* float* */ cptr, int numCmds) {
Florin Malitae1824da2018-07-12 10:33:39 -040099 const auto* cmds = reinterpret_cast<const float*>(cptr);
Kevin Lubick22647d02018-07-06 14:31:23 -0400100 SkPath path;
101 float x1, y1, x2, y2, x3, y3;
102
103 // if there are not enough arguments, bail with the path we've constructed so far.
104 #define CHECK_NUM_ARGS(n) \
105 if ((i + n) > numCmds) { \
106 SkDebugf("Not enough args to match the verbs. Saw %d commands\n", numCmds); \
107 return path; \
108 }
109
110 for(int i = 0; i < numCmds;){
111 switch (sk_float_floor2int(cmds[i++])) {
112 case MOVE:
113 CHECK_NUM_ARGS(2);
114 x1 = cmds[i++], y1 = cmds[i++];
115 path.moveTo(x1, y1);
116 break;
117 case LINE:
118 CHECK_NUM_ARGS(2);
119 x1 = cmds[i++], y1 = cmds[i++];
120 path.lineTo(x1, y1);
121 break;
122 case QUAD:
123 CHECK_NUM_ARGS(4);
124 x1 = cmds[i++], y1 = cmds[i++];
125 x2 = cmds[i++], y2 = cmds[i++];
126 path.quadTo(x1, y1, x2, y2);
127 break;
128 case CUBIC:
129 CHECK_NUM_ARGS(6);
130 x1 = cmds[i++], y1 = cmds[i++];
131 x2 = cmds[i++], y2 = cmds[i++];
132 x3 = cmds[i++], y3 = cmds[i++];
133 path.cubicTo(x1, y1, x2, y2, x3, y3);
134 break;
135 case CLOSE:
136 path.close();
137 break;
138 default:
139 SkDebugf(" path: UNKNOWN command %f, aborting dump...\n", cmds[i-1]);
140 return path;
141 }
142 }
143
144 #undef CHECK_NUM_ARGS
145
146 return path;
147}
148
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400149SkPath EMSCRIPTEN_KEEPALIVE NewPath() {
150 return SkPath();
151}
152
Kevin Lubick22647d02018-07-06 14:31:23 -0400153//========================================================================================
Kevin Lubick641bf872018-08-06 14:49:39 -0400154// SVG things
Kevin Lubick22647d02018-07-06 14:31:23 -0400155//========================================================================================
156
Kevin Lubick641bf872018-08-06 14:49:39 -0400157val EMSCRIPTEN_KEEPALIVE ToSVGString(const SkPath& path) {
Kevin Lubick22647d02018-07-06 14:31:23 -0400158 SkString s;
159 SkParsePath::ToSVGString(path, &s);
160 // Wrapping it in val automatically turns it into a JS string.
161 // Not too sure on performance implications, but is is simpler than
162 // returning a raw pointer to const char * and then using
163 // Pointer_stringify() on the calling side.
164 return val(s.c_str());
165}
166
167
168SkPath EMSCRIPTEN_KEEPALIVE FromSVGString(std::string str) {
169 SkPath path;
170 SkParsePath::FromSVGString(str.c_str(), &path);
171 return path;
172}
173
174//========================================================================================
Kevin Lubick641bf872018-08-06 14:49:39 -0400175// PATHOP things
Kevin Lubick22647d02018-07-06 14:31:23 -0400176//========================================================================================
177
Kevin Lubick641bf872018-08-06 14:49:39 -0400178SkPath EMSCRIPTEN_KEEPALIVE SimplifyPath(const SkPath& path) {
Kevin Lubick22647d02018-07-06 14:31:23 -0400179 SkPath simple;
180 Simplify(path, &simple);
181 return simple;
182}
183
Kevin Lubick641bf872018-08-06 14:49:39 -0400184SkPath EMSCRIPTEN_KEEPALIVE ApplyPathOp(const SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
Kevin Lubick22647d02018-07-06 14:31:23 -0400185 SkPath path;
186 Op(pathOne, pathTwo, op, &path);
187 return path;
188}
189
Kevin Lubick641bf872018-08-06 14:49:39 -0400190SkPath EMSCRIPTEN_KEEPALIVE ResolveBuilder(SkOpBuilder& builder) {
Kevin Lubick22647d02018-07-06 14:31:23 -0400191 SkPath path;
192 builder.resolve(&path);
193 return path;
194}
195
196//========================================================================================
Kevin Lubick641bf872018-08-06 14:49:39 -0400197// Canvas things
Kevin Lubick22647d02018-07-06 14:31:23 -0400198//========================================================================================
199
Kevin Lubick641bf872018-08-06 14:49:39 -0400200void EMSCRIPTEN_KEEPALIVE ToCanvas(const SkPath& path, val/* Path2D or Canvas*/ ctx) {
Kevin Lubick22647d02018-07-06 14:31:23 -0400201 SkPath::Iter iter(path, false);
202 SkPoint pts[4];
203 SkPath::Verb verb;
204 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
205 switch (verb) {
206 case SkPath::kMove_Verb:
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400207 ctx.call<void>("moveTo", pts[0].x(), pts[0].y());
Kevin Lubick22647d02018-07-06 14:31:23 -0400208 break;
209 case SkPath::kLine_Verb:
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400210 ctx.call<void>("lineTo", pts[1].x(), pts[1].y());
Kevin Lubick22647d02018-07-06 14:31:23 -0400211 break;
212 case SkPath::kQuad_Verb:
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400213 ctx.call<void>("quadraticCurveTo", pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
Kevin Lubick22647d02018-07-06 14:31:23 -0400214 break;
215 case SkPath::kConic_Verb:
Kevin Lubick641bf872018-08-06 14:49:39 -0400216 SkPoint quads[5];
217 // approximate with 2^1=2 quads.
218 SkPath::ConvertConicToQuads(pts[0], pts[1], pts[2], iter.conicWeight(), quads, 1);
219 ctx.call<void>("moveTo", quads[0].x(), quads[0].y());
220 ctx.call<void>("quadraticCurveTo", quads[1].x(), quads[1].y(), quads[2].x(), quads[2].y());
221 ctx.call<void>("quadraticCurveTo", quads[3].x(), quads[3].y(), quads[4].x(), quads[4].y());
Kevin Lubick22647d02018-07-06 14:31:23 -0400222 break;
223 case SkPath::kCubic_Verb:
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400224 ctx.call<void>("bezierCurveTo", pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y(),
Kevin Lubick22647d02018-07-06 14:31:23 -0400225 pts[3].x(), pts[3].y());
226 break;
227 case SkPath::kClose_Verb:
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400228 ctx.call<void>("closePath");
Kevin Lubick22647d02018-07-06 14:31:23 -0400229 break;
230 case SkPath::kDone_Verb:
231 break;
232 }
233 }
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400234}
235
236emscripten::val JSPath2D = emscripten::val::global("Path2D");
237
Kevin Lubick641bf872018-08-06 14:49:39 -0400238emscripten::val EMSCRIPTEN_KEEPALIVE ToPath2D(const SkPath& path) {
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400239 val retVal = JSPath2D.new_();
240 ToCanvas(path, retVal);
Kevin Lubick22647d02018-07-06 14:31:23 -0400241 return retVal;
242}
243
Kevin Lubick641bf872018-08-06 14:49:39 -0400244// ======================================================================================
245// Path2D API things
246// ======================================================================================
247void Path2DAddRect(SkPath& path, SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
248 path.addRect(x, y, x+width, y+height);
249}
250
251void Path2DAddArc(SkPath& path, SkScalar x, SkScalar y, SkScalar radius,
252 SkScalar startAngle, SkScalar endAngle, bool ccw) {
253 SkPath temp;
254 SkRect bounds = SkRect::MakeLTRB(x-radius, y-radius, x+radius, y+radius);
255 const auto sweep = SkRadiansToDegrees(endAngle - startAngle) - 360 * ccw;
256 temp.addArc(bounds, SkRadiansToDegrees(startAngle), sweep);
257 path.addPath(temp, SkPath::kExtend_AddPathMode);
258}
259
260void Path2DAddArc(SkPath& path, SkScalar x, SkScalar y, SkScalar radius,
261 SkScalar startAngle, SkScalar endAngle) {
262 Path2DAddArc(path, x, y, radius, startAngle, endAngle, false);
263}
264
265void Path2DAddEllipse(SkPath& path, SkScalar x, SkScalar y, SkScalar radiusX, SkScalar radiusY,
266 SkScalar rotation, SkScalar startAngle, SkScalar endAngle, bool ccw) {
267 // This is easiest to do by making a new path and then extending the current path
268 // (this properly catches the cases of if there's a moveTo before this call or not).
269 SkRect bounds = SkRect::MakeLTRB(x-radiusX, y-radiusY, x+radiusX, y+radiusY);
270 SkPath temp;
271 const auto sweep = SkRadiansToDegrees(endAngle - startAngle) - (360 * ccw);
272 temp.addArc(bounds, SkRadiansToDegrees(startAngle), sweep);
273
274 SkMatrix m;
275 m.setRotate(SkRadiansToDegrees(rotation), x, y);
276 path.addPath(temp, m, SkPath::kExtend_AddPathMode);
277}
278
279void Path2DAddEllipse(SkPath& path, SkScalar x, SkScalar y, SkScalar radiusX, SkScalar radiusY,
280 SkScalar rotation, SkScalar startAngle, SkScalar endAngle) {
281 Path2DAddEllipse(path, x, y, radiusX, radiusY, rotation, startAngle, endAngle, false);
282}
283
284void Path2DAddPath(SkPath& orig, const SkPath& newPath) {
285 orig.addPath(newPath);
286}
287
288void Path2DAddPath(SkPath& orig, const SkPath& newPath, val /* SVGMatrix*/ t) {
289 SkMatrix m = SkMatrix::MakeAll(
290 t["a"].as<SkScalar>(), t["c"].as<SkScalar>(), t["e"].as<SkScalar>(),
291 t["b"].as<SkScalar>(), t["d"].as<SkScalar>(), t["f"].as<SkScalar>(),
292 0 , 0 , 1);
293 orig.addPath(newPath, m);
294}
295
296// Mimics the order of SVGMatrix, just w/o the SVG Matrix
297// This order is scaleX, skewY, skewX, scaleY, transX, transY
298// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform#Transform_functions
299void Path2DAddPath(SkPath& orig, const SkPath& newPath, SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar e, SkScalar f) {
300 SkMatrix m = SkMatrix::MakeAll(a, c, e,
301 b, d, f,
302 0, 0, 1);
303 orig.addPath(newPath, m);
304}
305
306// Allows for full matix control.
307void Path2DAddPath(SkPath& orig, const SkPath& newPath,
308 SkScalar scaleX, SkScalar skewX, SkScalar transX,
309 SkScalar skewY, SkScalar scaleY, SkScalar transY,
310 SkScalar pers0, SkScalar pers1, SkScalar pers2) {
311 SkMatrix m = SkMatrix::MakeAll(scaleX, skewX , transX,
312 skewY , scaleY, transY,
313 pers0 , pers1 , pers2);
314 orig.addPath(newPath, m);
315}
316
Kevin Lubick92eaa3c2018-07-16 21:00:52 -0400317//========================================================================================
318// Region things
319//========================================================================================
320
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400321#ifdef PATHKIT_TESTING
Kevin Lubick641bf872018-08-06 14:49:39 -0400322SkPath GetBoundaryPathFromRegion(SkRegion& region) {
Kevin Lubick92eaa3c2018-07-16 21:00:52 -0400323 SkPath p;
324 region.getBoundaryPath(&p);
325 return p;
326}
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400327#endif
Kevin Lubick92eaa3c2018-07-16 21:00:52 -0400328
Kevin Lubick22647d02018-07-06 14:31:23 -0400329// Binds the classes to the JS
Kevin Lubick641bf872018-08-06 14:49:39 -0400330//
331// See https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html#non-member-functions-on-the-javascript-prototype
332// for more on binding non-member functions to the JS object, allowing us to rewire
333// various functions. That is, we can make the SkPath we expose appear to have methods
334// that the original SkPath does not, like rect(x, y, width, height) and toPath2D().
335//
336// An important detail for binding non-member functions is that the first argument
337// must be SkPath& (the reference part is very important).
Kevin Lubick22647d02018-07-06 14:31:23 -0400338EMSCRIPTEN_BINDINGS(skia) {
339 class_<SkPath>("SkPath")
340 .constructor<>()
341
Kevin Lubick641bf872018-08-06 14:49:39 -0400342 // Path2D API
343 .function("addPath",
344 select_overload<void(SkPath&, const SkPath&)>(&Path2DAddPath))
345 .function("addPath",
346 select_overload<void(SkPath&, const SkPath&, val)>(&Path2DAddPath))
347 .function("arc",
348 select_overload<void(SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&Path2DAddArc))
349 .function("arc",
350 select_overload<void(SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, bool)>(&Path2DAddArc))
351 .function("arcTo",
352 select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::arcTo))
353 .function("bezierCurveTo",
354 select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::cubicTo))
355 .function("closePath", &SkPath::close)
356 .function("ellipse",
357 select_overload<void(SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&Path2DAddEllipse))
358 .function("ellipse",
359 select_overload<void(SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, bool)>(&Path2DAddEllipse))
Kevin Lubick22647d02018-07-06 14:31:23 -0400360 .function("lineTo",
361 select_overload<void(SkScalar, SkScalar)>(&SkPath::lineTo))
Kevin Lubick641bf872018-08-06 14:49:39 -0400362 .function("moveTo",
363 select_overload<void(SkScalar, SkScalar)>(&SkPath::moveTo))
364 .function("quadraticCurveTo",
Kevin Lubick22647d02018-07-06 14:31:23 -0400365 select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::quadTo))
Kevin Lubick641bf872018-08-06 14:49:39 -0400366 .function("rect", &Path2DAddRect)
367
368 // Some shorthand helpers, to mirror SkPath.cpp's API
369 .function("addPath",
370 select_overload<void(SkPath&, const SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&Path2DAddPath))
371 .function("addPath",
372 select_overload<void(SkPath&, const SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&Path2DAddPath))
373 .function("close", &SkPath::close)
Kevin Lubick22647d02018-07-06 14:31:23 -0400374 .function("cubicTo",
375 select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::cubicTo))
Kevin Lubick641bf872018-08-06 14:49:39 -0400376 .function("quadTo",
377 select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::quadTo))
378
379 // PathOps
380 .function("simplify", &SimplifyPath)
381 .function("op", &ApplyPathOp)
382
383 // Exporting
384 .function("toCmds", &ToCmds)
385 .function("toPath2D", &ToPath2D)
386 .function("toCanvas", &ToCanvas)
387 .function("toSVGString", &ToSVGString)
388
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400389#ifdef PATHKIT_TESTING
390 .function("dump", select_overload<void() const>(&SkPath::dump))
391#endif
392 ;
Kevin Lubick22647d02018-07-06 14:31:23 -0400393
394 class_<SkOpBuilder>("SkOpBuilder")
395 .constructor<>()
396
Kevin Lubick641bf872018-08-06 14:49:39 -0400397 .function("add", &SkOpBuilder::add)
398 .function("resolve", &ResolveBuilder);
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400399
400 // Without these function() bindings, the function would be exposed but oblivious to
401 // our types (e.g. SkPath)
402
403 // Import
404 function("FromSVGString", &FromSVGString);
405 function("FromCmds", &FromCmds);
406 function("NewPath", &NewPath);
407 // Path2D is opaque, so we can't read in from it.
408
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400409 // PathOps
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400410 function("ApplyPathOp", &ApplyPathOp);
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400411
412 enum_<SkPathOp>("PathOp")
413 .value("DIFFERENCE", SkPathOp::kDifference_SkPathOp)
414 .value("INTERSECT", SkPathOp::kIntersect_SkPathOp)
415 .value("UNION", SkPathOp::kUnion_SkPathOp)
416 .value("XOR", SkPathOp::kXOR_SkPathOp)
417 .value("REVERSE_DIFFERENCE", SkPathOp::kReverseDifference_SkPathOp);
418
419 constant("MOVE_VERB", MOVE);
420 constant("LINE_VERB", LINE);
421 constant("QUAD_VERB", QUAD);
422 constant("CUBIC_VERB", CUBIC);
423 constant("CLOSE_VERB", CLOSE);
424
425 // coming soon - Stroke
426
427 // coming soon - Matrix
428
429 // coming soon - Bounds/Trim
430
431#ifdef PATHKIT_TESTING
432 function("SkBits2Float", &SkBits2Float);
433
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400434 enum_<SkRegion::Op>("RegionOp")
435 .value("DIFFERENCE", SkRegion::Op::kDifference_Op)
436 .value("INTERSECT", SkRegion::Op::kIntersect_Op)
437 .value("UNION", SkRegion::Op::kUnion_Op)
438 .value("XOR", SkRegion::Op::kXOR_Op)
439 .value("REVERSE_DIFFERENCE", SkRegion::Op::kReverseDifference_Op)
440 .value("REPLACE", SkRegion::Op::kReplace_Op);
441
Kevin Lubick92eaa3c2018-07-16 21:00:52 -0400442 class_<SkRegion>("SkRegion")
443 .constructor<>()
444
445 .function("setRect",
446 select_overload<bool(int32_t, int32_t, int32_t, int32_t)>(&SkRegion::setRect))
447 .function("setPath", &SkRegion::setPath)
448 .function("opLTRB",
449 select_overload<bool(int32_t, int32_t, int32_t, int32_t, SkRegion::Op)>(&SkRegion::op))
450 .function("opRegion",
451 select_overload<bool(const SkRegion&, SkRegion::Op)>(&SkRegion::op))
452 .function("opRegionAB",
Kevin Lubick641bf872018-08-06 14:49:39 -0400453 select_overload<bool(const SkRegion&, const SkRegion&, SkRegion::Op)>(&SkRegion::op))
454
455 .function("getBoundaryPath", &GetBoundaryPathFromRegion);
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400456#endif
Kevin Lubick22647d02018-07-06 14:31:23 -0400457}