1 /*
2 * Copyright 2018 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #if SK_SUPPORT_GPU
9 #include "GrBackendSurface.h"
10 #include "GrContext.h"
11 #include "GrGLInterface.h"
12 #include "GrGLTypes.h"
13 #endif
14
15 #include "SkBlendMode.h"
16 #include "SkBlurTypes.h"
17 #include "SkCanvas.h"
18 #include "SkColor.h"
19 #include "SkCornerPathEffect.h"
20 #include "SkDashPathEffect.h"
21 #include "SkData.h"
22 #include "SkDiscretePathEffect.h"
23 #include "SkEncodedImageFormat.h"
24 #include "SkFilterQuality.h"
25 #include "SkFont.h"
26 #include "SkFontMgr.h"
27 #include "SkFontMgrPriv.h"
28 #include "SkFontTypes.h"
29 #include "SkGradientShader.h"
30 #include "SkImage.h"
31 #include "SkImageInfo.h"
32 #include "SkImageShader.h"
33 #include "SkMakeUnique.h"
34 #include "SkMaskFilter.h"
35 #include "SkPaint.h"
36 #include "SkParsePath.h"
37 #include "SkPath.h"
38 #include "SkPathEffect.h"
39 #include "SkPathOps.h"
40 #include "SkScalar.h"
41 #include "SkShader.h"
42 #include "SkShadowUtils.h"
43 #include "SkString.h"
44 #include "SkStrokeRec.h"
45 #include "SkSurface.h"
46 #include "SkSurfaceProps.h"
47 #include "SkTextBlob.h"
48 #include "SkTrimPathEffect.h"
49 #include "SkTypeface.h"
50 #include "SkTypes.h"
51 #include "SkVertices.h"
52
53 #include <iostream>
54 #include <string>
55
56 #include "WasmAliases.h"
57 #include <emscripten.h>
58 #include <emscripten/bind.h>
59
60 #if SK_SUPPORT_GPU
61 #include <GL/gl.h>
62 #include <emscripten/html5.h>
63 #endif
64
65 // Aliases for less typing
66 using BoneIndices = SkVertices::BoneIndices;
67 using BoneWeights = SkVertices::BoneWeights;
68 using Bone = SkVertices::Bone;
69
70 #if SK_SUPPORT_GPU
71 // Wraps the WebGL context in an SkSurface and returns it.
72 // This function based on the work of
73 // https://github.com/Zubnix/skia-wasm-port/, used under the terms of the MIT license.
getWebGLSurface(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context,int width,int height)74 sk_sp<SkSurface> getWebGLSurface(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context, int width, int height) {
75 EMSCRIPTEN_RESULT r = emscripten_webgl_make_context_current(context);
76 if (r < 0) {
77 printf("failed to make webgl context current %d\n", r);
78 return nullptr;
79 }
80
81 glClearColor(0, 0, 0, 0);
82 glClearStencil(0);
83 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
84
85 // setup GrContext
86 auto interface = GrGLMakeNativeInterface();
87
88 // setup contexts
89 sk_sp<GrContext> grContext(GrContext::MakeGL(interface));
90
91 // Wrap the frame buffer object attached to the screen in a Skia render target so Skia can
92 // render to it
93 GrGLint buffer;
94 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &buffer);
95 GrGLFramebufferInfo info;
96 info.fFBOID = (GrGLuint) buffer;
97 SkColorType colorType;
98
99 info.fFormat = GL_RGBA8;
100 colorType = kRGBA_8888_SkColorType;
101
102 GrBackendRenderTarget target(width, height, 0, 8, info);
103
104 sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget(grContext.get(), target,
105 kBottomLeft_GrSurfaceOrigin,
106 colorType, nullptr, nullptr));
107 return surface;
108 }
109 #endif
110
111 struct SimpleMatrix {
112 SkScalar scaleX, skewX, transX;
113 SkScalar skewY, scaleY, transY;
114 SkScalar pers0, pers1, pers2;
115 };
116
toSkMatrix(const SimpleMatrix & sm)117 SkMatrix toSkMatrix(const SimpleMatrix& sm) {
118 return SkMatrix::MakeAll(sm.scaleX, sm.skewX , sm.transX,
119 sm.skewY , sm.scaleY, sm.transY,
120 sm.pers0 , sm.pers1 , sm.pers2);
121 }
122
toSimpleSkMatrix(const SkMatrix & sm)123 SimpleMatrix toSimpleSkMatrix(const SkMatrix& sm) {
124 SimpleMatrix m {sm[0], sm[1], sm[2],
125 sm[3], sm[4], sm[5],
126 sm[6], sm[7], sm[8]};
127 return m;
128 }
129
130 struct SimpleImageInfo {
131 int width;
132 int height;
133 SkColorType colorType;
134 SkAlphaType alphaType;
135 // TODO color spaces?
136 };
137
toSkImageInfo(const SimpleImageInfo & sii)138 SkImageInfo toSkImageInfo(const SimpleImageInfo& sii) {
139 return SkImageInfo::Make(sii.width, sii.height, sii.colorType, sii.alphaType);
140 }
141
142 //========================================================================================
143 // Path things
144 //========================================================================================
145
146 // All these Apply* methods are simple wrappers to avoid returning an object.
147 // The default WASM bindings produce code that will leak if a return value
148 // isn't assigned to a JS variable and has delete() called on it.
149 // These Apply methods, combined with the smarter binding code allow for chainable
150 // commands that don't leak if the return value is ignored (i.e. when used intuitively).
151
ApplyAddArc(SkPath & orig,const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle)152 void ApplyAddArc(SkPath& orig, const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle) {
153 orig.addArc(oval, startAngle, sweepAngle);
154 }
155
ApplyAddPath(SkPath & orig,const SkPath & newPath,SkScalar scaleX,SkScalar skewX,SkScalar transX,SkScalar skewY,SkScalar scaleY,SkScalar transY,SkScalar pers0,SkScalar pers1,SkScalar pers2,bool extendPath)156 void ApplyAddPath(SkPath& orig, const SkPath& newPath,
157 SkScalar scaleX, SkScalar skewX, SkScalar transX,
158 SkScalar skewY, SkScalar scaleY, SkScalar transY,
159 SkScalar pers0, SkScalar pers1, SkScalar pers2,
160 bool extendPath) {
161 SkMatrix m = SkMatrix::MakeAll(scaleX, skewX , transX,
162 skewY , scaleY, transY,
163 pers0 , pers1 , pers2);
164 orig.addPath(newPath, m, extendPath ? SkPath::kExtend_AddPathMode :
165 SkPath::kAppend_AddPathMode);
166 }
167
ApplyAddRect(SkPath & path,SkScalar left,SkScalar top,SkScalar right,SkScalar bottom,bool ccw)168 void ApplyAddRect(SkPath& path, SkScalar left, SkScalar top,
169 SkScalar right, SkScalar bottom, bool ccw) {
170 path.addRect(left, top, right, bottom,
171 ccw ? SkPath::Direction::kCCW_Direction :
172 SkPath::Direction::kCW_Direction);
173 }
174
ApplyAddRoundRect(SkPath & path,SkScalar left,SkScalar top,SkScalar right,SkScalar bottom,uintptr_t rPtr,bool ccw)175 void ApplyAddRoundRect(SkPath& path, SkScalar left, SkScalar top,
176 SkScalar right, SkScalar bottom, uintptr_t /* SkScalar* */ rPtr,
177 bool ccw) {
178 // See comment below for uintptr_t explanation
179 const SkScalar* radii = reinterpret_cast<const SkScalar*>(rPtr);
180 path.addRoundRect(SkRect::MakeLTRB(left, top, right, bottom), radii,
181 ccw ? SkPath::Direction::kCCW_Direction : SkPath::Direction::kCW_Direction);
182 }
183
184
ApplyArcTo(SkPath & p,SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2,SkScalar radius)185 void ApplyArcTo(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
186 SkScalar radius) {
187 p.arcTo(x1, y1, x2, y2, radius);
188 }
189
ApplyArcToAngle(SkPath & p,SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool forceMoveTo)190 void ApplyArcToAngle(SkPath& p, SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) {
191 p.arcTo(oval, startAngle, sweepAngle, forceMoveTo);
192 }
193
ApplyClose(SkPath & p)194 void ApplyClose(SkPath& p) {
195 p.close();
196 }
197
ApplyConicTo(SkPath & p,SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2,SkScalar w)198 void ApplyConicTo(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
199 SkScalar w) {
200 p.conicTo(x1, y1, x2, y2, w);
201 }
202
ApplyCubicTo(SkPath & p,SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2,SkScalar x3,SkScalar y3)203 void ApplyCubicTo(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
204 SkScalar x3, SkScalar y3) {
205 p.cubicTo(x1, y1, x2, y2, x3, y3);
206 }
207
ApplyLineTo(SkPath & p,SkScalar x,SkScalar y)208 void ApplyLineTo(SkPath& p, SkScalar x, SkScalar y) {
209 p.lineTo(x, y);
210 }
211
ApplyMoveTo(SkPath & p,SkScalar x,SkScalar y)212 void ApplyMoveTo(SkPath& p, SkScalar x, SkScalar y) {
213 p.moveTo(x, y);
214 }
215
ApplyReset(SkPath & p)216 void ApplyReset(SkPath& p) {
217 p.reset();
218 }
219
ApplyRewind(SkPath & p)220 void ApplyRewind(SkPath& p) {
221 p.rewind();
222 }
223
ApplyQuadTo(SkPath & p,SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2)224 void ApplyQuadTo(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
225 p.quadTo(x1, y1, x2, y2);
226 }
227
ApplyTransform(SkPath & orig,SkScalar scaleX,SkScalar skewX,SkScalar transX,SkScalar skewY,SkScalar scaleY,SkScalar transY,SkScalar pers0,SkScalar pers1,SkScalar pers2)228 void ApplyTransform(SkPath& orig,
229 SkScalar scaleX, SkScalar skewX, SkScalar transX,
230 SkScalar skewY, SkScalar scaleY, SkScalar transY,
231 SkScalar pers0, SkScalar pers1, SkScalar pers2) {
232 SkMatrix m = SkMatrix::MakeAll(scaleX, skewX , transX,
233 skewY , scaleY, transY,
234 pers0 , pers1 , pers2);
235 orig.transform(m);
236 }
237
ApplySimplify(SkPath & path)238 bool EMSCRIPTEN_KEEPALIVE ApplySimplify(SkPath& path) {
239 return Simplify(path, &path);
240 }
241
ApplyPathOp(SkPath & pathOne,const SkPath & pathTwo,SkPathOp op)242 bool EMSCRIPTEN_KEEPALIVE ApplyPathOp(SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
243 return Op(pathOne, pathTwo, op, &pathOne);
244 }
245
ToSVGString(const SkPath & path)246 JSString EMSCRIPTEN_KEEPALIVE ToSVGString(const SkPath& path) {
247 SkString s;
248 SkParsePath::ToSVGString(path, &s);
249 return emscripten::val(s.c_str());
250 }
251
MakePathFromSVGString(std::string str)252 SkPathOrNull EMSCRIPTEN_KEEPALIVE MakePathFromSVGString(std::string str) {
253 SkPath path;
254 if (SkParsePath::FromSVGString(str.c_str(), &path)) {
255 return emscripten::val(path);
256 }
257 return emscripten::val::null();
258 }
259
MakePathFromOp(const SkPath & pathOne,const SkPath & pathTwo,SkPathOp op)260 SkPathOrNull EMSCRIPTEN_KEEPALIVE MakePathFromOp(const SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
261 SkPath out;
262 if (Op(pathOne, pathTwo, op, &out)) {
263 return emscripten::val(out);
264 }
265 return emscripten::val::null();
266 }
267
CopyPath(const SkPath & a)268 SkPath EMSCRIPTEN_KEEPALIVE CopyPath(const SkPath& a) {
269 SkPath copy(a);
270 return copy;
271 }
272
Equals(const SkPath & a,const SkPath & b)273 bool EMSCRIPTEN_KEEPALIVE Equals(const SkPath& a, const SkPath& b) {
274 return a == b;
275 }
276
277 // =================================================================================
278 // Creating/Exporting Paths with cmd arrays
279 // =================================================================================
280
281 static const int MOVE = 0;
282 static const int LINE = 1;
283 static const int QUAD = 2;
284 static const int CONIC = 3;
285 static const int CUBIC = 4;
286 static const int CLOSE = 5;
287
288 template <typename VisitFunc>
VisitPath(const SkPath & p,VisitFunc && f)289 void VisitPath(const SkPath& p, VisitFunc&& f) {
290 SkPath::RawIter iter(p);
291 SkPoint pts[4];
292 SkPath::Verb verb;
293 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
294 f(verb, pts, iter);
295 }
296 }
297
ToCmds(const SkPath & path)298 JSArray EMSCRIPTEN_KEEPALIVE ToCmds(const SkPath& path) {
299 JSArray cmds = emscripten::val::array();
300
301 VisitPath(path, [&cmds](SkPath::Verb verb, const SkPoint pts[4], SkPath::RawIter iter) {
302 JSArray cmd = emscripten::val::array();
303 switch (verb) {
304 case SkPath::kMove_Verb:
305 cmd.call<void>("push", MOVE, pts[0].x(), pts[0].y());
306 break;
307 case SkPath::kLine_Verb:
308 cmd.call<void>("push", LINE, pts[1].x(), pts[1].y());
309 break;
310 case SkPath::kQuad_Verb:
311 cmd.call<void>("push", QUAD, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
312 break;
313 case SkPath::kConic_Verb:
314 cmd.call<void>("push", CONIC,
315 pts[1].x(), pts[1].y(),
316 pts[2].x(), pts[2].y(), iter.conicWeight());
317 break;
318 case SkPath::kCubic_Verb:
319 cmd.call<void>("push", CUBIC,
320 pts[1].x(), pts[1].y(),
321 pts[2].x(), pts[2].y(),
322 pts[3].x(), pts[3].y());
323 break;
324 case SkPath::kClose_Verb:
325 cmd.call<void>("push", CLOSE);
326 break;
327 case SkPath::kDone_Verb:
328 SkASSERT(false);
329 break;
330 }
331 cmds.call<void>("push", cmd);
332 });
333 return cmds;
334 }
335
336 // This type signature is a mess, but it's necessary. See, we can't use "bind" (EMSCRIPTEN_BINDINGS)
337 // and pointers to primitive types (Only bound types like SkPoint). We could if we used
338 // cwrap (see https://becominghuman.ai/passing-and-returning-webassembly-array-parameters-a0f572c65d97)
339 // but that requires us to stick to C code and, AFAIK, doesn't allow us to return nice things like
340 // SkPath or SkOpBuilder.
341 //
342 // So, basically, if we are using C++ and EMSCRIPTEN_BINDINGS, we can't have primative pointers
343 // in our function type signatures. (this gives an error message like "Cannot call foo due to unbound
344 // types Pi, Pf"). But, we can just pretend they are numbers and cast them to be pointers and
345 // the compiler is happy.
MakePathFromCmds(uintptr_t cptr,int numCmds)346 SkPathOrNull EMSCRIPTEN_KEEPALIVE MakePathFromCmds(uintptr_t /* float* */ cptr, int numCmds) {
347 const auto* cmds = reinterpret_cast<const float*>(cptr);
348 SkPath path;
349 float x1, y1, x2, y2, x3, y3;
350
351 // if there are not enough arguments, bail with the path we've constructed so far.
352 #define CHECK_NUM_ARGS(n) \
353 if ((i + n) > numCmds) { \
354 SkDebugf("Not enough args to match the verbs. Saw %d commands\n", numCmds); \
355 return emscripten::val::null(); \
356 }
357
358 for(int i = 0; i < numCmds;){
359 switch (sk_float_floor2int(cmds[i++])) {
360 case MOVE:
361 CHECK_NUM_ARGS(2);
362 x1 = cmds[i++], y1 = cmds[i++];
363 path.moveTo(x1, y1);
364 break;
365 case LINE:
366 CHECK_NUM_ARGS(2);
367 x1 = cmds[i++], y1 = cmds[i++];
368 path.lineTo(x1, y1);
369 break;
370 case QUAD:
371 CHECK_NUM_ARGS(4);
372 x1 = cmds[i++], y1 = cmds[i++];
373 x2 = cmds[i++], y2 = cmds[i++];
374 path.quadTo(x1, y1, x2, y2);
375 break;
376 case CONIC:
377 CHECK_NUM_ARGS(5);
378 x1 = cmds[i++], y1 = cmds[i++];
379 x2 = cmds[i++], y2 = cmds[i++];
380 x3 = cmds[i++]; // weight
381 path.conicTo(x1, y1, x2, y2, x3);
382 break;
383 case CUBIC:
384 CHECK_NUM_ARGS(6);
385 x1 = cmds[i++], y1 = cmds[i++];
386 x2 = cmds[i++], y2 = cmds[i++];
387 x3 = cmds[i++], y3 = cmds[i++];
388 path.cubicTo(x1, y1, x2, y2, x3, y3);
389 break;
390 case CLOSE:
391 path.close();
392 break;
393 default:
394 SkDebugf(" path: UNKNOWN command %f, aborting dump...\n", cmds[i-1]);
395 return emscripten::val::null();
396 }
397 }
398
399 #undef CHECK_NUM_ARGS
400
401 return emscripten::val(path);
402 }
403
404 //========================================================================================
405 // Path Effects
406 //========================================================================================
407
ApplyDash(SkPath & path,SkScalar on,SkScalar off,SkScalar phase)408 bool ApplyDash(SkPath& path, SkScalar on, SkScalar off, SkScalar phase) {
409 SkScalar intervals[] = { on, off };
410 auto pe = SkDashPathEffect::Make(intervals, 2, phase);
411 if (!pe) {
412 SkDebugf("Invalid args to dash()\n");
413 return false;
414 }
415 SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle);
416 if (pe->filterPath(&path, path, &rec, nullptr)) {
417 return true;
418 }
419 SkDebugf("Could not make dashed path\n");
420 return false;
421 }
422
ApplyTrim(SkPath & path,SkScalar startT,SkScalar stopT,bool isComplement)423 bool ApplyTrim(SkPath& path, SkScalar startT, SkScalar stopT, bool isComplement) {
424 auto mode = isComplement ? SkTrimPathEffect::Mode::kInverted : SkTrimPathEffect::Mode::kNormal;
425 auto pe = SkTrimPathEffect::Make(startT, stopT, mode);
426 if (!pe) {
427 SkDebugf("Invalid args to trim(): startT and stopT must be in [0,1]\n");
428 return false;
429 }
430 SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle);
431 if (pe->filterPath(&path, path, &rec, nullptr)) {
432 return true;
433 }
434 SkDebugf("Could not trim path\n");
435 return false;
436 }
437
438 struct StrokeOpts {
439 // Default values are set in interface.js which allows clients
440 // to set any number of them. Otherwise, the binding code complains if
441 // any are omitted.
442 SkScalar width;
443 SkScalar miter_limit;
444 SkPaint::Join join;
445 SkPaint::Cap cap;
446 float precision;
447 };
448
ApplyStroke(SkPath & path,StrokeOpts opts)449 bool ApplyStroke(SkPath& path, StrokeOpts opts) {
450 SkPaint p;
451 p.setStyle(SkPaint::kStroke_Style);
452 p.setStrokeCap(opts.cap);
453 p.setStrokeJoin(opts.join);
454 p.setStrokeWidth(opts.width);
455 p.setStrokeMiter(opts.miter_limit);
456
457 return p.getFillPath(path, &path, nullptr, opts.precision);
458 }
459
460 // to map from raw memory to a uint8array
getSkDataBytes(const SkData * data)461 Uint8Array getSkDataBytes(const SkData *data) {
462 return Uint8Array(typed_memory_view(data->size(), data->bytes()));
463 }
464
465 // These objects have private destructors / delete mthods - I don't think
466 // we need to do anything other than tell emscripten to do nothing.
467 namespace emscripten {
468 namespace internal {
469 template<typename ClassType>
470 void raw_destructor(ClassType *);
471
472 template<>
raw_destructor(SkData * ptr)473 void raw_destructor<SkData>(SkData *ptr) {
474 }
475
476 template<>
raw_destructor(SkTypeface * ptr)477 void raw_destructor<SkTypeface>(SkTypeface *ptr) {
478 }
479
480 template<>
raw_destructor(SkVertices * ptr)481 void raw_destructor<SkVertices>(SkVertices *ptr) {
482 }
483
484 template<>
raw_destructor(SkTextBlob * ptr)485 void raw_destructor<SkTextBlob>(SkTextBlob *ptr) {
486 }
487 }
488 }
489
490 // Some timesignatures below have uintptr_t instead of a pointer to a primative
491 // type (e.g. SkScalar). This is necessary because we can't use "bind" (EMSCRIPTEN_BINDINGS)
492 // and pointers to primitive types (Only bound types like SkPoint). We could if we used
493 // cwrap (see https://becominghuman.ai/passing-and-returning-webassembly-array-parameters-a0f572c65d97)
494 // but that requires us to stick to C code and, AFAIK, doesn't allow us to return nice things like
495 // SkPath or SkCanvas.
496 //
497 // So, basically, if we are using C++ and EMSCRIPTEN_BINDINGS, we can't have primative pointers
498 // in our function type signatures. (this gives an error message like "Cannot call foo due to unbound
499 // types Pi, Pf"). But, we can just pretend they are numbers and cast them to be pointers and
500 // the compiler is happy.
EMSCRIPTEN_BINDINGS(Skia)501 EMSCRIPTEN_BINDINGS(Skia) {
502 #if SK_SUPPORT_GPU
503 function("_getWebGLSurface", &getWebGLSurface, allow_raw_pointers());
504 function("currentContext", &emscripten_webgl_get_current_context);
505 function("setCurrentContext", &emscripten_webgl_make_context_current);
506 constant("gpu", true);
507 #endif
508 function("_decodeImage", optional_override([](uintptr_t /* uint8_t* */ iptr,
509 size_t length)->sk_sp<SkImage> {
510 uint8_t* imgData = reinterpret_cast<uint8_t*>(iptr);
511 sk_sp<SkData> bytes = SkData::MakeWithoutCopy(imgData, length);
512 return SkImage::MakeFromEncoded(bytes);
513 }), allow_raw_pointers());
514 function("_getRasterDirectSurface", optional_override([](const SimpleImageInfo ii,
515 uintptr_t /* uint8_t* */ pPtr,
516 size_t rowBytes)->sk_sp<SkSurface> {
517 uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
518 SkImageInfo imageInfo = toSkImageInfo(ii);
519 return SkSurface::MakeRasterDirect(imageInfo, pixels, rowBytes, nullptr);
520 }), allow_raw_pointers());
521 function("_getRasterN32PremulSurface", optional_override([](int width, int height)->sk_sp<SkSurface> {
522 return SkSurface::MakeRasterN32Premul(width, height, nullptr);
523 }), allow_raw_pointers());
524
525 function("getSkDataBytes", &getSkDataBytes, allow_raw_pointers());
526 function("MakeSkCornerPathEffect", &SkCornerPathEffect::Make, allow_raw_pointers());
527 function("MakeSkDiscretePathEffect", &SkDiscretePathEffect::Make, allow_raw_pointers());
528 function("MakeBlurMaskFilter", optional_override([](SkBlurStyle style, SkScalar sigma, bool respectCTM)->sk_sp<SkMaskFilter> {
529 // Adds a little helper because emscripten doesn't expose default params.
530 return SkMaskFilter::MakeBlur(style, sigma, respectCTM);
531 }), allow_raw_pointers());
532 function("_MakePathFromCmds", &MakePathFromCmds);
533 function("MakePathFromOp", &MakePathFromOp);
534 function("MakePathFromSVGString", &MakePathFromSVGString);
535
536 // These won't be called directly, there's a JS helper to deal with typed arrays.
537 function("_MakeSkDashPathEffect", optional_override([](uintptr_t /* float* */ cptr, int count, SkScalar phase)->sk_sp<SkPathEffect> {
538 // See comment above for uintptr_t explanation
539 const float* intervals = reinterpret_cast<const float*>(cptr);
540 return SkDashPathEffect::Make(intervals, count, phase);
541 }), allow_raw_pointers());
542 function("_MakeImage", optional_override([](SimpleImageInfo ii,
543 uintptr_t /* uint8_t* */ pPtr, int plen,
544 size_t rowBytes)->sk_sp<SkImage> {
545 // See comment above for uintptr_t explanation
546 uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
547 SkImageInfo info = toSkImageInfo(ii);
548 sk_sp<SkData> pixelData = SkData::MakeFromMalloc(pixels, plen);
549
550 return SkImage::MakeRasterData(info, pixelData, rowBytes);
551 }), allow_raw_pointers());
552 // Allow localMatrix to be optional, so we have 2 declarations of these shaders
553 function("_MakeImageShader", optional_override([](sk_sp<SkImage> img,
554 SkShader::TileMode tx, SkShader::TileMode ty,
555 bool clampAsIfUnpremul)->sk_sp<SkShader> {
556 return SkImageShader::Make(img, tx, ty, nullptr, clampAsIfUnpremul);
557 }), allow_raw_pointers());
558 function("_MakeImageShader", optional_override([](sk_sp<SkImage> img,
559 SkShader::TileMode tx, SkShader::TileMode ty,
560 bool clampAsIfUnpremul, const SimpleMatrix& lm)->sk_sp<SkShader> {
561 SkMatrix localMatrix = toSkMatrix(lm);
562
563 return SkImageShader::Make(img, tx, ty, &localMatrix, clampAsIfUnpremul);
564 }), allow_raw_pointers());
565 function("_MakeLinearGradientShader", optional_override([](SkPoint start, SkPoint end,
566 uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
567 int count, SkShader::TileMode mode, uint32_t flags)->sk_sp<SkShader> {
568 SkPoint points[] = { start, end };
569 // See comment above for uintptr_t explanation
570 const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
571 const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
572
573 return SkGradientShader::MakeLinear(points, colors, positions, count,
574 mode, flags, nullptr);
575 }), allow_raw_pointers());
576 function("_MakeLinearGradientShader", optional_override([](SkPoint start, SkPoint end,
577 uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
578 int count, SkShader::TileMode mode, uint32_t flags,
579 const SimpleMatrix& lm)->sk_sp<SkShader> {
580 SkPoint points[] = { start, end };
581 // See comment above for uintptr_t explanation
582 const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
583 const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
584
585 SkMatrix localMatrix = toSkMatrix(lm);
586
587 return SkGradientShader::MakeLinear(points, colors, positions, count,
588 mode, flags, &localMatrix);
589 }), allow_raw_pointers());
590 function("_MakeRadialGradientShader", optional_override([](SkPoint center, SkScalar radius,
591 uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
592 int count, SkShader::TileMode mode, uint32_t flags)->sk_sp<SkShader> {
593 // See comment above for uintptr_t explanation
594 const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
595 const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
596
597 return SkGradientShader::MakeRadial(center, radius, colors, positions, count,
598 mode, flags, nullptr);
599 }), allow_raw_pointers());
600 function("_MakeRadialGradientShader", optional_override([](SkPoint center, SkScalar radius,
601 uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
602 int count, SkShader::TileMode mode, uint32_t flags,
603 const SimpleMatrix& lm)->sk_sp<SkShader> {
604 // See comment above for uintptr_t explanation
605 const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
606 const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
607
608 SkMatrix localMatrix = toSkMatrix(lm);
609 return SkGradientShader::MakeRadial(center, radius, colors, positions, count,
610 mode, flags, &localMatrix);
611 }), allow_raw_pointers());
612 function("_MakeTwoPointConicalGradientShader", optional_override([](
613 SkPoint start, SkScalar startRadius,
614 SkPoint end, SkScalar endRadius,
615 uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
616 int count, SkShader::TileMode mode, uint32_t flags)->sk_sp<SkShader> {
617 // See comment above for uintptr_t explanation
618 const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
619 const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
620
621 return SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius,
622 colors, positions, count, mode,
623 flags, nullptr);
624 }), allow_raw_pointers());
625 function("_MakeTwoPointConicalGradientShader", optional_override([](
626 SkPoint start, SkScalar startRadius,
627 SkPoint end, SkScalar endRadius,
628 uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
629 int count, SkShader::TileMode mode, uint32_t flags,
630 const SimpleMatrix& lm)->sk_sp<SkShader> {
631 // See comment above for uintptr_t explanation
632 const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
633 const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
634
635 SkMatrix localMatrix = toSkMatrix(lm);
636 return SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius,
637 colors, positions, count, mode,
638 flags, &localMatrix);
639 }), allow_raw_pointers());
640
641 function("_MakeSkVertices", optional_override([](SkVertices::VertexMode mode, int vertexCount,
642 uintptr_t /* SkPoint* */ pPtr, uintptr_t /* SkPoint* */ tPtr,
643 uintptr_t /* SkColor* */ cPtr,
644 uintptr_t /* BoneIndices* */ biPtr, uintptr_t /* BoneWeights* */ bwPtr,
645 int indexCount, uintptr_t /* uint16_t * */ iPtr)->sk_sp<SkVertices> {
646 // See comment above for uintptr_t explanation
647 const SkPoint* positions = reinterpret_cast<const SkPoint*>(pPtr);
648 const SkPoint* texs = reinterpret_cast<const SkPoint*>(tPtr);
649 const SkColor* colors = reinterpret_cast<const SkColor*>(cPtr);
650 const BoneIndices* boneIndices = reinterpret_cast<const BoneIndices*>(biPtr);
651 const BoneWeights* boneWeights = reinterpret_cast<const BoneWeights*>(bwPtr);
652 const uint16_t* indices = reinterpret_cast<const uint16_t*>(iPtr);
653
654 return SkVertices::MakeCopy(mode, vertexCount, positions, texs, colors,
655 boneIndices, boneWeights, indexCount, indices);
656 }), allow_raw_pointers());
657
658 class_<SkCanvas>("SkCanvas")
659 .constructor<>()
660 .function("clear", optional_override([](SkCanvas& self, JSColor color)->void {
661 // JS side gives us a signed int instead of an unsigned int for color
662 // Add a optional_override to change it out.
663 self.clear(SkColor(color));
664 }))
665 .function("clipPath", select_overload<void (const SkPath&, SkClipOp, bool)>(&SkCanvas::clipPath))
666 .function("clipRect", select_overload<void (const SkRect&, SkClipOp, bool)>(&SkCanvas::clipRect))
667 .function("concat", optional_override([](SkCanvas& self, const SimpleMatrix& m) {
668 self.concat(toSkMatrix(m));
669 }))
670 .function("drawArc", &SkCanvas::drawArc)
671 .function("drawImage", select_overload<void (const sk_sp<SkImage>&, SkScalar, SkScalar, const SkPaint*)>(&SkCanvas::drawImage), allow_raw_pointers())
672 .function("drawImageRect", optional_override([](SkCanvas& self, const sk_sp<SkImage>& image,
673 SkRect src, SkRect dst,
674 const SkPaint* paint, bool fastSample)->void {
675 self.drawImageRect(image, src, dst, paint,
676 fastSample ? SkCanvas::kFast_SrcRectConstraint :
677 SkCanvas::kStrict_SrcRectConstraint);
678 }), allow_raw_pointers())
679 .function("drawLine", select_overload<void (SkScalar, SkScalar, SkScalar, SkScalar, const SkPaint&)>(&SkCanvas::drawLine))
680 .function("drawOval", &SkCanvas::drawOval)
681 .function("drawPaint", &SkCanvas::drawPaint)
682 .function("drawPath", &SkCanvas::drawPath)
683 .function("drawRect", &SkCanvas::drawRect)
684 .function("drawRoundRect", &SkCanvas::drawRoundRect)
685 .function("drawShadow", optional_override([](SkCanvas& self, const SkPath& path,
686 const SkPoint3& zPlaneParams,
687 const SkPoint3& lightPos, SkScalar lightRadius,
688 JSColor ambientColor, JSColor spotColor,
689 uint32_t flags) {
690 SkShadowUtils::DrawShadow(&self, path, zPlaneParams, lightPos, lightRadius,
691 SkColor(ambientColor), SkColor(spotColor), flags);
692 }))
693 .function("_drawSimpleText", optional_override([](SkCanvas& self, uintptr_t /* char* */ sptr,
694 size_t len, SkScalar x, SkScalar y, const SkFont& font,
695 const SkPaint& paint) {
696 // See comment above for uintptr_t explanation
697 const char* str = reinterpret_cast<const char*>(sptr);
698
699 self.drawSimpleText(str, len, SkTextEncoding::kUTF8, x, y, font, paint);
700 }))
701 .function("drawTextBlob", select_overload<void (const sk_sp<SkTextBlob>&, SkScalar, SkScalar, const SkPaint&)>(&SkCanvas::drawTextBlob))
702 .function("drawVertices", select_overload<void (const sk_sp<SkVertices>&, SkBlendMode, const SkPaint&)>(&SkCanvas::drawVertices))
703 .function("flush", &SkCanvas::flush)
704 .function("getTotalMatrix", optional_override([](const SkCanvas& self)->SimpleMatrix {
705 SkMatrix m = self.getTotalMatrix();
706 return toSimpleSkMatrix(m);
707 }))
708 .function("_readPixels", optional_override([](SkCanvas& self, SimpleImageInfo di,
709 uintptr_t /* uint8_t* */ pPtr,
710 size_t dstRowBytes, int srcX, int srcY) {
711 uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
712 SkImageInfo dstInfo = toSkImageInfo(di);
713
714 return self.readPixels(dstInfo, pixels, dstRowBytes, srcX, srcY);
715 }))
716 .function("restore", &SkCanvas::restore)
717 .function("rotate", select_overload<void (SkScalar, SkScalar, SkScalar)>(&SkCanvas::rotate))
718 .function("save", &SkCanvas::save)
719 .function("scale", &SkCanvas::scale)
720 .function("skew", &SkCanvas::skew)
721 .function("translate", &SkCanvas::translate)
722 .function("_writePixels", optional_override([](SkCanvas& self, SimpleImageInfo di,
723 uintptr_t /* uint8_t* */ pPtr,
724 size_t srcRowBytes, int dstX, int dstY) {
725 uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
726 SkImageInfo dstInfo = toSkImageInfo(di);
727
728 return self.writePixels(dstInfo, pixels, srcRowBytes, dstX, dstY);
729 }))
730 ;
731
732 class_<SkData>("SkData")
733 .smart_ptr<sk_sp<SkData>>("sk_sp<SkData>>")
734 .function("size", &SkData::size);
735
736 class_<SkFont>("SkFont")
737 .constructor<>()
738 .constructor<sk_sp<SkTypeface>>()
739 .constructor<sk_sp<SkTypeface>, SkScalar>()
740 .constructor<sk_sp<SkTypeface>, SkScalar, SkScalar, SkScalar>()
741 .function("getScaleX", &SkFont::getScaleX)
742 .function("getSize", &SkFont::getSize)
743 .function("getSkewX", &SkFont::getSkewX)
744 .function("getTypeface", &SkFont::getTypeface, allow_raw_pointers())
745 .function("measureText", optional_override([](SkFont& self, std::string text) {
746 // TODO(kjlubick): This does not work well for non-ascii
747 // Need to maybe add a helper in interface.js that supports UTF-8
748 // Otherwise, go with std::wstring and set UTF-32 encoding.
749 return self.measureText(text.c_str(), text.length(), SkTextEncoding::kUTF8);
750 }))
751 .function("setScaleX", &SkFont::setScaleX)
752 .function("setSize", &SkFont::setSize)
753 .function("setSkewX", &SkFont::setSkewX)
754 .function("setTypeface", &SkFont::setTypeface, allow_raw_pointers());
755
756 class_<SkFontMgr>("SkFontMgr")
757 .smart_ptr<sk_sp<SkFontMgr>>("sk_sp<SkFontMgr>")
758 .class_function("RefDefault", &SkFontMgr::RefDefault)
759 #ifdef SK_DEBUG
760 .function("dumpFamilies", optional_override([](SkFontMgr& self) {
761 int numFam = self.countFamilies();
762 SkDebugf("There are %d font families\n");
763 for (int i = 0 ; i< numFam; i++) {
764 SkString s;
765 self.getFamilyName(i, &s);
766 SkDebugf("\t%s", s.c_str());
767 }
768 }))
769 #endif
770 .function("countFamilies", &SkFontMgr::countFamilies)
771 .function("_makeTypefaceFromData", optional_override([](SkFontMgr& self,
772 uintptr_t /* uint8_t* */ fPtr,
773 int flen)->sk_sp<SkTypeface> {
774 // See comment above for uintptr_t explanation
775 uint8_t* font = reinterpret_cast<uint8_t*>(fPtr);
776 sk_sp<SkData> fontData = SkData::MakeFromMalloc(font, flen);
777
778 return self.makeFromData(fontData);
779 }), allow_raw_pointers());
780
781 class_<SkImage>("SkImage")
782 .smart_ptr<sk_sp<SkImage>>("sk_sp<SkImage>")
783 .function("height", &SkImage::height)
784 .function("width", &SkImage::width)
785 .function("_encodeToData", select_overload<sk_sp<SkData>()const>(&SkImage::encodeToData))
786 .function("_encodeToDataWithFormat", select_overload<sk_sp<SkData>(SkEncodedImageFormat encodedImageFormat, int quality)const>(&SkImage::encodeToData));
787
788 class_<SkMaskFilter>("SkMaskFilter")
789 .smart_ptr<sk_sp<SkMaskFilter>>("sk_sp<SkMaskFilter>");
790
791 class_<SkPaint>("SkPaint")
792 .constructor<>()
793 .function("copy", optional_override([](const SkPaint& self)->SkPaint {
794 SkPaint p(self);
795 return p;
796 }))
797 .function("getBlendMode", &SkPaint::getBlendMode)
798 .function("getColor", optional_override([](SkPaint& self)->JSColor {
799 // JS side gives us a signed int instead of an unsigned int for color
800 // Add a optional_override to change it out.
801 return JSColor(self.getColor());
802 }))
803 .function("getFilterQuality", &SkPaint::getFilterQuality)
804 .function("getStrokeCap", &SkPaint::getStrokeCap)
805 .function("getStrokeJoin", &SkPaint::getStrokeJoin)
806 .function("getStrokeMiter", &SkPaint::getStrokeMiter)
807 .function("getStrokeWidth", &SkPaint::getStrokeWidth)
808 .function("setAntiAlias", &SkPaint::setAntiAlias)
809 .function("setBlendMode", &SkPaint::setBlendMode)
810 .function("setColor", optional_override([](SkPaint& self, JSColor color)->void {
811 // JS side gives us a signed int instead of an unsigned int for color
812 // Add a optional_override to change it out.
813 self.setColor(SkColor(color));
814 }))
815 .function("setFilterQuality", &SkPaint::setFilterQuality)
816 .function("setMaskFilter", &SkPaint::setMaskFilter)
817 .function("setPathEffect", &SkPaint::setPathEffect)
818 .function("setShader", &SkPaint::setShader)
819 .function("setStrokeCap", &SkPaint::setStrokeCap)
820 .function("setStrokeJoin", &SkPaint::setStrokeJoin)
821 .function("setStrokeMiter", &SkPaint::setStrokeMiter)
822 .function("setStrokeWidth", &SkPaint::setStrokeWidth)
823 .function("setStyle", &SkPaint::setStyle);
824
825 class_<SkPathEffect>("SkPathEffect")
826 .smart_ptr<sk_sp<SkPathEffect>>("sk_sp<SkPathEffect>");
827
828 class_<SkPath>("SkPath")
829 .constructor<>()
830 .constructor<const SkPath&>()
831 .function("_addArc", &ApplyAddArc)
832 // interface.js has 3 overloads of addPath
833 .function("_addPath", &ApplyAddPath)
834 // interface.js has 4 overloads of addRect
835 .function("_addRect", &ApplyAddRect)
836 // interface.js has 4 overloads of addRoundRect
837 .function("_addRoundRect", &ApplyAddRoundRect)
838 .function("_arcTo", &ApplyArcTo)
839 .function("_arcTo", &ApplyArcToAngle)
840 .function("_close", &ApplyClose)
841 .function("_conicTo", &ApplyConicTo)
842 .function("countPoints", &SkPath::countPoints)
843 .function("contains", &SkPath::contains)
844 .function("_cubicTo", &ApplyCubicTo)
845 .function("getPoint", &SkPath::getPoint)
846 .function("isEmpty", &SkPath::isEmpty)
847 .function("isVolatile", &SkPath::isVolatile)
848 .function("_lineTo", &ApplyLineTo)
849 .function("_moveTo", &ApplyMoveTo)
850 .function("reset", &ApplyReset)
851 .function("rewind", &ApplyRewind)
852 .function("_quadTo", &ApplyQuadTo)
853 .function("setIsVolatile", &SkPath::setIsVolatile)
854 .function("_transform", select_overload<void(SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&ApplyTransform))
855
856 // PathEffects
857 .function("_dash", &ApplyDash)
858 .function("_trim", &ApplyTrim)
859 .function("_stroke", &ApplyStroke)
860
861 // PathOps
862 .function("_simplify", &ApplySimplify)
863 .function("_op", &ApplyPathOp)
864
865 // Exporting
866 .function("toSVGString", &ToSVGString)
867 .function("toCmds", &ToCmds)
868
869 .function("setFillType", &SkPath::setFillType)
870 .function("getFillType", &SkPath::getFillType)
871 .function("getBounds", &SkPath::getBounds)
872 .function("computeTightBounds", &SkPath::computeTightBounds)
873 .function("equals", &Equals)
874 .function("copy", &CopyPath)
875 #ifdef SK_DEBUG
876 .function("dump", select_overload<void() const>(&SkPath::dump))
877 .function("dumpHex", select_overload<void() const>(&SkPath::dumpHex))
878 #endif
879 ;
880
881 class_<SkShader>("SkShader")
882 .smart_ptr<sk_sp<SkShader>>("sk_sp<SkShader>");
883
884 class_<SkSurface>("SkSurface")
885 .smart_ptr<sk_sp<SkSurface>>("sk_sp<SkSurface>")
886 .function("width", &SkSurface::width)
887 .function("height", &SkSurface::height)
888 .function("_flush", &SkSurface::flush)
889 .function("makeImageSnapshot", select_overload<sk_sp<SkImage>()>(&SkSurface::makeImageSnapshot))
890 .function("makeImageSnapshot", select_overload<sk_sp<SkImage>(const SkIRect& bounds)>(&SkSurface::makeImageSnapshot))
891 .function("getCanvas", &SkSurface::getCanvas, allow_raw_pointers());
892
893 class_<SkTextBlob>("SkTextBlob")
894 .smart_ptr<sk_sp<SkTextBlob>>("sk_sp<SkTextBlob>>")
895 .class_function("_MakeFromText",optional_override([](uintptr_t /* char* */ sptr,
896 size_t len, const SkFont& font,
897 SkTextEncoding encoding)->sk_sp<SkTextBlob> {
898 // See comment above for uintptr_t explanation
899 const char* str = reinterpret_cast<const char*>(sptr);
900 return SkTextBlob::MakeFromText(str, len, font, encoding);
901 }), allow_raw_pointers());
902
903
904 class_<SkTypeface>("SkTypeface")
905 .smart_ptr<sk_sp<SkTypeface>>("sk_sp<SkTypeface>");
906
907 class_<SkVertices>("SkVertices")
908 .smart_ptr<sk_sp<SkVertices>>("sk_sp<SkVertices>")
909 .function("_applyBones", optional_override([](SkVertices& self, uintptr_t /* Bone* */ bptr, int boneCount)->sk_sp<SkVertices> {
910 // See comment above for uintptr_t explanation
911 const Bone* bones = reinterpret_cast<const Bone*>(bptr);
912 return self.applyBones(bones, boneCount);
913 }))
914 .function("bounds", &SkVertices::bounds)
915 .function("mode", &SkVertices::mode)
916 .function("uniqueID", &SkVertices::uniqueID)
917 #ifdef SK_DEBUG
918 .function("dumpPositions", optional_override([](SkVertices& self)->void {
919 auto pos = self.positions();
920 for(int i = 0; i< self.vertexCount(); i++) {
921 SkDebugf("position[%d] = (%f, %f)\n", i, pos[i].x(), pos[i].y());
922 }
923 }))
924 #endif
925 .function("vertexCount", &SkVertices::vertexCount);
926
927 enum_<SkAlphaType>("AlphaType")
928 .value("Opaque", SkAlphaType::kOpaque_SkAlphaType)
929 .value("Premul", SkAlphaType::kPremul_SkAlphaType)
930 .value("Unpremul", SkAlphaType::kUnpremul_SkAlphaType);
931
932 enum_<SkBlendMode>("BlendMode")
933 .value("Clear", SkBlendMode::kClear)
934 .value("Src", SkBlendMode::kSrc)
935 .value("Dst", SkBlendMode::kDst)
936 .value("SrcOver", SkBlendMode::kSrcOver)
937 .value("DstOver", SkBlendMode::kDstOver)
938 .value("SrcIn", SkBlendMode::kSrcIn)
939 .value("DstIn", SkBlendMode::kDstIn)
940 .value("SrcOut", SkBlendMode::kSrcOut)
941 .value("DstOut", SkBlendMode::kDstOut)
942 .value("SrcATop", SkBlendMode::kSrcATop)
943 .value("DstATop", SkBlendMode::kDstATop)
944 .value("Xor", SkBlendMode::kXor)
945 .value("Plus", SkBlendMode::kPlus)
946 .value("Modulate", SkBlendMode::kModulate)
947 .value("Screen", SkBlendMode::kScreen)
948 .value("Overlay", SkBlendMode::kOverlay)
949 .value("Darken", SkBlendMode::kDarken)
950 .value("Lighten", SkBlendMode::kLighten)
951 .value("ColorDodge", SkBlendMode::kColorDodge)
952 .value("ColorBurn", SkBlendMode::kColorBurn)
953 .value("HardLight", SkBlendMode::kHardLight)
954 .value("SoftLight", SkBlendMode::kSoftLight)
955 .value("Difference", SkBlendMode::kDifference)
956 .value("Exclusion", SkBlendMode::kExclusion)
957 .value("Multiply", SkBlendMode::kMultiply)
958 .value("Hue", SkBlendMode::kHue)
959 .value("Saturation", SkBlendMode::kSaturation)
960 .value("Color", SkBlendMode::kColor)
961 .value("Luminosity", SkBlendMode::kLuminosity);
962
963 enum_<SkBlurStyle>("BlurStyle")
964 .value("Normal", SkBlurStyle::kNormal_SkBlurStyle)
965 .value("Solid", SkBlurStyle::kSolid_SkBlurStyle)
966 .value("Outer", SkBlurStyle::kOuter_SkBlurStyle)
967 .value("Inner", SkBlurStyle::kInner_SkBlurStyle);
968
969 enum_<SkClipOp>("ClipOp")
970 .value("Difference", SkClipOp::kDifference)
971 .value("Intersect", SkClipOp::kIntersect);
972
973 enum_<SkColorType>("ColorType")
974 .value("Alpha_8", SkColorType::kAlpha_8_SkColorType)
975 .value("RGB_565", SkColorType::kRGB_565_SkColorType)
976 .value("ARGB_4444", SkColorType::kARGB_4444_SkColorType)
977 .value("RGBA_8888", SkColorType::kRGBA_8888_SkColorType)
978 .value("RGB_888x", SkColorType::kRGB_888x_SkColorType)
979 .value("BGRA_8888", SkColorType::kBGRA_8888_SkColorType)
980 .value("RGBA_1010102", SkColorType::kRGBA_1010102_SkColorType)
981 .value("RGB_101010x", SkColorType::kRGB_101010x_SkColorType)
982 .value("Gray_8", SkColorType::kGray_8_SkColorType)
983 .value("RGBA_F16", SkColorType::kRGBA_F16_SkColorType)
984 .value("RGBA_F32", SkColorType::kRGBA_F32_SkColorType);
985
986 enum_<SkPath::FillType>("FillType")
987 .value("Winding", SkPath::FillType::kWinding_FillType)
988 .value("EvenOdd", SkPath::FillType::kEvenOdd_FillType)
989 .value("InverseWinding", SkPath::FillType::kInverseWinding_FillType)
990 .value("InverseEvenOdd", SkPath::FillType::kInverseEvenOdd_FillType);
991
992 enum_<SkFilterQuality>("FilterQuality")
993 .value("None", SkFilterQuality::kNone_SkFilterQuality)
994 .value("Low", SkFilterQuality::kLow_SkFilterQuality)
995 .value("Medium", SkFilterQuality::kMedium_SkFilterQuality)
996 .value("High", SkFilterQuality::kHigh_SkFilterQuality);
997
998 enum_<SkEncodedImageFormat>("ImageFormat")
999 .value("PNG", SkEncodedImageFormat::kPNG)
1000 .value("JPEG", SkEncodedImageFormat::kJPEG);
1001
1002 enum_<SkPaint::Style>("PaintStyle")
1003 .value("Fill", SkPaint::Style::kFill_Style)
1004 .value("Stroke", SkPaint::Style::kStroke_Style)
1005 .value("StrokeAndFill", SkPaint::Style::kStrokeAndFill_Style);
1006
1007 enum_<SkPathOp>("PathOp")
1008 .value("Difference", SkPathOp::kDifference_SkPathOp)
1009 .value("Intersect", SkPathOp::kIntersect_SkPathOp)
1010 .value("Union", SkPathOp::kUnion_SkPathOp)
1011 .value("XOR", SkPathOp::kXOR_SkPathOp)
1012 .value("ReverseDifference", SkPathOp::kReverseDifference_SkPathOp);
1013
1014 enum_<SkPaint::Cap>("StrokeCap")
1015 .value("Butt", SkPaint::Cap::kButt_Cap)
1016 .value("Round", SkPaint::Cap::kRound_Cap)
1017 .value("Square", SkPaint::Cap::kSquare_Cap);
1018
1019 enum_<SkPaint::Join>("StrokeJoin")
1020 .value("Miter", SkPaint::Join::kMiter_Join)
1021 .value("Round", SkPaint::Join::kRound_Join)
1022 .value("Bevel", SkPaint::Join::kBevel_Join);
1023
1024 enum_<SkTextEncoding>("TextEncoding")
1025 .value("UTF8", SkTextEncoding::kUTF8)
1026 .value("UTF16", SkTextEncoding::kUTF16)
1027 .value("UTF32", SkTextEncoding::kUTF32)
1028 .value("GlyphID", SkTextEncoding::kGlyphID);
1029
1030 enum_<SkShader::TileMode>("TileMode")
1031 .value("Clamp", SkShader::TileMode::kClamp_TileMode)
1032 .value("Repeat", SkShader::TileMode::kRepeat_TileMode)
1033 .value("Mirror", SkShader::TileMode::kMirror_TileMode)
1034 // Decal mode only works in the SW backend, not WebGl (yet).
1035 .value("Decal", SkShader::TileMode::kDecal_TileMode);
1036
1037 enum_<SkVertices::VertexMode>("VertexMode")
1038 .value("Triangles", SkVertices::VertexMode::kTriangles_VertexMode)
1039 .value("TrianglesStrip", SkVertices::VertexMode::kTriangleStrip_VertexMode)
1040 .value("TriangleFan", SkVertices::VertexMode::kTriangleFan_VertexMode);
1041
1042
1043 // A value object is much simpler than a class - it is returned as a JS
1044 // object and does not require delete().
1045 // https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html#value-types
1046 value_object<SkRect>("SkRect")
1047 .field("fLeft", &SkRect::fLeft)
1048 .field("fTop", &SkRect::fTop)
1049 .field("fRight", &SkRect::fRight)
1050 .field("fBottom", &SkRect::fBottom);
1051
1052 value_object<SkIRect>("SkIRect")
1053 .field("fLeft", &SkIRect::fLeft)
1054 .field("fTop", &SkIRect::fTop)
1055 .field("fRight", &SkIRect::fRight)
1056 .field("fBottom", &SkIRect::fBottom);
1057
1058 value_object<SimpleImageInfo>("SkImageInfo")
1059 .field("width", &SimpleImageInfo::width)
1060 .field("height", &SimpleImageInfo::height)
1061 .field("colorType", &SimpleImageInfo::colorType)
1062 .field("alphaType", &SimpleImageInfo::alphaType);
1063
1064 // SkPoints can be represented by [x, y]
1065 value_array<SkPoint>("SkPoint")
1066 .element(&SkPoint::fX)
1067 .element(&SkPoint::fY);
1068
1069 // SkPoint3s can be represented by [x, y, z]
1070 value_array<SkPoint3>("SkPoint3")
1071 .element(&SkPoint3::fX)
1072 .element(&SkPoint3::fY)
1073 .element(&SkPoint3::fZ);
1074
1075 // {"w": Number, "h", Number}
1076 value_object<SkSize>("SkSize")
1077 .field("w", &SkSize::fWidth)
1078 .field("h", &SkSize::fHeight);
1079
1080 value_object<SkISize>("SkISize")
1081 .field("w", &SkISize::fWidth)
1082 .field("h", &SkISize::fHeight);
1083
1084 value_object<StrokeOpts>("StrokeOpts")
1085 .field("width", &StrokeOpts::width)
1086 .field("miter_limit", &StrokeOpts::miter_limit)
1087 .field("join", &StrokeOpts::join)
1088 .field("cap", &StrokeOpts::cap)
1089 .field("precision", &StrokeOpts::precision);
1090
1091 // Allows clients to supply a 1D array of 9 elements and the bindings
1092 // will automatically turn it into a 3x3 2D matrix.
1093 // e.g. path.transform([0,1,2,3,4,5,6,7,8])
1094 // This is likely simpler for the client than exposing SkMatrix
1095 // directly and requiring them to do a lot of .delete().
1096 value_array<SimpleMatrix>("SkMatrix")
1097 .element(&SimpleMatrix::scaleX)
1098 .element(&SimpleMatrix::skewX)
1099 .element(&SimpleMatrix::transX)
1100
1101 .element(&SimpleMatrix::skewY)
1102 .element(&SimpleMatrix::scaleY)
1103 .element(&SimpleMatrix::transY)
1104
1105 .element(&SimpleMatrix::pers0)
1106 .element(&SimpleMatrix::pers1)
1107 .element(&SimpleMatrix::pers2);
1108
1109 constant("TRANSPARENT", (JSColor) SK_ColorTRANSPARENT);
1110 constant("RED", (JSColor) SK_ColorRED);
1111 constant("BLUE", (JSColor) SK_ColorBLUE);
1112 constant("YELLOW", (JSColor) SK_ColorYELLOW);
1113 constant("CYAN", (JSColor) SK_ColorCYAN);
1114 constant("BLACK", (JSColor) SK_ColorBLACK);
1115 constant("WHITE", (JSColor) SK_ColorWHITE);
1116 // TODO(?)
1117
1118 constant("MOVE_VERB", MOVE);
1119 constant("LINE_VERB", LINE);
1120 constant("QUAD_VERB", QUAD);
1121 constant("CONIC_VERB", CONIC);
1122 constant("CUBIC_VERB", CUBIC);
1123 constant("CLOSE_VERB", CLOSE);
1124 }
1125