• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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