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