• 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/android/SkAnimatedImage.h"
9 #include "include/codec/SkAndroidCodec.h"
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkBlurTypes.h"
12 #include "include/core/SkCanvas.h"
13 #include "include/core/SkColor.h"
14 #include "include/core/SkColorFilter.h"
15 #include "include/core/SkColorSpace.h"
16 #include "include/core/SkData.h"
17 #include "include/core/SkEncodedImageFormat.h"
18 #include "include/core/SkImage.h"
19 #include "include/core/SkImageFilter.h"
20 #include "include/core/SkImageGenerator.h"
21 #include "include/core/SkImageInfo.h"
22 #include "include/core/SkM44.h"
23 #include "include/core/SkMaskFilter.h"
24 #include "include/core/SkPaint.h"
25 #include "include/core/SkPath.h"
26 #include "include/core/SkPathEffect.h"
27 #include "include/core/SkPathMeasure.h"
28 #include "include/core/SkPicture.h"
29 #include "include/core/SkPictureRecorder.h"
30 #include "include/core/SkRRect.h"
31 #include "include/core/SkSamplingOptions.h"
32 #include "include/core/SkScalar.h"
33 #include "include/core/SkShader.h"
34 #include "include/core/SkString.h"
35 #include "include/core/SkStrokeRec.h"
36 #include "include/core/SkSurface.h"
37 #include "include/core/SkTextBlob.h"
38 #include "include/core/SkTypeface.h"
39 #include "include/core/SkTypes.h"
40 #include "include/core/SkVertices.h"
41 #include "include/effects/SkCornerPathEffect.h"
42 #include "include/effects/SkDashPathEffect.h"
43 #include "include/effects/SkDiscretePathEffect.h"
44 #include "include/effects/SkGradientShader.h"
45 #include "include/effects/SkImageFilters.h"
46 #include "include/effects/SkPerlinNoiseShader.h"
47 #include "include/effects/SkRuntimeEffect.h"
48 #include "include/effects/SkTrimPathEffect.h"
49 #include "include/private/SkShadowFlags.h"
50 #include "include/utils/SkParsePath.h"
51 #include "include/utils/SkShadowUtils.h"
52 #include "src/core/SkPathPriv.h"
53 #include "src/core/SkResourceCache.h"
54 #include "src/image/SkImage_Base.h"
55 #include "src/sksl/SkSLCompiler.h"
56 
57 #include "modules/canvaskit/WasmCommon.h"
58 #include <emscripten.h>
59 #include <emscripten/bind.h>
60 #include <emscripten/html5.h>
61 
62 #ifdef SK_GL
63 #include "include/gpu/GrBackendSurface.h"
64 #include "include/gpu/GrDirectContext.h"
65 #include "include/gpu/gl/GrGLInterface.h"
66 #include "include/gpu/gl/GrGLTypes.h"
67 #include "src/gpu/GrProxyProvider.h"
68 #include "src/gpu/GrRecordingContextPriv.h"
69 #include "src/gpu/gl/GrGLDefines.h"
70 
71 #include "webgl/webgl1.h"
72 #endif
73 
74 #ifndef SK_NO_FONTS
75 #include "include/core/SkFont.h"
76 #include "include/core/SkFontMetrics.h"
77 #include "include/core/SkFontMgr.h"
78 #include "include/core/SkFontTypes.h"
79 #include "modules/skparagraph/include/Paragraph.h"
80 #endif
81 
82 #ifdef SK_INCLUDE_PATHOPS
83 #include "include/pathops/SkPathOps.h"
84 #endif
85 
86 #ifndef SK_NO_FONTS
87 sk_sp<SkFontMgr> SkFontMgr_New_Custom_Data(sk_sp<SkData>* datas, int n);
88 #endif
89 
90 struct OptionalMatrix : SkMatrix {
OptionalMatrixOptionalMatrix91     OptionalMatrix(WASMPointerF32 mPtr) {
92         if (mPtr) {
93             const SkScalar* nineMatrixValues = reinterpret_cast<const SkScalar*>(mPtr);
94             this->set9(nineMatrixValues);
95         }
96     }
97 };
98 
ptrToSkColor4f(WASMPointerF32 cPtr)99 SkColor4f ptrToSkColor4f(WASMPointerF32 cPtr) {
100     float* fourFloats = reinterpret_cast<float*>(cPtr);
101     SkColor4f color;
102     memcpy(&color, fourFloats, 4 * sizeof(float));
103     return color;
104 }
105 
ptrToSkRRect(WASMPointerF32 fPtr)106 SkRRect ptrToSkRRect(WASMPointerF32 fPtr) {
107     // In order, these floats should be 4 floats for the rectangle
108     // (left, top, right, bottom) and then 8 floats for the radii
109     // (upper left, upper right, lower right, lower left).
110     const SkScalar* twelveFloats = reinterpret_cast<const SkScalar*>(fPtr);
111     const SkRect rect = reinterpret_cast<const SkRect*>(twelveFloats)[0];
112     const SkVector* radiiValues = reinterpret_cast<const SkVector*>(twelveFloats + 4);
113 
114     SkRRect rr;
115     rr.setRectRadii(rect, radiiValues);
116     return rr;
117 }
118 
119 // Surface creation structs and helpers
120 struct SimpleImageInfo {
121     int width;
122     int height;
123     SkColorType colorType;
124     SkAlphaType alphaType;
125     sk_sp<SkColorSpace> colorSpace;
126 };
127 
toSkImageInfo(const SimpleImageInfo & sii)128 SkImageInfo toSkImageInfo(const SimpleImageInfo& sii) {
129     return SkImageInfo::Make(sii.width, sii.height, sii.colorType, sii.alphaType, sii.colorSpace);
130 }
131 
132 #ifdef SK_GL
133 
134 // Set the pixel format based on the colortype.
135 // These degrees of freedom are removed from canvaskit only to keep the interface simpler.
136 struct ColorSettings {
ColorSettingsColorSettings137     ColorSettings(sk_sp<SkColorSpace> colorSpace) {
138         if (colorSpace == nullptr || colorSpace->isSRGB()) {
139             colorType = kRGBA_8888_SkColorType;
140             pixFormat = GR_GL_RGBA8;
141         } else {
142             colorType = kRGBA_F16_SkColorType;
143             pixFormat = GR_GL_RGBA16F;
144         }
145     };
146     SkColorType colorType;
147     GrGLenum pixFormat;
148 };
149 
MakeGrContext()150 sk_sp<GrDirectContext> MakeGrContext()
151 {
152     // We assume that any calls we make to GL for the remainder of this function will go to the
153     // desired WebGL Context.
154     // setup interface.
155     auto interface = GrGLMakeNativeInterface();
156     // setup context
157     return GrDirectContext::MakeGL(interface);
158 }
159 
MakeOnScreenGLSurface(sk_sp<GrDirectContext> dContext,int width,int height,sk_sp<SkColorSpace> colorSpace)160 sk_sp<SkSurface> MakeOnScreenGLSurface(sk_sp<GrDirectContext> dContext, int width, int height,
161                                        sk_sp<SkColorSpace> colorSpace) {
162     // WebGL should already be clearing the color and stencil buffers, but do it again here to
163     // ensure Skia receives them in the expected state.
164     emscripten_glBindFramebuffer(GL_FRAMEBUFFER, 0);
165     emscripten_glClearColor(0, 0, 0, 0);
166     emscripten_glClearStencil(0);
167     emscripten_glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
168     dContext->resetContext(kRenderTarget_GrGLBackendState | kMisc_GrGLBackendState);
169 
170     // The on-screen canvas is FBO 0. Wrap it in a Skia render target so Skia can render to it.
171     GrGLFramebufferInfo info;
172     info.fFBOID = 0;
173 
174     GrGLint sampleCnt;
175     emscripten_glGetIntegerv(GL_SAMPLES, &sampleCnt);
176 
177     GrGLint stencil;
178     emscripten_glGetIntegerv(GL_STENCIL_BITS, &stencil);
179 
180     const auto colorSettings = ColorSettings(colorSpace);
181     info.fFormat = colorSettings.pixFormat;
182     GrBackendRenderTarget target(width, height, sampleCnt, stencil, info);
183     sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget(dContext.get(), target,
184         kBottomLeft_GrSurfaceOrigin, colorSettings.colorType, colorSpace, nullptr));
185     return surface;
186 }
187 
MakeRenderTarget(sk_sp<GrDirectContext> dContext,int width,int height)188 sk_sp<SkSurface> MakeRenderTarget(sk_sp<GrDirectContext> dContext, int width, int height) {
189     SkImageInfo info = SkImageInfo::MakeN32(width, height, SkAlphaType::kPremul_SkAlphaType);
190 
191     sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(dContext.get(),
192                              SkBudgeted::kYes,
193                              info, 0,
194                              kBottomLeft_GrSurfaceOrigin,
195                              nullptr, true));
196     return surface;
197 }
198 
MakeRenderTarget(sk_sp<GrDirectContext> dContext,SimpleImageInfo sii)199 sk_sp<SkSurface> MakeRenderTarget(sk_sp<GrDirectContext> dContext, SimpleImageInfo sii) {
200     sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(dContext.get(),
201                              SkBudgeted::kYes,
202                              toSkImageInfo(sii), 0,
203                              kBottomLeft_GrSurfaceOrigin,
204                              nullptr, true));
205     return surface;
206 }
207 #endif
208 
209 
210 //========================================================================================
211 // Path things
212 //========================================================================================
213 
214 // All these Apply* methods are simple wrappers to avoid returning an object.
215 // The default WASM bindings produce code that will leak if a return value
216 // isn't assigned to a JS variable and has delete() called on it.
217 // These Apply methods, combined with the smarter binding code allow for chainable
218 // commands that don't leak if the return value is ignored (i.e. when used intuitively).
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)219 void ApplyAddPath(SkPath& orig, const SkPath& newPath,
220                    SkScalar scaleX, SkScalar skewX,  SkScalar transX,
221                    SkScalar skewY,  SkScalar scaleY, SkScalar transY,
222                    SkScalar pers0, SkScalar pers1, SkScalar pers2,
223                    bool extendPath) {
224     SkMatrix m = SkMatrix::MakeAll(scaleX, skewX , transX,
225                                    skewY , scaleY, transY,
226                                    pers0 , pers1 , pers2);
227     orig.addPath(newPath, m, extendPath ? SkPath::kExtend_AddPathMode :
228                                           SkPath::kAppend_AddPathMode);
229 }
230 
ApplyArcToTangent(SkPath & p,SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2,SkScalar radius)231 void ApplyArcToTangent(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
232                 SkScalar radius) {
233     p.arcTo(x1, y1, x2, y2, radius);
234 }
235 
ApplyArcToArcSize(SkPath & orig,SkScalar rx,SkScalar ry,SkScalar xAxisRotate,bool useSmallArc,bool ccw,SkScalar x,SkScalar y)236 void ApplyArcToArcSize(SkPath& orig, SkScalar rx, SkScalar ry, SkScalar xAxisRotate,
237                        bool useSmallArc, bool ccw, SkScalar x, SkScalar y) {
238     auto arcSize = useSmallArc ? SkPath::ArcSize::kSmall_ArcSize : SkPath::ArcSize::kLarge_ArcSize;
239     auto sweep = ccw ? SkPathDirection::kCCW : SkPathDirection::kCW;
240     orig.arcTo(rx, ry, xAxisRotate, arcSize, sweep, x, y);
241 }
242 
ApplyRArcToArcSize(SkPath & orig,SkScalar rx,SkScalar ry,SkScalar xAxisRotate,bool useSmallArc,bool ccw,SkScalar dx,SkScalar dy)243 void ApplyRArcToArcSize(SkPath& orig, SkScalar rx, SkScalar ry, SkScalar xAxisRotate,
244                         bool useSmallArc, bool ccw, SkScalar dx, SkScalar dy) {
245     auto arcSize = useSmallArc ? SkPath::ArcSize::kSmall_ArcSize : SkPath::ArcSize::kLarge_ArcSize;
246     auto sweep = ccw ? SkPathDirection::kCCW : SkPathDirection::kCW;
247     orig.rArcTo(rx, ry, xAxisRotate, arcSize, sweep, dx, dy);
248 }
249 
ApplyClose(SkPath & p)250 void ApplyClose(SkPath& p) {
251     p.close();
252 }
253 
ApplyConicTo(SkPath & p,SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2,SkScalar w)254 void ApplyConicTo(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
255                   SkScalar w) {
256     p.conicTo(x1, y1, x2, y2, w);
257 }
258 
ApplyRConicTo(SkPath & p,SkScalar dx1,SkScalar dy1,SkScalar dx2,SkScalar dy2,SkScalar w)259 void ApplyRConicTo(SkPath& p, SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
260                   SkScalar w) {
261     p.rConicTo(dx1, dy1, dx2, dy2, w);
262 }
263 
ApplyCubicTo(SkPath & p,SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2,SkScalar x3,SkScalar y3)264 void ApplyCubicTo(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
265                   SkScalar x3, SkScalar y3) {
266     p.cubicTo(x1, y1, x2, y2, x3, y3);
267 }
268 
ApplyRCubicTo(SkPath & p,SkScalar dx1,SkScalar dy1,SkScalar dx2,SkScalar dy2,SkScalar dx3,SkScalar dy3)269 void ApplyRCubicTo(SkPath& p, SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
270                   SkScalar dx3, SkScalar dy3) {
271     p.rCubicTo(dx1, dy1, dx2, dy2, dx3, dy3);
272 }
273 
ApplyLineTo(SkPath & p,SkScalar x,SkScalar y)274 void ApplyLineTo(SkPath& p, SkScalar x, SkScalar y) {
275     p.lineTo(x, y);
276 }
277 
ApplyRLineTo(SkPath & p,SkScalar dx,SkScalar dy)278 void ApplyRLineTo(SkPath& p, SkScalar dx, SkScalar dy) {
279     p.rLineTo(dx, dy);
280 }
281 
ApplyMoveTo(SkPath & p,SkScalar x,SkScalar y)282 void ApplyMoveTo(SkPath& p, SkScalar x, SkScalar y) {
283     p.moveTo(x, y);
284 }
285 
ApplyRMoveTo(SkPath & p,SkScalar dx,SkScalar dy)286 void ApplyRMoveTo(SkPath& p, SkScalar dx, SkScalar dy) {
287     p.rMoveTo(dx, dy);
288 }
289 
ApplyReset(SkPath & p)290 void ApplyReset(SkPath& p) {
291     p.reset();
292 }
293 
ApplyRewind(SkPath & p)294 void ApplyRewind(SkPath& p) {
295     p.rewind();
296 }
297 
ApplyQuadTo(SkPath & p,SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2)298 void ApplyQuadTo(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
299     p.quadTo(x1, y1, x2, y2);
300 }
301 
ApplyRQuadTo(SkPath & p,SkScalar dx1,SkScalar dy1,SkScalar dx2,SkScalar dy2)302 void ApplyRQuadTo(SkPath& p, SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2) {
303     p.rQuadTo(dx1, dy1, dx2, dy2);
304 }
305 
ApplyTransform(SkPath & orig,SkScalar scaleX,SkScalar skewX,SkScalar transX,SkScalar skewY,SkScalar scaleY,SkScalar transY,SkScalar pers0,SkScalar pers1,SkScalar pers2)306 void ApplyTransform(SkPath& orig,
307                     SkScalar scaleX, SkScalar skewX,  SkScalar transX,
308                     SkScalar skewY,  SkScalar scaleY, SkScalar transY,
309                     SkScalar pers0, SkScalar pers1, SkScalar pers2) {
310     SkMatrix m = SkMatrix::MakeAll(scaleX, skewX , transX,
311                                    skewY , scaleY, transY,
312                                    pers0 , pers1 , pers2);
313     orig.transform(m);
314 }
315 
316 #ifdef SK_INCLUDE_PATHOPS
ApplySimplify(SkPath & path)317 bool ApplySimplify(SkPath& path) {
318     return Simplify(path, &path);
319 }
320 
ApplyPathOp(SkPath & pathOne,const SkPath & pathTwo,SkPathOp op)321 bool ApplyPathOp(SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
322     return Op(pathOne, pathTwo, op, &pathOne);
323 }
324 
MakePathFromOp(const SkPath & pathOne,const SkPath & pathTwo,SkPathOp op)325 SkPathOrNull MakePathFromOp(const SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
326     SkPath out;
327     if (Op(pathOne, pathTwo, op, &out)) {
328         return emscripten::val(out);
329     }
330     return emscripten::val::null();
331 }
332 
MakeAsWinding(const SkPath & self)333 SkPathOrNull MakeAsWinding(const SkPath& self) {
334     SkPath out;
335     if (AsWinding(self, &out)) {
336         return emscripten::val(out);
337     }
338     return emscripten::val::null();
339 }
340 #endif
341 
ToSVGString(const SkPath & path)342 JSString ToSVGString(const SkPath& path) {
343     SkString s;
344     SkParsePath::ToSVGString(path, &s);
345     return emscripten::val(s.c_str());
346 }
347 
MakePathFromSVGString(std::string str)348 SkPathOrNull MakePathFromSVGString(std::string str) {
349     SkPath path;
350     if (SkParsePath::FromSVGString(str.c_str(), &path)) {
351         return emscripten::val(path);
352     }
353     return emscripten::val::null();
354 }
355 
CopyPath(const SkPath & a)356 SkPath CopyPath(const SkPath& a) {
357     SkPath copy(a);
358     return copy;
359 }
360 
Equals(const SkPath & a,const SkPath & b)361 bool Equals(const SkPath& a, const SkPath& b) {
362     return a == b;
363 }
364 
365 // =================================================================================
366 // Creating/Exporting Paths with cmd arrays
367 // =================================================================================
368 
369 static const int MOVE = 0;
370 static const int LINE = 1;
371 static const int QUAD = 2;
372 static const int CONIC = 3;
373 static const int CUBIC = 4;
374 static const int CLOSE = 5;
375 
ToCmds(const SkPath & path)376 Float32Array ToCmds(const SkPath& path) {
377     std::vector<SkScalar> cmds;
378     for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
379         switch (verb) {
380         case SkPathVerb::kMove:
381             cmds.insert(cmds.end(), {MOVE, pts[0].x(), pts[0].y()});
382             break;
383         case SkPathVerb::kLine:
384             cmds.insert(cmds.end(), {LINE, pts[1].x(), pts[1].y()});
385             break;
386         case SkPathVerb::kQuad:
387             cmds.insert(cmds.end(), {QUAD, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y()});
388             break;
389         case SkPathVerb::kConic:
390             cmds.insert(cmds.end(), {CONIC,
391                            pts[1].x(), pts[1].y(),
392                            pts[2].x(), pts[2].y(), *w});
393             break;
394         case SkPathVerb::kCubic:
395             cmds.insert(cmds.end(), {CUBIC,
396                            pts[1].x(), pts[1].y(),
397                            pts[2].x(), pts[2].y(),
398                            pts[3].x(), pts[3].y()});
399             break;
400         case SkPathVerb::kClose:
401             cmds.push_back(CLOSE);
402             break;
403         }
404     }
405     return MakeTypedArray(cmds.size(), (const float*)cmds.data());
406 }
407 
MakePathFromCmds(WASMPointerF32 cptr,int numCmds)408 SkPathOrNull MakePathFromCmds(WASMPointerF32 cptr, int numCmds) {
409     const auto* cmds = reinterpret_cast<const float*>(cptr);
410     SkPath path;
411     float x1, y1, x2, y2, x3, y3;
412 
413     // if there are not enough arguments, bail with the path we've constructed so far.
414     #define CHECK_NUM_ARGS(n) \
415         if ((i + n) > numCmds) { \
416             SkDebugf("Not enough args to match the verbs. Saw %d commands\n", numCmds); \
417             return emscripten::val::null(); \
418         }
419 
420     for(int i = 0; i < numCmds;){
421          switch (sk_float_floor2int(cmds[i++])) {
422             case MOVE:
423                 CHECK_NUM_ARGS(2);
424                 x1 = cmds[i++], y1 = cmds[i++];
425                 path.moveTo(x1, y1);
426                 break;
427             case LINE:
428                 CHECK_NUM_ARGS(2);
429                 x1 = cmds[i++], y1 = cmds[i++];
430                 path.lineTo(x1, y1);
431                 break;
432             case QUAD:
433                 CHECK_NUM_ARGS(4);
434                 x1 = cmds[i++], y1 = cmds[i++];
435                 x2 = cmds[i++], y2 = cmds[i++];
436                 path.quadTo(x1, y1, x2, y2);
437                 break;
438             case CONIC:
439                 CHECK_NUM_ARGS(5);
440                 x1 = cmds[i++], y1 = cmds[i++];
441                 x2 = cmds[i++], y2 = cmds[i++];
442                 x3 = cmds[i++]; // weight
443                 path.conicTo(x1, y1, x2, y2, x3);
444                 break;
445             case CUBIC:
446                 CHECK_NUM_ARGS(6);
447                 x1 = cmds[i++], y1 = cmds[i++];
448                 x2 = cmds[i++], y2 = cmds[i++];
449                 x3 = cmds[i++], y3 = cmds[i++];
450                 path.cubicTo(x1, y1, x2, y2, x3, y3);
451                 break;
452             case CLOSE:
453                 path.close();
454                 break;
455             default:
456                 SkDebugf("  path: UNKNOWN command %f, aborting dump...\n", cmds[i-1]);
457                 return emscripten::val::null();
458         }
459     }
460 
461     #undef CHECK_NUM_ARGS
462 
463     return emscripten::val(path);
464 }
465 
PathAddVerbsPointsWeights(SkPath & path,WASMPointerU8 verbsPtr,int numVerbs,WASMPointerF32 ptsPtr,int numPts,WASMPointerF32 wtsPtr,int numWts)466 void PathAddVerbsPointsWeights(SkPath& path, WASMPointerU8 verbsPtr, int numVerbs,
467                                              WASMPointerF32 ptsPtr, int numPts,
468                                              WASMPointerF32 wtsPtr, int numWts) {
469     const uint8_t* verbs = reinterpret_cast<const uint8_t*>(verbsPtr);
470     const float* pts = reinterpret_cast<const float*>(ptsPtr);
471     const float* weights = reinterpret_cast<const float*>(wtsPtr);
472 
473     #define CHECK_NUM_POINTS(n) \
474         if ((ptIdx + n) > numPts) { \
475             SkDebugf("Not enough points to match the verbs. Saw %d points\n", numPts); \
476             return; \
477         }
478     #define CHECK_NUM_WEIGHTS(n) \
479         if ((wtIdx + n) > numWts) { \
480             SkDebugf("Not enough weights to match the verbs. Saw %d weights\n", numWts); \
481             return; \
482         }
483 
484     path.incReserve(numPts);
485     int ptIdx = 0;
486     int wtIdx = 0;
487     for (int v = 0; v < numVerbs; ++v) {
488          switch (verbs[v]) {
489               case MOVE:
490                   CHECK_NUM_POINTS(2);
491                   path.moveTo(pts[ptIdx], pts[ptIdx+1]);
492                   ptIdx += 2;
493                   break;
494               case LINE:
495                   CHECK_NUM_POINTS(2);
496                   path.lineTo(pts[ptIdx], pts[ptIdx+1]);
497                   ptIdx += 2;
498                   break;
499               case QUAD:
500                   CHECK_NUM_POINTS(4);
501                   path.quadTo(pts[ptIdx], pts[ptIdx+1], pts[ptIdx+2], pts[ptIdx+3]);
502                   ptIdx += 4;
503                   break;
504               case CONIC:
505                   CHECK_NUM_POINTS(4);
506                   CHECK_NUM_WEIGHTS(1);
507                   path.conicTo(pts[ptIdx], pts[ptIdx+1], pts[ptIdx+2], pts[ptIdx+3],
508                                weights[wtIdx]);
509                   ptIdx += 4;
510                   wtIdx++;
511                   break;
512               case CUBIC:
513                   CHECK_NUM_POINTS(6);
514                   path.cubicTo(pts[ptIdx  ], pts[ptIdx+1],
515                                pts[ptIdx+2], pts[ptIdx+3],
516                                pts[ptIdx+4], pts[ptIdx+5]);
517                   ptIdx += 6;
518                   break;
519               case CLOSE:
520                   path.close();
521                   break;
522         }
523     }
524     #undef CHECK_NUM_POINTS
525     #undef CHECK_NUM_WEIGHTS
526 }
527 
MakePathFromVerbsPointsWeights(WASMPointerU8 verbsPtr,int numVerbs,WASMPointerF32 ptsPtr,int numPts,WASMPointerF32 wtsPtr,int numWts)528 SkPath MakePathFromVerbsPointsWeights(WASMPointerU8 verbsPtr, int numVerbs,
529                                       WASMPointerF32 ptsPtr, int numPts,
530                                       WASMPointerF32 wtsPtr, int numWts) {
531     SkPath path;
532     PathAddVerbsPointsWeights(path, verbsPtr, numVerbs, ptsPtr, numPts, wtsPtr, numWts);
533     return path;
534 }
535 
536 //========================================================================================
537 // Path Effects
538 //========================================================================================
539 
ApplyDash(SkPath & path,SkScalar on,SkScalar off,SkScalar phase)540 bool ApplyDash(SkPath& path, SkScalar on, SkScalar off, SkScalar phase) {
541     SkScalar intervals[] = { on, off };
542     auto pe = SkDashPathEffect::Make(intervals, 2, phase);
543     if (!pe) {
544         SkDebugf("Invalid args to dash()\n");
545         return false;
546     }
547     SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle);
548     if (pe->filterPath(&path, path, &rec, nullptr)) {
549         return true;
550     }
551     SkDebugf("Could not make dashed path\n");
552     return false;
553 }
554 
ApplyTrim(SkPath & path,SkScalar startT,SkScalar stopT,bool isComplement)555 bool ApplyTrim(SkPath& path, SkScalar startT, SkScalar stopT, bool isComplement) {
556     auto mode = isComplement ? SkTrimPathEffect::Mode::kInverted : SkTrimPathEffect::Mode::kNormal;
557     auto pe = SkTrimPathEffect::Make(startT, stopT, mode);
558     if (!pe) {
559         SkDebugf("Invalid args to trim(): startT and stopT must be in [0,1]\n");
560         return false;
561     }
562     SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle);
563     if (pe->filterPath(&path, path, &rec, nullptr)) {
564         return true;
565     }
566     SkDebugf("Could not trim path\n");
567     return false;
568 }
569 
570 struct StrokeOpts {
571     // Default values are set in interface.js which allows clients
572     // to set any number of them. Otherwise, the binding code complains if
573     // any are omitted.
574     SkScalar width;
575     SkScalar miter_limit;
576     SkPaint::Join join;
577     SkPaint::Cap cap;
578     float precision;
579 };
580 
ApplyStroke(SkPath & path,StrokeOpts opts)581 bool ApplyStroke(SkPath& path, StrokeOpts opts) {
582     SkPaint p;
583     p.setStyle(SkPaint::kStroke_Style);
584     p.setStrokeCap(opts.cap);
585     p.setStrokeJoin(opts.join);
586     p.setStrokeWidth(opts.width);
587     p.setStrokeMiter(opts.miter_limit);
588 
589     return p.getFillPath(path, &path, nullptr, opts.precision);
590 }
591 
592 // This function is private, we call it in interface.js
computeTonalColors(WASMPointerF32 cPtrAmbi,WASMPointerF32 cPtrSpot)593 void computeTonalColors(WASMPointerF32 cPtrAmbi, WASMPointerF32 cPtrSpot) {
594     // private methods accepting colors take pointers to floats already copied into wasm memory.
595     float* ambiFloats = reinterpret_cast<float*>(cPtrAmbi);
596     float* spotFloats = reinterpret_cast<float*>(cPtrSpot);
597     SkColor4f ambiColor = { ambiFloats[0], ambiFloats[1], ambiFloats[2], ambiFloats[3]};
598     SkColor4f spotColor = { spotFloats[0], spotFloats[1], spotFloats[2], spotFloats[3]};
599 
600     // This function takes SkColor
601     SkColor resultAmbi, resultSpot;
602     SkShadowUtils::ComputeTonalColors(
603         ambiColor.toSkColor(), spotColor.toSkColor(),
604         &resultAmbi, &resultSpot);
605 
606     // Convert back to color4f
607     const SkColor4f ambi4f = SkColor4f::FromColor(resultAmbi);
608     const SkColor4f spot4f = SkColor4f::FromColor(resultSpot);
609 
610     // Re-use the caller's allocated memory to hold the result.
611     memcpy(ambiFloats, ambi4f.vec(), 4 * sizeof(SkScalar));
612     memcpy(spotFloats, spot4f.vec(), 4 * sizeof(SkScalar));
613 }
614 
615 #ifdef SK_INCLUDE_RUNTIME_EFFECT
616 struct RuntimeEffectUniform {
617     int columns;
618     int rows;
619     int slot; // the index into the uniforms array that this uniform begins.
620     bool isInteger;
621 };
622 
fromUniform(const SkRuntimeEffect::Uniform & u)623 RuntimeEffectUniform fromUniform(const SkRuntimeEffect::Uniform& u) {
624     RuntimeEffectUniform su;
625     su.rows      = u.count;  // arrayLength
626     su.columns   = 1;
627     su.isInteger = false;
628     using Type = SkRuntimeEffect::Uniform::Type;
629     switch (u.type) {
630         case Type::kFloat:                                                       break;
631         case Type::kFloat2:   su.columns = 2;                                    break;
632         case Type::kFloat3:   su.columns = 3;                                    break;
633         case Type::kFloat4:   su.columns = 4;                                    break;
634         case Type::kFloat2x2: su.columns = 2; su.rows *= 2;                      break;
635         case Type::kFloat3x3: su.columns = 3; su.rows *= 3;                      break;
636         case Type::kFloat4x4: su.columns = 4; su.rows *= 4;                      break;
637         case Type::kInt:                                    su.isInteger = true; break;
638         case Type::kInt2:     su.columns = 2;               su.isInteger = true; break;
639         case Type::kInt3:     su.columns = 3;               su.isInteger = true; break;
640         case Type::kInt4:     su.columns = 4;               su.isInteger = true; break;
641     }
642     su.slot = u.offset / sizeof(float);
643     return su;
644 }
645 
castUniforms(void * data,size_t dataLen,const SkRuntimeEffect & effect)646 void castUniforms(void* data, size_t dataLen, const SkRuntimeEffect& effect) {
647     if (dataLen != effect.uniformSize()) {
648         // Incorrect number of uniforms. Our code below could read/write off the end of the buffer.
649         // However, shader creation is going to fail anyway, so just do nothing.
650         return;
651     }
652 
653     float* fltData = reinterpret_cast<float*>(data);
654     for (const auto& u : effect.uniforms()) {
655         RuntimeEffectUniform reu = fromUniform(u);
656         if (reu.isInteger) {
657             // The SkSL is expecting integers in the uniform data
658             for (int i = 0; i < reu.columns * reu.rows; ++i) {
659                 int numAsInt = static_cast<int>(fltData[reu.slot + i]);
660                 fltData[reu.slot + i] = SkBits2Float(numAsInt);
661             }
662         }
663     }
664 }
665 #endif
666 
667 // These objects have private destructors / delete methods - I don't think
668 // we need to do anything other than tell emscripten to do nothing.
669 namespace emscripten {
670     namespace internal {
671         template<typename ClassType>
672         void raw_destructor(ClassType*);
673 
674         template<>
raw_destructor(SkContourMeasure * ptr)675         void raw_destructor<SkContourMeasure>(SkContourMeasure* ptr) {
676         }
677 
678         template<>
raw_destructor(SkVertices * ptr)679         void raw_destructor<SkVertices>(SkVertices* ptr) {
680         }
681 
682 #ifndef SK_NO_FONTS
683         template<>
raw_destructor(SkTextBlob * ptr)684         void raw_destructor<SkTextBlob>(SkTextBlob* ptr) {
685         }
686 
687         template<>
raw_destructor(SkTypeface * ptr)688         void raw_destructor<SkTypeface>(SkTypeface* ptr) {
689         }
690 #endif
691     }
692 }
693 
694 // toBytes returns a Uint8Array that has a copy of the data in the given SkData.
toBytes(sk_sp<SkData> data)695 Uint8Array toBytes(sk_sp<SkData> data) {
696     // By making the copy using the JS transliteration, we don't risk the SkData object being
697     // cleaned up before we make the copy.
698     return emscripten::val(
699         // https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#memory-views
700         typed_memory_view(data->size(), data->bytes())
701     ).call<Uint8Array>("slice"); // slice with no args makes a copy of the memory view.
702 }
703 
704 #ifdef SK_GL
705 // We need to call into the JS side of things to free webGL contexts. This object will be called
706 // with _setTextureCleanup after CanvasKit loads. The object will have one attribute,
707 // a function called deleteTexture that takes two ints.
708 JSObject textureCleanup = emscripten::val::null();
709 
710 struct TextureReleaseContext {
711     // This refers to which webgl context, i.e. which surface, owns the texture. We need this
712     // to route the deleteTexture to the right context.
713     uint32_t webglHandle;
714     // This refers to the index of the texture in the complete list of textures.
715     uint32_t texHandle;
716 };
717 
deleteJSTexture(SkImage::ReleaseContext rc)718 void deleteJSTexture(SkImage::ReleaseContext rc) {
719     auto ctx = reinterpret_cast<TextureReleaseContext*>(rc);
720     textureCleanup.call<void>("deleteTexture", ctx->webglHandle, ctx->texHandle);
721     delete ctx;
722 }
723 
724 class WebGLTextureImageGenerator : public SkImageGenerator {
725 public:
WebGLTextureImageGenerator(SkImageInfo ii,JSObject callbackObj)726     WebGLTextureImageGenerator(SkImageInfo ii, JSObject callbackObj):
727             SkImageGenerator(ii),
728             fCallback(callbackObj) {}
729 
~WebGLTextureImageGenerator()730     ~WebGLTextureImageGenerator() {
731         // This cleans up the associated TextureSource that is used to make the texture
732         // (i.e. "makeTexture" below). We expect this destructor to be called when the
733         // SkImage that this Generator belongs to is destroyed.
734         fCallback.call<void>("freeSrc");
735     }
736 
737 protected:
onGenerateTexture(GrRecordingContext * ctx,const SkImageInfo & info,const SkIPoint & origin,GrMipmapped mipMapped,GrImageTexGenPolicy texGenPolicy)738     GrSurfaceProxyView onGenerateTexture(GrRecordingContext* ctx,
739                                          const SkImageInfo& info,
740                                          const SkIPoint& origin,
741                                          GrMipmapped mipMapped,
742                                          GrImageTexGenPolicy texGenPolicy) {
743         if (ctx->backend() != GrBackendApi::kOpenGL) {
744             return {};
745         }
746 
747         GrGLTextureInfo glInfo;
748         glInfo.fID     = fCallback.call<uint32_t>("makeTexture");
749         // The format and target should match how we make the texture on the JS side
750         // See the implementation of the makeTexture function.
751         glInfo.fFormat = GR_GL_RGBA8;
752         glInfo.fTarget = GR_GL_TEXTURE_2D;
753 
754         static constexpr auto kMipmapped = GrMipmapped::kNo;
755         GrBackendTexture backendTexture(info.width(), info.height(), kMipmapped, glInfo);
756 
757         const GrBackendFormat& format    = backendTexture.getBackendFormat();
758         const GrColorType      colorType = SkColorTypeToGrColorType(info.colorType());
759         if (!ctx->priv().caps()->areColorTypeAndFormatCompatible(colorType, format)) {
760             return {};
761         }
762 
763         uint32_t webGLCtx = emscripten_webgl_get_current_context();
764         auto releaseCtx = new TextureReleaseContext{webGLCtx, glInfo.fID};
765         auto cleanupCallback = GrRefCntedCallback::Make(deleteJSTexture, releaseCtx);
766 
767         sk_sp<GrSurfaceProxy> proxy = ctx->priv().proxyProvider()->wrapBackendTexture(
768                 backendTexture,
769                 kBorrow_GrWrapOwnership,
770                 GrWrapCacheable::kYes,
771                 kRead_GrIOType,
772                 std::move(cleanupCallback));
773         if (!proxy) {
774             return {};
775         }
776         static constexpr auto kOrigin = kTopLeft_GrSurfaceOrigin;
777         GrSwizzle swizzle = ctx->priv().caps()->getReadSwizzle(format, colorType);
778         return GrSurfaceProxyView(std::move(proxy), kOrigin, swizzle);
779     }
780 
781 private:
782     JSObject fCallback;
783 };
784 
785 // callbackObj has two functions in it, one to create a texture "makeTexture" and one to clean up
786 // the underlying texture source "freeSrc". This way, we can create WebGL textures for each
787 // surface/WebGLContext that the image is used on (we cannot share WebGLTextures across contexts).
MakeImageFromGenerator(SimpleImageInfo ii,JSObject callbackObj)788 sk_sp<SkImage> MakeImageFromGenerator(SimpleImageInfo ii, JSObject callbackObj) {
789     auto gen = std::make_unique<WebGLTextureImageGenerator>(toSkImageInfo(ii), callbackObj);
790     return SkImage::MakeFromGenerator(std::move(gen));
791 }
792 #endif // SK_GL
793 
EMSCRIPTEN_BINDINGS(Skia)794 EMSCRIPTEN_BINDINGS(Skia) {
795 #ifdef SK_GL
796     function("_MakeGrContext", &MakeGrContext);
797     function("_MakeOnScreenGLSurface", &MakeOnScreenGLSurface);
798     function("_MakeRenderTargetWH", select_overload<sk_sp<SkSurface>(sk_sp<GrDirectContext>, int, int)>(&MakeRenderTarget));
799     function("_MakeRenderTargetII", select_overload<sk_sp<SkSurface>(sk_sp<GrDirectContext>, SimpleImageInfo)>(&MakeRenderTarget));
800 
801     constant("gpu", true);
802 #endif
803     function("getDecodeCacheLimitBytes", &SkResourceCache::GetTotalByteLimit);
804     function("setDecodeCacheLimitBytes", &SkResourceCache::SetTotalByteLimit);
805     function("getDecodeCacheUsedBytes" , &SkResourceCache::GetTotalBytesUsed);
806 
807     function("_computeTonalColors", &computeTonalColors);
808     function("_decodeAnimatedImage", optional_override([](WASMPointerU8 iptr,
809                                                   size_t length)->sk_sp<SkAnimatedImage> {
810         uint8_t* imgData = reinterpret_cast<uint8_t*>(iptr);
811         auto bytes = SkData::MakeFromMalloc(imgData, length);
812         auto aCodec = SkAndroidCodec::MakeFromData(std::move(bytes));
813         if (nullptr == aCodec) {
814             return nullptr;
815         }
816 
817         return SkAnimatedImage::Make(std::move(aCodec));
818     }), allow_raw_pointers());
819     function("_decodeImage", optional_override([](WASMPointerU8 iptr,
820                                                   size_t length)->sk_sp<SkImage> {
821         uint8_t* imgData = reinterpret_cast<uint8_t*>(iptr);
822         sk_sp<SkData> bytes = SkData::MakeFromMalloc(imgData, length);
823         return SkImage::MakeFromEncoded(std::move(bytes));
824     }), allow_raw_pointers());
825 
826     // These won't be called directly, there are corresponding JS helpers to deal with arrays.
827     function("_MakeImage", optional_override([](SimpleImageInfo ii,
828                                                 WASMPointerU8 pPtr, int plen,
829                                                 size_t rowBytes)->sk_sp<SkImage> {
830         uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
831         SkImageInfo info = toSkImageInfo(ii);
832         sk_sp<SkData> pixelData = SkData::MakeFromMalloc(pixels, plen);
833 
834         return SkImage::MakeRasterData(info, pixelData, rowBytes);
835     }), allow_raw_pointers());
836 
837     function("_getShadowLocalBounds", optional_override([](
838             WASMPointerF32 ctmPtr, const SkPath& path,
839             WASMPointerF32  zPlaneParamPtr, WASMPointerF32 lightPosPtr,
840             SkScalar lightRadius, uint32_t flags, WASMPointerF32 outPtr) -> bool {
841         SkMatrix ctm;
842         const SkScalar* nineMatrixValues = reinterpret_cast<const SkScalar*>(ctmPtr);
843         ctm.set9(nineMatrixValues);
844         const SkVector3* zPlaneParams = reinterpret_cast<const SkVector3*>(zPlaneParamPtr);
845         const SkVector3* lightPos = reinterpret_cast<const SkVector3*>(lightPosPtr);
846         SkRect* outputBounds = reinterpret_cast<SkRect*>(outPtr);
847         return SkShadowUtils::GetLocalBounds(ctm, path, *zPlaneParams, *lightPos, lightRadius,
848                               flags, outputBounds);
849     }));
850 
851 #ifdef SK_SERIALIZE_SKP
852     function("_MakePicture", optional_override([](WASMPointerU8 dPtr,
853                                                   size_t bytes)->sk_sp<SkPicture> {
854         uint8_t* d = reinterpret_cast<uint8_t*>(dPtr);
855         sk_sp<SkData> data = SkData::MakeFromMalloc(d, bytes);
856 
857         return SkPicture::MakeFromData(data.get(), nullptr);
858     }), allow_raw_pointers());
859 #endif
860 
861 #ifdef SK_GL
862     class_<GrDirectContext>("GrDirectContext")
863         .smart_ptr<sk_sp<GrDirectContext>>("sk_sp<GrDirectContext>")
864         .function("getResourceCacheLimitBytes",
865                 optional_override([](GrDirectContext& self)->size_t {
866             int maxResources = 0;// ignored
867             size_t currMax = 0;
868             self.getResourceCacheLimits(&maxResources, &currMax);
869             return currMax;
870         }))
871         .function("getResourceCacheUsageBytes",
872                 optional_override([](GrDirectContext& self)->size_t {
873             int usedResources = 0;// ignored
874             size_t currUsage = 0;
875             self.getResourceCacheUsage(&usedResources, &currUsage);
876             return currUsage;
877         }))
878         .function("releaseResourcesAndAbandonContext",
879                 &GrDirectContext::releaseResourcesAndAbandonContext)
880         .function("setResourceCacheLimitBytes",
881                 optional_override([](GrDirectContext& self, size_t maxResourceBytes)->void {
882             int maxResources = 0;
883             size_t currMax = 0; // ignored
884             self.getResourceCacheLimits(&maxResources, &currMax);
885             self.setResourceCacheLimits(maxResources, maxResourceBytes);
886         }));
887 
888     // This allows us to give the C++ code a JS callback to delete textures that
889     // have been passed in via makeImageFromTexture and makeImageFromTextureSource.
890     function("_setTextureCleanup", optional_override([](JSObject callbackObj)->void {
891          textureCleanup = callbackObj;
892      }));
893 #endif
894 
895     class_<SkAnimatedImage>("AnimatedImage")
896         .smart_ptr<sk_sp<SkAnimatedImage>>("sk_sp<AnimatedImage>")
897         .function("decodeNextFrame", &SkAnimatedImage::decodeNextFrame)
898         .function("getFrameCount", &SkAnimatedImage::getFrameCount)
899         .function("getRepetitionCount", &SkAnimatedImage::getRepetitionCount)
900         .function("height",  optional_override([](SkAnimatedImage& self)->int32_t {
901             // getBounds returns an SkRect, but internally, the width and height are ints.
902             return SkScalarFloorToInt(self.getBounds().height());
903         }))
904         .function("makeImageAtCurrentFrame", &SkAnimatedImage::getCurrentFrame)
905         .function("reset", &SkAnimatedImage::reset)
906         .function("width",  optional_override([](SkAnimatedImage& self)->int32_t {
907             return SkScalarFloorToInt(self.getBounds().width());
908         }));
909 
910     class_<SkCanvas>("Canvas")
911         .constructor<>()
912         .function("_clear", optional_override([](SkCanvas& self, WASMPointerF32 cPtr) {
913             self.clear(ptrToSkColor4f(cPtr));
914         }))
915         .function("clipPath", select_overload<void (const SkPath&, SkClipOp, bool)>(&SkCanvas::clipPath))
916         .function("_clipRRect", optional_override([](SkCanvas& self, WASMPointerF32 fPtr, SkClipOp op, bool doAntiAlias) {
917             self.clipRRect(ptrToSkRRect(fPtr), op, doAntiAlias);
918         }))
919         .function("_clipRect", optional_override([](SkCanvas& self, WASMPointerF32 fPtr, SkClipOp op, bool doAntiAlias) {
920             const SkRect* rect = reinterpret_cast<const SkRect*>(fPtr);
921             self.clipRect(*rect, op, doAntiAlias);
922         }))
923         .function("_concat", optional_override([](SkCanvas& self, WASMPointerF32 mPtr) {
924             //TODO(skbug.com/10108): make the JS side be column major.
925             const SkScalar* sixteenMatrixValues = reinterpret_cast<const SkScalar*>(mPtr);
926             SkM44 m = SkM44::RowMajor(sixteenMatrixValues);
927             self.concat(m);
928         }))
929         .function("_drawArc", optional_override([](SkCanvas& self, WASMPointerF32 fPtr,
930                                                   SkScalar startAngle, SkScalar sweepAngle,
931                                                   bool useCenter, const SkPaint& paint) {
932             const SkRect* oval = reinterpret_cast<const SkRect*>(fPtr);
933             self.drawArc(*oval, startAngle, sweepAngle, useCenter, paint);
934         }))
935         .function("_drawAtlasOptions", optional_override([](SkCanvas& self,
936                 const sk_sp<SkImage>& atlas, WASMPointerF32 xptr,
937                 WASMPointerF32 rptr, WASMPointerU32 cptr, int count,
938                 SkBlendMode mode, SkFilterMode filter, SkMipmapMode mipmap,
939                 const SkPaint* paint)->void {
940             const SkRSXform* dstXforms = reinterpret_cast<const SkRSXform*>(xptr);
941             const SkRect* srcRects = reinterpret_cast<const SkRect*>(rptr);
942             const SkColor* colors = nullptr;
943             if (cptr) {
944                 colors = reinterpret_cast<const SkColor*>(cptr);
945             }
946             SkSamplingOptions sampling(filter, mipmap);
947             self.drawAtlas(atlas.get(), dstXforms, srcRects, colors, count, mode, sampling,
948                            nullptr, paint);
949         }), allow_raw_pointers())
950         .function("_drawAtlasCubic", optional_override([](SkCanvas& self,
951                 const sk_sp<SkImage>& atlas, WASMPointerF32 xptr,
952                 WASMPointerF32 rptr, WASMPointerU32 cptr, int count,
953                 SkBlendMode mode, float B, float C, const SkPaint* paint)->void {
954             const SkRSXform* dstXforms = reinterpret_cast<const SkRSXform*>(xptr);
955             const SkRect* srcRects = reinterpret_cast<const SkRect*>(rptr);
956             const SkColor* colors = nullptr;
957             if (cptr) {
958                 colors = reinterpret_cast<const SkColor*>(cptr);
959             }
960             SkSamplingOptions sampling({B, C});
961             self.drawAtlas(atlas.get(), dstXforms, srcRects, colors, count, mode, sampling,
962                            nullptr, paint);
963         }), allow_raw_pointers())
964         .function("_drawCircle", select_overload<void (SkScalar, SkScalar, SkScalar, const SkPaint& paint)>(&SkCanvas::drawCircle))
965         .function("_drawColor", optional_override([](SkCanvas& self, WASMPointerF32 cPtr) {
966             self.drawColor(ptrToSkColor4f(cPtr));
967         }))
968         .function("_drawColor", optional_override([](SkCanvas& self, WASMPointerF32 cPtr, SkBlendMode mode) {
969             self.drawColor(ptrToSkColor4f(cPtr), mode);
970         }))
971         .function("_drawColorInt", optional_override([](SkCanvas& self, SkColor color, SkBlendMode mode) {
972             self.drawColor(color, mode);
973         }))
974         .function("_drawDRRect", optional_override([](SkCanvas& self, WASMPointerF32 outerPtr,
975                                                      WASMPointerF32 innerPtr, const SkPaint& paint) {
976             self.drawDRRect(ptrToSkRRect(outerPtr), ptrToSkRRect(innerPtr), paint);
977         }))
978         .function("_drawGlyphs", optional_override([](SkCanvas& self,
979                                                       int count,
980                                                       WASMPointerU16 glyphs,
981                                                       WASMPointerF32 positions,
982                                                       float x, float y,
983                                                       const SkFont& font,
984                                                       const SkPaint& paint)->void {
985             self.drawGlyphs(count,
986                             reinterpret_cast<const uint16_t*>(glyphs),
987                             reinterpret_cast<const SkPoint*>(positions),
988                             {x, y}, font, paint);
989         }))
990         // TODO: deprecate this version, and require sampling
991         .function("_drawImage", optional_override([](SkCanvas& self, const sk_sp<SkImage>& image,
992                                                     SkScalar x, SkScalar y, const SkPaint* paint) {
993             self.drawImage(image.get(), x, y, SkSamplingOptions(), paint);
994         }), allow_raw_pointers())
995         .function("_drawImageCubic",  optional_override([](SkCanvas& self, const sk_sp<SkImage>& img,
996                                                           SkScalar left, SkScalar top,
997                                                           float B, float C, // See SkSamplingOptions.h for docs.
998                                                           const SkPaint* paint)->void {
999             self.drawImage(img.get(), left, top, SkSamplingOptions({B, C}), paint);
1000         }), allow_raw_pointers())
1001         .function("_drawImageOptions",  optional_override([](SkCanvas& self, const sk_sp<SkImage>& img,
1002                                                           SkScalar left, SkScalar top,
1003                                                           SkFilterMode filter, SkMipmapMode mipmap,
1004                                                           const SkPaint* paint)->void {
1005             self.drawImage(img.get(), left, top, {filter, mipmap}, paint);
1006         }), allow_raw_pointers())
1007 
1008         .function("_drawImageNine", optional_override([](SkCanvas& self, const sk_sp<SkImage>& image,
1009                                                          WASMPointerU32 centerPtr, WASMPointerF32 dstPtr,
1010                                                          SkFilterMode filter, const SkPaint* paint)->void {
1011             const SkIRect* center = reinterpret_cast<const SkIRect*>(centerPtr);
1012             const SkRect* dst = reinterpret_cast<const SkRect*>(dstPtr);
1013 
1014             self.drawImageNine(image.get(), *center, *dst, filter, paint);
1015         }), allow_raw_pointers())
1016         // TODO: deprecate this version, and require sampling
1017         .function("_drawImageRect", optional_override([](SkCanvas& self, const sk_sp<SkImage>& image,
1018                                                          WASMPointerF32 srcPtr, WASMPointerF32 dstPtr,
1019                                                          const SkPaint* paint, bool fastSample)->void {
1020             const SkRect* src = reinterpret_cast<const SkRect*>(srcPtr);
1021             const SkRect* dst = reinterpret_cast<const SkRect*>(dstPtr);
1022             self.drawImageRect(image, *src, *dst, SkSamplingOptions(), paint,
1023                                fastSample ? SkCanvas::kFast_SrcRectConstraint:
1024                                             SkCanvas::kStrict_SrcRectConstraint);
1025         }), allow_raw_pointers())
1026         .function("_drawImageRectCubic", optional_override([](SkCanvas& self, const sk_sp<SkImage>& image,
1027                                                               WASMPointerF32 srcPtr, WASMPointerF32 dstPtr,
1028                                                               float B, float C, // See SkSamplingOptions.h for docs.
1029                                                               const SkPaint* paint)->void {
1030             const SkRect* src = reinterpret_cast<const SkRect*>(srcPtr);
1031             const SkRect* dst = reinterpret_cast<const SkRect*>(dstPtr);
1032             auto constraint = SkCanvas::kStrict_SrcRectConstraint;  // TODO: get from caller
1033             self.drawImageRect(image.get(), *src, *dst, SkSamplingOptions({B, C}), paint, constraint);
1034         }), allow_raw_pointers())
1035         .function("_drawImageRectOptions", optional_override([](SkCanvas& self, const sk_sp<SkImage>& image,
1036                                                                 WASMPointerF32 srcPtr, WASMPointerF32 dstPtr,
1037                                                                 SkFilterMode filter, SkMipmapMode mipmap,
1038                                                                 const SkPaint* paint)->void {
1039             const SkRect* src = reinterpret_cast<const SkRect*>(srcPtr);
1040             const SkRect* dst = reinterpret_cast<const SkRect*>(dstPtr);
1041             auto constraint = SkCanvas::kStrict_SrcRectConstraint;  // TODO: get from caller
1042             self.drawImageRect(image.get(), *src, *dst, {filter, mipmap}, paint, constraint);
1043         }), allow_raw_pointers())
1044         .function("_drawLine", select_overload<void (SkScalar, SkScalar, SkScalar, SkScalar, const SkPaint&)>(&SkCanvas::drawLine))
1045         .function("_drawOval", optional_override([](SkCanvas& self, WASMPointerF32 fPtr,
1046                                                     const SkPaint& paint)->void {
1047             const SkRect* oval = reinterpret_cast<const SkRect*>(fPtr);
1048             self.drawOval(*oval, paint);
1049         }))
1050         .function("_drawPaint", &SkCanvas::drawPaint)
1051 #ifdef SK_INCLUDE_PARAGRAPH
1052         .function("_drawParagraph", optional_override([](SkCanvas& self, skia::textlayout::Paragraph* p,
1053                                                         SkScalar x, SkScalar y) {
1054             p->paint(&self, x, y);
1055         }), allow_raw_pointers())
1056 #endif
1057         .function("_drawPath", &SkCanvas::drawPath)
1058         .function("_drawPatch", optional_override([](SkCanvas& self,
1059                                                      WASMPointerF32 cubics,
1060                                                      WASMPointerU32 colors,
1061                                                      WASMPointerF32 texs,
1062                                                      SkBlendMode mode,
1063                                                      const SkPaint& paint)->void {
1064             self.drawPatch(reinterpret_cast<const SkPoint*>(cubics),
1065                            reinterpret_cast<const SkColor*>(colors),
1066                            reinterpret_cast<const SkPoint*>(texs),
1067                            mode, paint);
1068         }))
1069         // Of note, picture is *not* what is colloquially thought of as a "picture", what we call
1070         // a bitmap. An SkPicture is a series of draw commands.
1071         .function("_drawPicture", select_overload<void (const sk_sp<SkPicture>&)>(&SkCanvas::drawPicture))
1072         .function("_drawPoints", optional_override([](SkCanvas& self, SkCanvas::PointMode mode,
1073                                                      WASMPointerF32 pptr,
1074                                                      int count, SkPaint& paint)->void {
1075             const SkPoint* pts = reinterpret_cast<const SkPoint*>(pptr);
1076             self.drawPoints(mode, count, pts, paint);
1077         }))
1078         .function("_drawRRect",optional_override([](SkCanvas& self, WASMPointerF32 fPtr, const SkPaint& paint) {
1079             self.drawRRect(ptrToSkRRect(fPtr), paint);
1080         }))
1081         .function("_drawRect", optional_override([](SkCanvas& self, WASMPointerF32 fPtr,
1082                                                     const SkPaint& paint)->void {
1083             const SkRect* rect = reinterpret_cast<const SkRect*>(fPtr);
1084             self.drawRect(*rect, paint);
1085         }))
1086         .function("_drawRect4f", optional_override([](SkCanvas& self, SkScalar left, SkScalar top,
1087                                                      SkScalar right, SkScalar bottom,
1088                                                      const SkPaint& paint)->void {
1089             const SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
1090             self.drawRect(rect, paint);
1091         }))
1092         .function("_drawShadow", optional_override([](SkCanvas& self, const SkPath& path,
1093                                                      WASMPointerF32 zPlaneParamPtr,
1094                                                      WASMPointerF32 lightPosPtr,
1095                                                      SkScalar lightRadius,
1096                                                      WASMPointerF32 ambientColorPtr,
1097                                                      WASMPointerF32 spotColorPtr,
1098                                                      uint32_t flags) {
1099             const SkVector3* zPlaneParams = reinterpret_cast<const SkVector3*>(zPlaneParamPtr);
1100             const SkVector3* lightPos = reinterpret_cast<const SkVector3*>(lightPosPtr);
1101 
1102             SkShadowUtils::DrawShadow(&self, path, *zPlaneParams, *lightPos, lightRadius,
1103                                       ptrToSkColor4f(ambientColorPtr).toSkColor(),
1104                                       ptrToSkColor4f(spotColorPtr).toSkColor(),
1105                                       flags);
1106         }))
1107 #ifndef SK_NO_FONTS
1108         .function("_drawSimpleText", optional_override([](SkCanvas& self, WASMPointerU8 sptr,
1109                                                           size_t len, SkScalar x, SkScalar y, const SkFont& font,
1110                                                           const SkPaint& paint) {
1111             const char* str = reinterpret_cast<const char*>(sptr);
1112 
1113             self.drawSimpleText(str, len, SkTextEncoding::kUTF8, x, y, font, paint);
1114         }))
1115         .function("_drawTextBlob", select_overload<void (const sk_sp<SkTextBlob>&, SkScalar, SkScalar, const SkPaint&)>(&SkCanvas::drawTextBlob))
1116 #endif
1117         .function("_drawVertices", select_overload<void (const sk_sp<SkVertices>&, SkBlendMode, const SkPaint&)>(&SkCanvas::drawVertices))
1118         .function("_findMarkedCTM", optional_override([](SkCanvas& self, std::string marker, WASMPointerF32 mPtr) -> bool {
1119             SkScalar* sixteenMatrixValues = reinterpret_cast<SkScalar*>(mPtr);
1120             if (!sixteenMatrixValues) {
1121                 return false; // matrix cannot be null
1122             }
1123             SkM44 m;
1124             if (self.findMarkedCTM(marker.c_str(), &m)) {
1125                 m.getRowMajor(sixteenMatrixValues);
1126                 return true;
1127             }
1128             return false;
1129         }))
1130         // 4x4 matrix functions
1131         // Just like with getTotalMatrix, we allocate the buffer for the 16 floats to go in from
1132         // interface.js, so it can also free them when its done.
1133         .function("_getLocalToDevice", optional_override([](const SkCanvas& self, WASMPointerF32 mPtr) {
1134             SkScalar* sixteenMatrixValues = reinterpret_cast<SkScalar*>(mPtr);
1135             if (!sixteenMatrixValues) {
1136                 return; // matrix cannot be null
1137             }
1138             SkM44 m = self.getLocalToDevice();
1139             m.getRowMajor(sixteenMatrixValues);
1140         }))
1141         .function("getSaveCount", &SkCanvas::getSaveCount)
1142         // We allocate room for the matrix from the JS side and free it there so as to not have
1143         // an awkward moment where we malloc something here and "just know" to free it on the
1144         // JS side.
1145         .function("_getTotalMatrix", optional_override([](const SkCanvas& self, WASMPointerU8 mPtr) {
1146             SkScalar* nineMatrixValues = reinterpret_cast<SkScalar*>(mPtr);
1147             if (!nineMatrixValues) {
1148                 return; // matrix cannot be null
1149             }
1150             SkMatrix m = self.getTotalMatrix();
1151             m.get9(nineMatrixValues);
1152         }))
1153         .function("_makeSurface", optional_override([](SkCanvas& self, SimpleImageInfo sii)->sk_sp<SkSurface> {
1154             return self.makeSurface(toSkImageInfo(sii), nullptr);
1155         }), allow_raw_pointers())
1156         .function("markCTM", optional_override([](SkCanvas& self, std::string marker) {
1157             self.markCTM(marker.c_str());
1158         }))
1159 
1160         .function("_readPixels", optional_override([](SkCanvas& self, SimpleImageInfo di,
1161                                                       WASMPointerU8 pPtr,
1162                                                       size_t dstRowBytes, int srcX, int srcY) {
1163             uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
1164             SkImageInfo dstInfo = toSkImageInfo(di);
1165 
1166             return self.readPixels(dstInfo, pixels, dstRowBytes, srcX, srcY);
1167         }))
1168         .function("restore", &SkCanvas::restore)
1169         .function("restoreToCount", &SkCanvas::restoreToCount)
1170         .function("rotate", select_overload<void (SkScalar, SkScalar, SkScalar)>(&SkCanvas::rotate))
1171         .function("save", &SkCanvas::save)
1172         .function("_saveLayer", optional_override([](SkCanvas& self, const SkPaint* p, WASMPointerF32 fPtr,
1173                                                      const SkImageFilter* backdrop, SkCanvas::SaveLayerFlags flags)->int {
1174             SkRect* bounds = reinterpret_cast<SkRect*>(fPtr);
1175             return self.saveLayer(SkCanvas::SaveLayerRec(bounds, p, backdrop, flags));
1176         }), allow_raw_pointers())
1177         .function("saveLayerPaint", optional_override([](SkCanvas& self, const SkPaint p)->int {
1178             return self.saveLayer(SkCanvas::SaveLayerRec(nullptr, &p, 0));
1179         }))
1180         .function("scale", &SkCanvas::scale)
1181         .function("skew", &SkCanvas::skew)
1182         .function("translate", &SkCanvas::translate)
1183         .function("_writePixels", optional_override([](SkCanvas& self, SimpleImageInfo di,
1184                                                        WASMPointerU8 pPtr,
1185                                                        size_t srcRowBytes, int dstX, int dstY) {
1186             uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
1187             SkImageInfo dstInfo = toSkImageInfo(di);
1188 
1189             return self.writePixels(dstInfo, pixels, srcRowBytes, dstX, dstY);
1190         }));
1191 
1192     class_<SkColorFilter>("ColorFilter")
1193         .smart_ptr<sk_sp<SkColorFilter>>("sk_sp<ColorFilter>>")
1194         .class_function("_MakeBlend", optional_override([](WASMPointerF32 cPtr, SkBlendMode mode)->sk_sp<SkColorFilter> {
1195             return SkColorFilters::Blend(ptrToSkColor4f(cPtr).toSkColor(), mode);
1196         }))
1197         .class_function("MakeCompose", &SkColorFilters::Compose)
1198         .class_function("MakeLerp", &SkColorFilters::Lerp)
1199         .class_function("MakeLinearToSRGBGamma", &SkColorFilters::LinearToSRGBGamma)
1200         .class_function("_makeMatrix", optional_override([](WASMPointerF32 fPtr) {
1201             float* twentyFloats = reinterpret_cast<float*>(fPtr);
1202             return SkColorFilters::Matrix(twentyFloats);
1203         }))
1204         .class_function("MakeSRGBToLinearGamma", &SkColorFilters::SRGBToLinearGamma);
1205 
1206     class_<SkContourMeasureIter>("ContourMeasureIter")
1207         .constructor<const SkPath&, bool, SkScalar>()
1208         .function("next", &SkContourMeasureIter::next);
1209 
1210     class_<SkContourMeasure>("ContourMeasure")
1211         .smart_ptr<sk_sp<SkContourMeasure>>("sk_sp<ContourMeasure>>")
1212         .function("_getPosTan", optional_override([](SkContourMeasure& self,
1213                                                      SkScalar distance,
1214                                                      WASMPointerF32 oPtr) -> void {
1215             SkPoint* pointAndVector = reinterpret_cast<SkPoint*>(oPtr);
1216             if (!self.getPosTan(distance, pointAndVector, pointAndVector + 1)) {
1217                 SkDebugf("zero-length path in getPosTan\n");
1218             }
1219         }))
1220         .function("getSegment", optional_override([](SkContourMeasure& self, SkScalar startD,
1221                                                      SkScalar stopD, bool startWithMoveTo) -> SkPath {
1222             SkPath p;
1223             bool ok = self.getSegment(startD, stopD, &p, startWithMoveTo);
1224             if (ok) {
1225                 return p;
1226             }
1227             return SkPath();
1228         }))
1229         .function("isClosed", &SkContourMeasure::isClosed)
1230         .function("length", &SkContourMeasure::length);
1231 
1232 #ifndef SK_NO_FONTS
1233     class_<SkFont>("Font")
1234         .constructor<>()
1235         .constructor<sk_sp<SkTypeface>>()
1236         .constructor<sk_sp<SkTypeface>, SkScalar>()
1237         .constructor<sk_sp<SkTypeface>, SkScalar, SkScalar, SkScalar>()
1238         .function("_getGlyphWidthBounds", optional_override([](SkFont& self, WASMPointerU16 gPtr,
1239                                                           int numGlyphs, WASMPointerF32 wPtr,
1240                                                           WASMPointerF32 rPtr,
1241                                                           SkPaint* paint) {
1242             const SkGlyphID* glyphs = reinterpret_cast<const SkGlyphID*>(gPtr);
1243             // On the JS side only one of these is set at a time for easier ergonomics.
1244             SkRect* outputRects = reinterpret_cast<SkRect*>(rPtr);
1245             SkScalar* outputWidths = reinterpret_cast<SkScalar*>(wPtr);
1246             self.getWidthsBounds(glyphs, numGlyphs, outputWidths, outputRects, paint);
1247         }), allow_raw_pointers())
1248         .function("_getGlyphIDs", optional_override([](SkFont& self, WASMPointerU8 sptr,
1249                                                        size_t strLen, size_t expectedCodePoints,
1250                                                        WASMPointerU16 iPtr) -> int {
1251             char* str = reinterpret_cast<char*>(sptr);
1252             SkGlyphID* glyphIDs = reinterpret_cast<SkGlyphID*>(iPtr);
1253 
1254             int actualCodePoints = self.textToGlyphs(str, strLen, SkTextEncoding::kUTF8,
1255                                                      glyphIDs, expectedCodePoints);
1256             return actualCodePoints;
1257         }))
1258         .function("getMetrics", optional_override([](SkFont& self) -> JSObject {
1259             SkFontMetrics fm;
1260             self.getMetrics(&fm);
1261 
1262             JSObject j = emscripten::val::object();
1263             j.set("ascent",  fm.fAscent);
1264             j.set("descent", fm.fDescent);
1265             j.set("leading", fm.fLeading);
1266             if (!(fm.fFlags & SkFontMetrics::kBoundsInvalid_Flag)) {
1267                 const float rect[] = {
1268                     fm.fXMin, fm.fTop, fm.fXMax, fm.fBottom
1269                 };
1270                 j.set("bounds", MakeTypedArray(4, rect));
1271             }
1272             return j;
1273         }))
1274         .function("_getGlyphIntercepts", optional_override([](SkFont& self,
1275                                                              WASMPointerU16 gPtr, size_t numGlyphs, bool ownGlyphs,
1276                                                              WASMPointerF32 pPtr, size_t numPos, bool ownPos,
1277                                                              float top, float bottom) -> Float32Array {
1278             JSSpan<uint16_t> glyphs(gPtr, numGlyphs, ownGlyphs);
1279             JSSpan<float>    pos   (pPtr, numPos, ownPos);
1280             if (glyphs.size() > (pos.size() >> 1)) {
1281                 return emscripten::val("Not enough x,y position pairs for glyphs");
1282             }
1283             auto sects  = self.getIntercepts(glyphs.data(), SkToInt(glyphs.size()),
1284                                              (const SkPoint*)pos.data(), top, bottom);
1285             return MakeTypedArray(sects.size(), (const float*)sects.data());
1286         }), allow_raw_pointers())
1287         .function("getScaleX", &SkFont::getScaleX)
1288         .function("getSize", &SkFont::getSize)
1289         .function("getSkewX", &SkFont::getSkewX)
1290         .function("isEmbolden", &SkFont::isEmbolden)
1291         .function("getTypeface", &SkFont::getTypeface, allow_raw_pointers())
1292         .function("setEdging", &SkFont::setEdging)
1293         .function("setEmbeddedBitmaps", &SkFont::setEmbeddedBitmaps)
1294         .function("setHinting", &SkFont::setHinting)
1295         .function("setLinearMetrics", &SkFont::setLinearMetrics)
1296         .function("setScaleX", &SkFont::setScaleX)
1297         .function("setSize", &SkFont::setSize)
1298         .function("setSkewX", &SkFont::setSkewX)
1299         .function("setEmbolden", &SkFont::setEmbolden)
1300         .function("setSubpixel", &SkFont::setSubpixel)
1301         .function("setTypeface", &SkFont::setTypeface, allow_raw_pointers());
1302 
1303     class_<SkFontMgr>("FontMgr")
1304         .smart_ptr<sk_sp<SkFontMgr>>("sk_sp<FontMgr>")
1305         .class_function("_fromData", optional_override([](WASMPointerU32 dPtr,
1306                                                           WASMPointerU32 sPtr,
1307                                                           int numFonts)->sk_sp<SkFontMgr> {
1308             auto datas = reinterpret_cast<const uint8_t**>(dPtr);
1309             auto sizes = reinterpret_cast<const size_t*>(sPtr);
1310 
1311             std::unique_ptr<sk_sp<SkData>[]> skdatas(new sk_sp<SkData>[numFonts]);
1312             for (int i = 0; i < numFonts; ++i) {
1313                 skdatas[i] = SkData::MakeFromMalloc(datas[i], sizes[i]);
1314             }
1315 
1316             return SkFontMgr_New_Custom_Data(skdatas.get(), numFonts);
1317         }), allow_raw_pointers())
1318         .function("countFamilies", &SkFontMgr::countFamilies)
1319         .function("getFamilyName", optional_override([](SkFontMgr& self, int index)->JSString {
1320             if (index < 0 || index >= self.countFamilies()) {
1321                 return emscripten::val::null();
1322             }
1323             SkString s;
1324             self.getFamilyName(index, &s);
1325             return emscripten::val(s.c_str());
1326         }))
1327 #ifdef SK_DEBUG
1328         .function("dumpFamilies", optional_override([](SkFontMgr& self) {
1329             int numFam = self.countFamilies();
1330             SkDebugf("There are %d font families\n", numFam);
1331             for (int i = 0 ; i< numFam; i++) {
1332                 SkString s;
1333                 self.getFamilyName(i, &s);
1334                 SkDebugf("\t%s\n", s.c_str());
1335             }
1336         }))
1337 #endif
1338         .function("_makeTypefaceFromData", optional_override([](SkFontMgr& self,
1339                                                 WASMPointerU8 fPtr,
1340                                                 int flen)->sk_sp<SkTypeface> {
1341         uint8_t* font = reinterpret_cast<uint8_t*>(fPtr);
1342         sk_sp<SkData> fontData = SkData::MakeFromMalloc(font, flen);
1343 
1344         return self.makeFromData(fontData);
1345     }), allow_raw_pointers());
1346 #endif // SK_NO_FONTS
1347 
1348     class_<SkImage>("Image")
1349         .smart_ptr<sk_sp<SkImage>>("sk_sp<Image>")
1350 #if SK_GL
1351         .class_function("_makeFromGenerator", &MakeImageFromGenerator)
1352 #endif
1353         // Note that this needs to be cleaned up with delete().
1354         .function("getColorSpace", optional_override([](sk_sp<SkImage> self)->sk_sp<SkColorSpace> {
1355             return self->imageInfo().refColorSpace();
1356         }), allow_raw_pointers())
1357         .function("getImageInfo", optional_override([](sk_sp<SkImage> self)->JSObject {
1358             // We cannot return a SimpleImageInfo because the colorspace object would be leaked.
1359             JSObject result = emscripten::val::object();
1360             SkImageInfo ii = self->imageInfo();
1361             result.set("alphaType", ii.alphaType());
1362             result.set("colorType", ii.colorType());
1363             result.set("height", ii.height());
1364             result.set("width", ii.width());
1365             return result;
1366         }))
1367         .function("height", &SkImage::height)
1368         .function("encodeToBytes", optional_override([](sk_sp<SkImage> self) -> Uint8Array {
1369             sk_sp<SkData> data = self->encodeToData();
1370             if (!data) {
1371                 return emscripten::val::null();
1372             }
1373             return toBytes(data);
1374         }))
1375        .function("encodeToBytes", optional_override([](sk_sp<SkImage> self,
1376                                             SkEncodedImageFormat fmt, int quality) -> Uint8Array {
1377             sk_sp<SkData> data = self->encodeToData(fmt, quality);
1378             if (!data) {
1379                 return emscripten::val::null();
1380             }
1381             return toBytes(data);
1382         }))
1383         .function("makeCopyWithDefaultMipmaps", optional_override([](sk_sp<SkImage> self)->sk_sp<SkImage> {
1384             return self->withDefaultMipmaps();
1385         }))
1386         .function("_makeShaderCubic", optional_override([](sk_sp<SkImage> self,
1387                                  SkTileMode tx, SkTileMode ty,
1388                                  float B, float C, // See SkSamplingOptions.h for docs.
1389                                  WASMPointerF32 mPtr)->sk_sp<SkShader> {
1390             return self->makeShader(tx, ty, SkSamplingOptions({B, C}), OptionalMatrix(mPtr));
1391         }), allow_raw_pointers())
1392         .function("_makeShaderOptions", optional_override([](sk_sp<SkImage> self,
1393                                  SkTileMode tx, SkTileMode ty,
1394                                  SkFilterMode filter, SkMipmapMode mipmap,
1395                                  WASMPointerF32 mPtr)->sk_sp<SkShader> {
1396             return self->makeShader(tx, ty, {filter, mipmap}, OptionalMatrix(mPtr));
1397         }), allow_raw_pointers())
1398         .function("_readPixels", optional_override([](sk_sp<SkImage> self,
1399                                  SimpleImageInfo sii, WASMPointerU8 pPtr,
1400                                  size_t dstRowBytes, int srcX, int srcY)->bool {
1401             uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
1402             SkImageInfo ii = toSkImageInfo(sii);
1403             // TODO(adlai) Migrate CanvasKit API to require DirectContext arg here.
1404             GrDirectContext* dContext = nullptr;
1405 #ifdef SK_GL
1406             dContext = GrAsDirectContext(as_IB(self.get())->context());
1407 #endif
1408             return self->readPixels(dContext, ii, pixels, dstRowBytes, srcX, srcY);
1409         }), allow_raw_pointers())
1410         .function("width", &SkImage::width);
1411 
1412     class_<SkImageFilter>("ImageFilter")
1413         .smart_ptr<sk_sp<SkImageFilter>>("sk_sp<ImageFilter>")
1414         .class_function("MakeBlur", optional_override([](SkScalar sigmaX, SkScalar sigmaY,
1415                                                          SkTileMode tileMode, sk_sp<SkImageFilter> input)->sk_sp<SkImageFilter> {
1416             return SkImageFilters::Blur(sigmaX, sigmaY, tileMode, input);
1417         }))
1418         .class_function("MakeColorFilter", optional_override([](sk_sp<SkColorFilter> cf,
1419                                                                 sk_sp<SkImageFilter> input)->sk_sp<SkImageFilter> {
1420             return SkImageFilters::ColorFilter(cf, input);
1421         }))
1422         .class_function("MakeCompose", &SkImageFilters::Compose)
1423         .class_function("_MakeMatrixTransformCubic",
1424                         optional_override([](WASMPointerF32 mPtr, float B, float C,
1425                                              sk_sp<SkImageFilter> input)->sk_sp<SkImageFilter> {
1426             OptionalMatrix matr(mPtr);
1427             return SkImageFilters::MatrixTransform(matr, SkSamplingOptions({B, C}), input);
1428         }))
1429         .class_function("_MakeMatrixTransformOptions",
1430                         optional_override([](WASMPointerF32 mPtr, SkFilterMode fm, SkMipmapMode mm,
1431                                              sk_sp<SkImageFilter> input)->sk_sp<SkImageFilter> {
1432             OptionalMatrix matr(mPtr);
1433             return SkImageFilters::MatrixTransform(matr, SkSamplingOptions(fm, mm), input);
1434         }));
1435 
1436     class_<SkMaskFilter>("MaskFilter")
1437         .smart_ptr<sk_sp<SkMaskFilter>>("sk_sp<MaskFilter>")
1438         .class_function("MakeBlur", optional_override([](SkBlurStyle style, SkScalar sigma, bool respectCTM)->sk_sp<SkMaskFilter> {
1439         // Adds a little helper because emscripten doesn't expose default params.
1440         return SkMaskFilter::MakeBlur(style, sigma, respectCTM);
1441     }), allow_raw_pointers());
1442 
1443     class_<SkPaint>("Paint")
1444         .constructor<>()
1445         .function("copy", optional_override([](const SkPaint& self)->SkPaint {
1446             SkPaint p(self);
1447             return p;
1448         }))
1449         // provide an allocated place to put the returned color
1450         .function("_getColor", optional_override([](SkPaint& self, WASMPointerF32 cPtr)->void {
1451             const SkColor4f& c = self.getColor4f();
1452             float* fourFloats = reinterpret_cast<float*>(cPtr);
1453             memcpy(fourFloats, c.vec(), 4 * sizeof(SkScalar));
1454         }))
1455         .function("getStrokeCap", &SkPaint::getStrokeCap)
1456         .function("getStrokeJoin", &SkPaint::getStrokeJoin)
1457         .function("getStrokeMiter", &SkPaint::getStrokeMiter)
1458         .function("getStrokeWidth", &SkPaint::getStrokeWidth)
1459         .function("setAntiAlias", &SkPaint::setAntiAlias)
1460         .function("setAlphaf", &SkPaint::setAlphaf)
1461         .function("setBlendMode", &SkPaint::setBlendMode)
1462         .function("_setColor", optional_override([](SkPaint& self, WASMPointerF32 cPtr,
1463                 sk_sp<SkColorSpace> colorSpace) {
1464             self.setColor(ptrToSkColor4f(cPtr), colorSpace.get());
1465         }))
1466         .function("setColorInt", optional_override([](SkPaint& self, SkColor color) {
1467             self.setColor(SkColor4f::FromColor(color), nullptr);
1468         }))
1469         .function("setColorInt", optional_override([](SkPaint& self, SkColor color,
1470                 sk_sp<SkColorSpace> colorSpace) {
1471             self.setColor(SkColor4f::FromColor(color), colorSpace.get());
1472         }))
1473         .function("setColorFilter", &SkPaint::setColorFilter)
1474         .function("setImageFilter", &SkPaint::setImageFilter)
1475         .function("setMaskFilter", &SkPaint::setMaskFilter)
1476         .function("setPathEffect", &SkPaint::setPathEffect)
1477         .function("setShader", &SkPaint::setShader)
1478         .function("setStrokeCap", &SkPaint::setStrokeCap)
1479         .function("setStrokeJoin", &SkPaint::setStrokeJoin)
1480         .function("setStrokeMiter", &SkPaint::setStrokeMiter)
1481         .function("setStrokeWidth", &SkPaint::setStrokeWidth)
1482         .function("setStyle", &SkPaint::setStyle);
1483 
1484     class_<SkColorSpace>("ColorSpace")
1485         .smart_ptr<sk_sp<SkColorSpace>>("sk_sp<ColorSpace>")
1486         .class_function("Equals", optional_override([](sk_sp<SkColorSpace> a, sk_sp<SkColorSpace> b)->bool {
1487             return SkColorSpace::Equals(a.get(), b.get());
1488         }))
1489         // These are private because they are to be called once in interface.js to
1490         // avoid clients having to delete the returned objects.
1491         .class_function("_MakeSRGB", &SkColorSpace::MakeSRGB)
1492         .class_function("_MakeDisplayP3", optional_override([]()->sk_sp<SkColorSpace> {
1493             return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3);
1494         }))
1495         .class_function("_MakeAdobeRGB", optional_override([]()->sk_sp<SkColorSpace> {
1496             return SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB);
1497         }));
1498 
1499     class_<SkPathEffect>("PathEffect")
1500         .smart_ptr<sk_sp<SkPathEffect>>("sk_sp<PathEffect>")
1501         .class_function("MakeCorner", &SkCornerPathEffect::Make)
1502         .class_function("_MakeDash", optional_override([](WASMPointerF32 cptr, int count,
1503                                                           SkScalar phase)->sk_sp<SkPathEffect> {
1504             const float* intervals = reinterpret_cast<const float*>(cptr);
1505             return SkDashPathEffect::Make(intervals, count, phase);
1506         }), allow_raw_pointers())
1507         .class_function("MakeDiscrete", &SkDiscretePathEffect::Make);
1508 
1509     // TODO(kjlubick, reed) Make SkPath immutable and only creatable via a factory/builder.
1510     class_<SkPath>("Path")
1511         .constructor<>()
1512 #ifdef SK_INCLUDE_PATHOPS
1513         .class_function("MakeFromOp", &MakePathFromOp)
1514 #endif
1515         .class_function("MakeFromSVGString", &MakePathFromSVGString)
1516         .class_function("_MakeFromCmds", &MakePathFromCmds)
1517         .class_function("_MakeFromVerbsPointsWeights", &MakePathFromVerbsPointsWeights)
1518         .function("_addArc", optional_override([](SkPath& self,
1519                                                    WASMPointerF32 fPtr,
1520                                                    SkScalar startAngle, SkScalar sweepAngle)->void {
1521             const SkRect* oval = reinterpret_cast<const SkRect*>(fPtr);
1522             self.addArc(*oval, startAngle, sweepAngle);
1523         }))
1524         .function("_addOval", optional_override([](SkPath& self,
1525                                                    WASMPointerF32 fPtr,
1526                                                    bool ccw, unsigned start)->void {
1527             const SkRect* oval = reinterpret_cast<const SkRect*>(fPtr);
1528             self.addOval(*oval, ccw ? SkPathDirection::kCCW : SkPathDirection::kCW, start);
1529         }))
1530         // interface.js has 3 overloads of addPath
1531         .function("_addPath", &ApplyAddPath)
1532         .function("_addPoly", optional_override([](SkPath& self,
1533                                                    WASMPointerF32 fPtr,
1534                                                    int count, bool close)->void {
1535             const SkPoint* pts = reinterpret_cast<const SkPoint*>(fPtr);
1536             self.addPoly(pts, count, close);
1537         }))
1538         .function("_addRect", optional_override([](SkPath& self,
1539                                                    WASMPointerF32 fPtr,
1540                                                    bool ccw)->void {
1541             const SkRect* rect = reinterpret_cast<const SkRect*>(fPtr);
1542             self.addRect(*rect, ccw ? SkPathDirection::kCCW : SkPathDirection::kCW);
1543         }))
1544         .function("_addRRect", optional_override([](SkPath& self,
1545                                                    WASMPointerF32 fPtr,
1546                                                    bool ccw)->void {
1547             self.addRRect(ptrToSkRRect(fPtr), ccw ? SkPathDirection::kCCW : SkPathDirection::kCW);
1548         }))
1549         .function("_addVerbsPointsWeights", &PathAddVerbsPointsWeights)
1550         .function("_arcToOval", optional_override([](SkPath& self,
1551                                                    WASMPointerF32 fPtr, SkScalar startAngle,
1552                                                    SkScalar sweepAngle, bool forceMoveTo)->void {
1553             const SkRect* oval = reinterpret_cast<const SkRect*>(fPtr);
1554             self.arcTo(*oval, startAngle, sweepAngle, forceMoveTo);
1555         }))
1556         .function("_arcToRotated", &ApplyArcToArcSize)
1557         .function("_arcToTangent", ApplyArcToTangent)
1558         .function("_close", &ApplyClose)
1559         .function("_conicTo", &ApplyConicTo)
1560         .function("countPoints", &SkPath::countPoints)
1561         .function("contains", &SkPath::contains)
1562         .function("_cubicTo", &ApplyCubicTo)
1563         .function("_getPoint", optional_override([](SkPath& self, int index,
1564                                                     WASMPointerF32 oPtr)->void {
1565             SkPoint* output = reinterpret_cast<SkPoint*>(oPtr);
1566             *output = self.getPoint(index);
1567         }))
1568         .function("isEmpty",  &SkPath::isEmpty)
1569         .function("isVolatile", &SkPath::isVolatile)
1570         .function("_lineTo", &ApplyLineTo)
1571         .function("_moveTo", &ApplyMoveTo)
1572         .function("_quadTo", &ApplyQuadTo)
1573         .function("_rArcTo", &ApplyRArcToArcSize)
1574         .function("_rConicTo", &ApplyRConicTo)
1575         .function("_rCubicTo", &ApplyRCubicTo)
1576         .function("_rLineTo", &ApplyRLineTo)
1577         .function("_rMoveTo", &ApplyRMoveTo)
1578         .function("_rQuadTo", &ApplyRQuadTo)
1579         .function("reset", &ApplyReset)
1580         .function("rewind", &ApplyRewind)
1581         .function("setIsVolatile", &SkPath::setIsVolatile)
1582         .function("_transform", select_overload<void(SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&ApplyTransform))
1583 
1584         // PathEffects
1585         .function("_dash", &ApplyDash)
1586         .function("_trim", &ApplyTrim)
1587         .function("_stroke", &ApplyStroke)
1588 
1589 #ifdef SK_INCLUDE_PATHOPS
1590         // PathOps
1591         .function("_simplify", &ApplySimplify)
1592         .function("_op", &ApplyPathOp)
1593         .function("makeAsWinding", &MakeAsWinding)
1594 #endif
1595         // Exporting
1596         .function("toSVGString", &ToSVGString)
1597         .function("toCmds", &ToCmds)
1598 
1599         .function("setFillType", select_overload<void(SkPathFillType)>(&SkPath::setFillType))
1600         .function("getFillType", &SkPath::getFillType)
1601         .function("_getBounds", optional_override([](SkPath& self,
1602                                                      WASMPointerF32 fPtr)->void {
1603             SkRect* output = reinterpret_cast<SkRect*>(fPtr);
1604             output[0] = self.getBounds();
1605         }))
1606         .function("_computeTightBounds", optional_override([](SkPath& self,
1607                                                               WASMPointerF32 fPtr)->void {
1608             SkRect* output = reinterpret_cast<SkRect*>(fPtr);
1609             output[0] = self.computeTightBounds();
1610         }))
1611         .function("equals", &Equals)
1612         .function("copy", &CopyPath)
1613 #ifdef SK_DEBUG
1614         .function("dump", select_overload<void() const>(&SkPath::dump))
1615         .function("dumpHex", select_overload<void() const>(&SkPath::dumpHex))
1616 #endif
1617         ;
1618 
1619     class_<SkPictureRecorder>("PictureRecorder")
1620         .constructor<>()
1621         .function("_beginRecording", optional_override([](SkPictureRecorder& self,
1622                                                           WASMPointerF32 fPtr) -> SkCanvas* {
1623             SkRect* bounds = reinterpret_cast<SkRect*>(fPtr);
1624             return self.beginRecording(*bounds, nullptr);
1625         }), allow_raw_pointers())
1626         .function("finishRecordingAsPicture", optional_override([](SkPictureRecorder& self)
1627                                                                    -> sk_sp<SkPicture> {
1628             return self.finishRecordingAsPicture();
1629         }), allow_raw_pointers());
1630 
1631     class_<SkPicture>("Picture")
1632         .smart_ptr<sk_sp<SkPicture>>("sk_sp<Picture>")
1633 #ifdef SK_SERIALIZE_SKP
1634         // The serialized format of an SkPicture (informally called an "skp"), is not something
1635         // that clients should ever rely on.  The format may change at anytime and no promises
1636         // are made for backwards or forward compatibility.
1637         .function("serialize", optional_override([](SkPicture& self) -> Uint8Array {
1638             // Emscripten doesn't play well with optional arguments, which we don't
1639             // want to expose anyway.
1640             sk_sp<SkData> data = self.serialize();
1641             if (!data) {
1642                 return emscripten::val::null();
1643             }
1644             return toBytes(data);
1645         }), allow_raw_pointers())
1646 #endif
1647     ;
1648 
1649     class_<SkShader>("Shader")
1650         .smart_ptr<sk_sp<SkShader>>("sk_sp<Shader>")
1651         .class_function("MakeBlend", select_overload<sk_sp<SkShader>(SkBlendMode, sk_sp<SkShader>, sk_sp<SkShader>)>(&SkShaders::Blend))
1652         .class_function("_MakeColor",
1653             optional_override([](WASMPointerF32 cPtr, sk_sp<SkColorSpace> colorSpace)->sk_sp<SkShader> {
1654                 return SkShaders::Color(ptrToSkColor4f(cPtr), colorSpace);
1655             })
1656         )
1657         .class_function("MakeFractalNoise", optional_override([](
1658                                                 SkScalar baseFreqX, SkScalar baseFreqY,
1659                                                 int numOctaves, SkScalar seed,
1660                                                 int tileW, int tileH)->sk_sp<SkShader> {
1661             // if tileSize is empty (e.g. tileW <= 0 or tileH <= 0, it will be ignored.
1662             SkISize tileSize = SkISize::Make(tileW, tileH);
1663             return SkPerlinNoiseShader::MakeFractalNoise(baseFreqX, baseFreqY,
1664                                                          numOctaves, seed, &tileSize);
1665         }))
1666          // Here and in other gradient functions, cPtr is a pointer to an array of data
1667          // representing colors. whether this is an array of SkColor or SkColor4f is indicated
1668          // by the colorType argument. Only RGBA_8888 and RGBA_F32 are accepted.
1669         .class_function("_MakeLinearGradient", optional_override([](
1670                                          WASMPointerF32 fourFloatsPtr,
1671                                          WASMPointerF32 cPtr, SkColorType colorType,
1672                                          WASMPointerF32 pPtr,
1673                                          int count, SkTileMode mode, uint32_t flags,
1674                                          WASMPointerF32 mPtr,
1675                                          sk_sp<SkColorSpace> colorSpace)->sk_sp<SkShader> {
1676              const SkPoint* points = reinterpret_cast<const SkPoint*>(fourFloatsPtr);
1677              const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
1678              OptionalMatrix localMatrix(mPtr);
1679 
1680              if (colorType == SkColorType::kRGBA_F32_SkColorType) {
1681                  const SkColor4f* colors  = reinterpret_cast<const SkColor4f*>(cPtr);
1682                  return SkGradientShader::MakeLinear(points, colors, colorSpace, positions, count,
1683                                                      mode, flags, &localMatrix);
1684              } else if (colorType == SkColorType::kRGBA_8888_SkColorType) {
1685                  const SkColor* colors  = reinterpret_cast<const SkColor*>(cPtr);
1686                  return SkGradientShader::MakeLinear(points, colors, positions, count,
1687                                                      mode, flags, &localMatrix);
1688              }
1689              SkDebugf("%d is not an accepted colorType\n", colorType);
1690              return nullptr;
1691          }), allow_raw_pointers())
1692         .class_function("_MakeRadialGradient", optional_override([](
1693                                          SkScalar cx, SkScalar cy, SkScalar radius,
1694                                          WASMPointerF32 cPtr, SkColorType colorType,
1695                                          WASMPointerF32 pPtr,
1696                                          int count, SkTileMode mode, uint32_t flags,
1697                                          WASMPointerF32 mPtr,
1698                                          sk_sp<SkColorSpace> colorSpace)->sk_sp<SkShader> {
1699             const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
1700             OptionalMatrix localMatrix(mPtr);
1701             if (colorType == SkColorType::kRGBA_F32_SkColorType) {
1702                const SkColor4f* colors  = reinterpret_cast<const SkColor4f*>(cPtr);
1703                return SkGradientShader::MakeRadial({cx, cy}, radius, colors, colorSpace,
1704                                                    positions, count, mode, flags, &localMatrix);
1705             } else if (colorType == SkColorType::kRGBA_8888_SkColorType) {
1706                const SkColor* colors  = reinterpret_cast<const SkColor*>(cPtr);
1707                return SkGradientShader::MakeRadial({cx, cy}, radius, colors, positions,
1708                                                    count, mode, flags, &localMatrix);
1709             }
1710             SkDebugf("%d is not an accepted colorType\n", colorType);
1711             return nullptr;
1712         }), allow_raw_pointers())
1713         .class_function("_MakeSweepGradient", optional_override([](SkScalar cx, SkScalar cy,
1714                                          WASMPointerF32 cPtr, SkColorType colorType,
1715                                          WASMPointerF32 pPtr,
1716                                          int count, SkTileMode mode,
1717                                          SkScalar startAngle, SkScalar endAngle,
1718                                          uint32_t flags,
1719                                          WASMPointerF32 mPtr,
1720                                          sk_sp<SkColorSpace> colorSpace)->sk_sp<SkShader> {
1721             const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
1722             OptionalMatrix localMatrix(mPtr);
1723             if (colorType == SkColorType::kRGBA_F32_SkColorType) {
1724                const SkColor4f* colors  = reinterpret_cast<const SkColor4f*>(cPtr);
1725                return SkGradientShader::MakeSweep(cx, cy, colors, colorSpace, positions, count,
1726                                                   mode, startAngle, endAngle, flags,
1727                                                   &localMatrix);
1728             } else if (colorType == SkColorType::kRGBA_8888_SkColorType) {
1729                const SkColor* colors  = reinterpret_cast<const SkColor*>(cPtr);
1730                return SkGradientShader::MakeSweep(cx, cy, colors, positions, count,
1731                                                   mode, startAngle, endAngle, flags,
1732                                                   &localMatrix);
1733             }
1734             SkDebugf("%d is not an accepted colorType\n", colorType);
1735             return nullptr;
1736         }), allow_raw_pointers())
1737         .class_function("MakeTurbulence", optional_override([](
1738                                                 SkScalar baseFreqX, SkScalar baseFreqY,
1739                                                 int numOctaves, SkScalar seed,
1740                                                 int tileW, int tileH)->sk_sp<SkShader> {
1741             // if tileSize is empty (e.g. tileW <= 0 or tileH <= 0, it will be ignored.
1742             SkISize tileSize = SkISize::Make(tileW, tileH);
1743             return SkPerlinNoiseShader::MakeTurbulence(baseFreqX, baseFreqY,
1744                                                        numOctaves, seed, &tileSize);
1745         }))
1746         .class_function("_MakeTwoPointConicalGradient", optional_override([](
1747                                          WASMPointerF32 fourFloatsPtr,
1748                                          SkScalar startRadius, SkScalar endRadius,
1749                                          WASMPointerF32 cPtr, SkColorType colorType,
1750                                          WASMPointerF32 pPtr,
1751                                          int count, SkTileMode mode, uint32_t flags,
1752                                          WASMPointerF32 mPtr,
1753                                          sk_sp<SkColorSpace> colorSpace)->sk_sp<SkShader> {
1754             const SkPoint* startAndEnd = reinterpret_cast<const SkPoint*>(fourFloatsPtr);
1755             const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
1756             OptionalMatrix localMatrix(mPtr);
1757 
1758             if (colorType == SkColorType::kRGBA_F32_SkColorType) {
1759                const SkColor4f* colors  = reinterpret_cast<const SkColor4f*>(cPtr);
1760                return SkGradientShader::MakeTwoPointConical(startAndEnd[0], startRadius,
1761                                                             startAndEnd[1], endRadius,
1762                                                             colors, colorSpace, positions, count, mode,
1763                                                             flags, &localMatrix);
1764             } else if (colorType == SkColorType::kRGBA_8888_SkColorType) {
1765                const SkColor* colors  = reinterpret_cast<const SkColor*>(cPtr);
1766                return SkGradientShader::MakeTwoPointConical(startAndEnd[0], startRadius,
1767                                                             startAndEnd[1], endRadius,
1768                                                             colors, positions, count, mode,
1769                                                             flags, &localMatrix);
1770             }
1771             SkDebugf("%d is not an accepted colorType\n", colorType);
1772             return nullptr;
1773         }), allow_raw_pointers());
1774 
1775 #ifdef SK_INCLUDE_RUNTIME_EFFECT
1776     class_<SkRuntimeEffect>("RuntimeEffect")
1777         .smart_ptr<sk_sp<SkRuntimeEffect>>("sk_sp<RuntimeEffect>")
1778         .class_function("_Make", optional_override([](std::string sksl,
1779                                                      emscripten::val errHandler
1780                                                     )->sk_sp<SkRuntimeEffect> {
1781             SkString s(sksl.c_str(), sksl.length());
1782             auto [effect, errorText] = SkRuntimeEffect::MakeForShader(s);
1783             if (!effect) {
1784                 errHandler.call<void>("onError", val(errorText.c_str()));
1785                 return nullptr;
1786             }
1787             return effect;
1788         }))
1789         .function("_makeShader", optional_override([](SkRuntimeEffect& self, WASMPointerF32 fPtr, size_t fLen, bool isOpaque,
1790                                                       WASMPointerF32 mPtr)->sk_sp<SkShader> {
1791             void* inputData = reinterpret_cast<void*>(fPtr);
1792             castUniforms(inputData, fLen, self);
1793             sk_sp<SkData> inputs = SkData::MakeFromMalloc(inputData, fLen);
1794 
1795             OptionalMatrix localMatrix(mPtr);
1796             return self.makeShader(inputs, nullptr, 0, &localMatrix, isOpaque);
1797         }))
1798         .function("_makeShaderWithChildren", optional_override([](SkRuntimeEffect& self, WASMPointerF32 fPtr, size_t fLen, bool isOpaque,
1799                                                                   WASMPointerU32 cPtrs, size_t cLen,
1800                                                                   WASMPointerF32 mPtr)->sk_sp<SkShader> {
1801             void* inputData = reinterpret_cast<void*>(fPtr);
1802             castUniforms(inputData, fLen, self);
1803             sk_sp<SkData> inputs = SkData::MakeFromMalloc(inputData, fLen);
1804 
1805             sk_sp<SkShader>* children = new sk_sp<SkShader>[cLen];
1806             SkShader** childrenPtrs = reinterpret_cast<SkShader**>(cPtrs);
1807             for (size_t i = 0; i < cLen; i++) {
1808                 // This bare pointer was already part of an sk_sp (owned outside of here),
1809                 // so we want to ref the new sk_sp so makeShader doesn't clean it up.
1810                 children[i] = sk_ref_sp<SkShader>(childrenPtrs[i]);
1811             }
1812             OptionalMatrix localMatrix(mPtr);
1813             auto s = self.makeShader(inputs, children, cLen, &localMatrix, isOpaque);
1814             delete[] children;
1815             return s;
1816         }))
1817         .function("getUniformCount", optional_override([](SkRuntimeEffect& self)->int {
1818             return self.uniforms().size();
1819         }))
1820         .function("getUniformFloatCount", optional_override([](SkRuntimeEffect& self)->int {
1821             return self.uniformSize() / sizeof(float);
1822         }))
1823         .function("getUniformName", optional_override([](SkRuntimeEffect& self, int i)->JSString {
1824             auto it = self.uniforms().begin() + i;
1825             return emscripten::val(it->name.c_str());
1826         }))
1827         .function("getUniform", optional_override([](SkRuntimeEffect& self, int i)->RuntimeEffectUniform {
1828             auto it = self.uniforms().begin() + i;
1829             RuntimeEffectUniform su = fromUniform(*it);
1830             return su;
1831         }));
1832 
1833     value_object<RuntimeEffectUniform>("RuntimeEffectUniform")
1834         .field("columns",   &RuntimeEffectUniform::columns)
1835         .field("rows",      &RuntimeEffectUniform::rows)
1836         .field("slot",      &RuntimeEffectUniform::slot)
1837         .field("isInteger", &RuntimeEffectUniform::isInteger);
1838 
1839     constant("rt_effect", true);
1840 #endif
1841 
1842     class_<SkSurface>("Surface")
1843         .smart_ptr<sk_sp<SkSurface>>("sk_sp<Surface>")
1844         .class_function("_makeRasterDirect", optional_override([](const SimpleImageInfo ii,
1845                                                                   WASMPointerU8 pPtr,
1846                                                                   size_t rowBytes)->sk_sp<SkSurface> {
1847             uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
1848             SkImageInfo imageInfo = toSkImageInfo(ii);
1849             return SkSurface::MakeRasterDirect(imageInfo, pixels, rowBytes, nullptr);
1850         }), allow_raw_pointers())
1851         .function("_flush", optional_override([](SkSurface& self) {
1852             self.flushAndSubmit(false);
1853         }))
1854         .function("_getCanvas", &SkSurface::getCanvas, allow_raw_pointers())
1855         .function("imageInfo", optional_override([](SkSurface& self)->SimpleImageInfo {
1856             const auto& ii = self.imageInfo();
1857             return {ii.width(), ii.height(), ii.colorType(), ii.alphaType(), ii.refColorSpace()};
1858         }))
1859         .function("height", &SkSurface::height)
1860 #ifdef SK_GL
1861         .function("_makeImageFromTexture", optional_override([](SkSurface& self,
1862                                                 uint32_t webglHandle, uint32_t texHandle,
1863                                                 SimpleImageInfo ii)->sk_sp<SkImage> {
1864             auto releaseCtx = new TextureReleaseContext{webglHandle, texHandle};
1865             GrGLTextureInfo gti = {GR_GL_TEXTURE_2D, texHandle,
1866                                    GR_GL_RGBA8}; // TODO(kjlubick) look at ii for this
1867             GrBackendTexture gbt(ii.width, ii.height, GrMipmapped::kNo, gti);
1868             auto dContext = GrAsDirectContext(self.getCanvas()->recordingContext());
1869 
1870             return SkImage::MakeFromTexture(
1871                              dContext,
1872                              gbt,
1873                              GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
1874                              ii.colorType,
1875                              ii.alphaType,
1876                              ii.colorSpace,
1877                              deleteJSTexture,
1878                              releaseCtx);
1879          }))
1880  #endif
1881         .function("_makeImageSnapshot",  optional_override([](SkSurface& self, WASMPointerU32 iPtr)->sk_sp<SkImage> {
1882             SkIRect* bounds = reinterpret_cast<SkIRect*>(iPtr);
1883             if (!bounds) {
1884                 return self.makeImageSnapshot();
1885             }
1886             return self.makeImageSnapshot(*bounds);
1887         }))
1888         .function("_makeSurface", optional_override([](SkSurface& self, SimpleImageInfo sii)->sk_sp<SkSurface> {
1889             return self.makeSurface(toSkImageInfo(sii));
1890         }), allow_raw_pointers())
1891 #ifdef SK_GL
1892         .function("reportBackendTypeIsGPU", optional_override([](SkSurface& self) -> bool {
1893             return self.getCanvas()->recordingContext() != nullptr;
1894         }))
1895         .function("sampleCnt", optional_override([](SkSurface& self)->int {
1896             auto backendRT = self.getBackendRenderTarget(SkSurface::kFlushRead_BackendHandleAccess);
1897             return (backendRT.isValid()) ? backendRT.sampleCnt() : 0;
1898         }))
1899 #else
1900         .function("reportBackendTypeIsGPU", optional_override([](SkSurface& self) -> bool {
1901             return false;
1902         }))
1903 #endif
1904         .function("width", &SkSurface::width);
1905 
1906 #ifndef SK_NO_FONTS
1907     class_<SkTextBlob>("TextBlob")
1908         .smart_ptr<sk_sp<SkTextBlob>>("sk_sp<TextBlob>")
1909         .class_function("_MakeFromRSXform", optional_override([](WASMPointerU8 sptr,
1910                                                               size_t strBtyes,
1911                                                               WASMPointerF32 xptr,
1912                                                               const SkFont& font)->sk_sp<SkTextBlob> {
1913             const char* str = reinterpret_cast<const char*>(sptr);
1914             const SkRSXform* xforms = reinterpret_cast<const SkRSXform*>(xptr);
1915 
1916             return SkTextBlob::MakeFromRSXform(str, strBtyes, xforms, font, SkTextEncoding::kUTF8);
1917         }), allow_raw_pointers())
1918         .class_function("_MakeFromRSXformGlyphs", optional_override([](WASMPointerU16 gPtr,
1919                                                               size_t byteLen,
1920                                                               WASMPointerF32 xptr,
1921                                                               const SkFont& font)->sk_sp<SkTextBlob> {
1922             const SkGlyphID* glyphs = reinterpret_cast<const SkGlyphID*>(gPtr);
1923             const SkRSXform* xforms = reinterpret_cast<const SkRSXform*>(xptr);
1924 
1925             return SkTextBlob::MakeFromRSXform(glyphs, byteLen, xforms, font, SkTextEncoding::kGlyphID);
1926         }), allow_raw_pointers())
1927         .class_function("_MakeFromText", optional_override([](WASMPointerU8 sptr,
1928                                                               size_t len, const SkFont& font)->sk_sp<SkTextBlob> {
1929             const char* str = reinterpret_cast<const char*>(sptr);
1930             return SkTextBlob::MakeFromText(str, len, font, SkTextEncoding::kUTF8);
1931         }), allow_raw_pointers())
1932         .class_function("_MakeFromGlyphs", optional_override([](WASMPointerU16 gPtr,
1933                                                                 size_t byteLen, const SkFont& font)->sk_sp<SkTextBlob> {
1934             const SkGlyphID* glyphs = reinterpret_cast<const SkGlyphID*>(gPtr);
1935             return SkTextBlob::MakeFromText(glyphs, byteLen, font, SkTextEncoding::kGlyphID);
1936         }), allow_raw_pointers());
1937 
1938     class_<SkTypeface>("Typeface")
1939         .smart_ptr<sk_sp<SkTypeface>>("sk_sp<Typeface>")
1940         .class_function("_MakeFreeTypeFaceFromData", optional_override([](WASMPointerU8 fPtr,
1941                                                 int flen)->sk_sp<SkTypeface> {
1942             uint8_t* font = reinterpret_cast<uint8_t*>(fPtr);
1943             sk_sp<SkData> fontData = SkData::MakeFromMalloc(font, flen);
1944 
1945             return SkFontMgr::RefDefault()->makeFromData(fontData);
1946         }), allow_raw_pointers())
1947         .function("_getGlyphIDs", optional_override([](SkTypeface& self, WASMPointerU8 sptr,
1948                                                    size_t strLen, size_t expectedCodePoints,
1949                                                    WASMPointerU16 iPtr) -> int {
1950             char* str = reinterpret_cast<char*>(sptr);
1951             SkGlyphID* glyphIDs = reinterpret_cast<SkGlyphID*>(iPtr);
1952 
1953             int actualCodePoints = self.textToGlyphs(str, strLen, SkTextEncoding::kUTF8,
1954                                                      glyphIDs, expectedCodePoints);
1955             return actualCodePoints;
1956         }));
1957 #endif
1958 
1959     class_<SkVertices>("Vertices")
1960         .smart_ptr<sk_sp<SkVertices>>("sk_sp<Vertices>")
1961         .function("_bounds", optional_override([](SkVertices& self,
1962                                                   WASMPointerF32 fPtr)->void {
1963             SkRect* output = reinterpret_cast<SkRect*>(fPtr);
1964             output[0] = self.bounds();
1965         }))
1966         .function("uniqueID", &SkVertices::uniqueID);
1967 
1968     // Not intended to be called directly by clients
1969     class_<SkVertices::Builder>("_VerticesBuilder")
1970         .constructor<SkVertices::VertexMode, int, int, uint32_t>()
1971         .function("colors", optional_override([](SkVertices::Builder& self)->WASMPointerF32{
1972             // Emscripten won't let us return bare pointers, but we can return ints just fine.
1973             return reinterpret_cast<WASMPointerF32>(self.colors());
1974         }))
1975         .function("detach", &SkVertices::Builder::detach)
1976         .function("indices", optional_override([](SkVertices::Builder& self)->WASMPointerU16{
1977             // Emscripten won't let us return bare pointers, but we can return ints just fine.
1978             return reinterpret_cast<WASMPointerU16>(self.indices());
1979         }))
1980         .function("positions", optional_override([](SkVertices::Builder& self)->WASMPointerF32{
1981             // Emscripten won't let us return bare pointers, but we can return ints just fine.
1982             return reinterpret_cast<WASMPointerF32>(self.positions());
1983         }))
1984         .function("texCoords", optional_override([](SkVertices::Builder& self)->WASMPointerF32{
1985             // Emscripten won't let us return bare pointers, but we can return ints just fine.
1986             return reinterpret_cast<WASMPointerF32>(self.texCoords());
1987         }));
1988 
1989     enum_<SkAlphaType>("AlphaType")
1990         .value("Opaque",   SkAlphaType::kOpaque_SkAlphaType)
1991         .value("Premul",   SkAlphaType::kPremul_SkAlphaType)
1992         .value("Unpremul", SkAlphaType::kUnpremul_SkAlphaType);
1993 
1994     enum_<SkBlendMode>("BlendMode")
1995         .value("Clear",      SkBlendMode::kClear)
1996         .value("Src",        SkBlendMode::kSrc)
1997         .value("Dst",        SkBlendMode::kDst)
1998         .value("SrcOver",    SkBlendMode::kSrcOver)
1999         .value("DstOver",    SkBlendMode::kDstOver)
2000         .value("SrcIn",      SkBlendMode::kSrcIn)
2001         .value("DstIn",      SkBlendMode::kDstIn)
2002         .value("SrcOut",     SkBlendMode::kSrcOut)
2003         .value("DstOut",     SkBlendMode::kDstOut)
2004         .value("SrcATop",    SkBlendMode::kSrcATop)
2005         .value("DstATop",    SkBlendMode::kDstATop)
2006         .value("Xor",        SkBlendMode::kXor)
2007         .value("Plus",       SkBlendMode::kPlus)
2008         .value("Modulate",   SkBlendMode::kModulate)
2009         .value("Screen",     SkBlendMode::kScreen)
2010         .value("Overlay",    SkBlendMode::kOverlay)
2011         .value("Darken",     SkBlendMode::kDarken)
2012         .value("Lighten",    SkBlendMode::kLighten)
2013         .value("ColorDodge", SkBlendMode::kColorDodge)
2014         .value("ColorBurn",  SkBlendMode::kColorBurn)
2015         .value("HardLight",  SkBlendMode::kHardLight)
2016         .value("SoftLight",  SkBlendMode::kSoftLight)
2017         .value("Difference", SkBlendMode::kDifference)
2018         .value("Exclusion",  SkBlendMode::kExclusion)
2019         .value("Multiply",   SkBlendMode::kMultiply)
2020         .value("Hue",        SkBlendMode::kHue)
2021         .value("Saturation", SkBlendMode::kSaturation)
2022         .value("Color",      SkBlendMode::kColor)
2023         .value("Luminosity", SkBlendMode::kLuminosity);
2024 
2025     enum_<SkBlurStyle>("BlurStyle")
2026         .value("Normal", SkBlurStyle::kNormal_SkBlurStyle)
2027         .value("Solid",  SkBlurStyle::kSolid_SkBlurStyle)
2028         .value("Outer",  SkBlurStyle::kOuter_SkBlurStyle)
2029         .value("Inner",  SkBlurStyle::kInner_SkBlurStyle);
2030 
2031     enum_<SkClipOp>("ClipOp")
2032         .value("Difference", SkClipOp::kDifference)
2033         .value("Intersect",  SkClipOp::kIntersect);
2034 
2035     enum_<SkColorType>("ColorType")
2036         .value("Alpha_8", SkColorType::kAlpha_8_SkColorType)
2037         .value("RGB_565", SkColorType::kRGB_565_SkColorType)
2038         .value("RGBA_8888", SkColorType::kRGBA_8888_SkColorType)
2039         .value("BGRA_8888", SkColorType::kBGRA_8888_SkColorType)
2040         .value("RGBA_1010102", SkColorType::kRGBA_1010102_SkColorType)
2041         .value("RGB_101010x", SkColorType::kRGB_101010x_SkColorType)
2042         .value("Gray_8", SkColorType::kGray_8_SkColorType)
2043         .value("RGBA_F16", SkColorType::kRGBA_F16_SkColorType)
2044         .value("RGBA_F32", SkColorType::kRGBA_F32_SkColorType);
2045 
2046     enum_<SkPathFillType>("FillType")
2047         .value("Winding",           SkPathFillType::kWinding)
2048         .value("EvenOdd",           SkPathFillType::kEvenOdd);
2049 
2050     enum_<SkFilterMode>("FilterMode")
2051         .value("Nearest",   SkFilterMode::kNearest)
2052         .value("Linear",    SkFilterMode::kLinear);
2053 
2054     // Only used to control the encode function.
2055     // TODO(kjlubick): compile these out when the appropriate encoder is disabled.
2056     enum_<SkEncodedImageFormat>("ImageFormat")
2057         .value("PNG",  SkEncodedImageFormat::kPNG)
2058         .value("JPEG",  SkEncodedImageFormat::kJPEG)
2059         .value("WEBP",  SkEncodedImageFormat::kWEBP);
2060 
2061     enum_<SkMipmapMode>("MipmapMode")
2062         .value("None",    SkMipmapMode::kNone)
2063         .value("Nearest", SkMipmapMode::kNearest)
2064         .value("Linear",  SkMipmapMode::kLinear);
2065 
2066     enum_<SkPaint::Style>("PaintStyle")
2067         .value("Fill",            SkPaint::Style::kFill_Style)
2068         .value("Stroke",          SkPaint::Style::kStroke_Style);
2069 
2070 #ifdef SK_INCLUDE_PATHOPS
2071     enum_<SkPathOp>("PathOp")
2072         .value("Difference",         SkPathOp::kDifference_SkPathOp)
2073         .value("Intersect",          SkPathOp::kIntersect_SkPathOp)
2074         .value("Union",              SkPathOp::kUnion_SkPathOp)
2075         .value("XOR",                SkPathOp::kXOR_SkPathOp)
2076         .value("ReverseDifference",  SkPathOp::kReverseDifference_SkPathOp);
2077 #endif
2078 
2079     enum_<SkCanvas::PointMode>("PointMode")
2080         .value("Points",   SkCanvas::PointMode::kPoints_PointMode)
2081         .value("Lines",    SkCanvas::PointMode::kLines_PointMode)
2082         .value("Polygon",  SkCanvas::PointMode::kPolygon_PointMode);
2083 
2084     enum_<SkPaint::Cap>("StrokeCap")
2085         .value("Butt",   SkPaint::Cap::kButt_Cap)
2086         .value("Round",  SkPaint::Cap::kRound_Cap)
2087         .value("Square", SkPaint::Cap::kSquare_Cap);
2088 
2089     enum_<SkPaint::Join>("StrokeJoin")
2090         .value("Miter", SkPaint::Join::kMiter_Join)
2091         .value("Round", SkPaint::Join::kRound_Join)
2092         .value("Bevel", SkPaint::Join::kBevel_Join);
2093 
2094 #ifndef SK_NO_FONTS
2095     enum_<SkFontHinting>("FontHinting")
2096         .value("None",   SkFontHinting::kNone)
2097         .value("Slight", SkFontHinting::kSlight)
2098         .value("Normal", SkFontHinting::kNormal)
2099         .value("Full",   SkFontHinting::kFull);
2100 
2101     enum_<SkFont::Edging>("FontEdging")
2102 #ifndef CANVASKIT_NO_ALIAS_FONT
2103         .value("Alias",             SkFont::Edging::kAlias)
2104 #endif
2105         .value("AntiAlias",         SkFont::Edging::kAntiAlias)
2106         .value("SubpixelAntiAlias", SkFont::Edging::kSubpixelAntiAlias);
2107 #endif
2108 
2109     enum_<SkTileMode>("TileMode")
2110         .value("Clamp",    SkTileMode::kClamp)
2111         .value("Repeat",   SkTileMode::kRepeat)
2112         .value("Mirror",   SkTileMode::kMirror)
2113         .value("Decal",    SkTileMode::kDecal);
2114 
2115     enum_<SkVertices::VertexMode>("VertexMode")
2116         .value("Triangles",       SkVertices::VertexMode::kTriangles_VertexMode)
2117         .value("TrianglesStrip",  SkVertices::VertexMode::kTriangleStrip_VertexMode)
2118         .value("TriangleFan",     SkVertices::VertexMode::kTriangleFan_VertexMode);
2119 
2120     // A value object is much simpler than a class - it is returned as a JS
2121     // object and does not require delete().
2122     // https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#value-types
2123 
2124     value_object<SimpleImageInfo>("ImageInfo")
2125         .field("width",      &SimpleImageInfo::width)
2126         .field("height",     &SimpleImageInfo::height)
2127         .field("colorType",  &SimpleImageInfo::colorType)
2128         .field("alphaType",  &SimpleImageInfo::alphaType)
2129         .field("colorSpace", &SimpleImageInfo::colorSpace);
2130 
2131     value_object<StrokeOpts>("StrokeOpts")
2132         .field("width",       &StrokeOpts::width)
2133         .field("miter_limit", &StrokeOpts::miter_limit)
2134         .field("join",        &StrokeOpts::join)
2135         .field("cap",         &StrokeOpts::cap)
2136         .field("precision",   &StrokeOpts::precision);
2137 
2138     constant("MOVE_VERB",  MOVE);
2139     constant("LINE_VERB",  LINE);
2140     constant("QUAD_VERB",  QUAD);
2141     constant("CONIC_VERB", CONIC);
2142     constant("CUBIC_VERB", CUBIC);
2143     constant("CLOSE_VERB", CLOSE);
2144 
2145     constant("SaveLayerInitWithPrevious", (int)SkCanvas::SaveLayerFlagsSet::kInitWithPrevious_SaveLayerFlag);
2146     constant("SaveLayerF16ColorType",     (int)SkCanvas::SaveLayerFlagsSet::kF16ColorType);
2147 
2148     constant("ShadowTransparentOccluder", (int)SkShadowFlags::kTransparentOccluder_ShadowFlag);
2149     constant("ShadowGeometricOnly", (int)SkShadowFlags::kGeometricOnly_ShadowFlag);
2150     constant("ShadowDirectionalLight", (int)SkShadowFlags::kDirectionalLight_ShadowFlag);
2151 
2152 #ifndef SK_NO_FONTS
2153     constant("_GlyphRunFlags_isWhiteSpace", (int)skia::textlayout::Paragraph::kWhiteSpace_VisitorFlag);
2154 #endif
2155 }
2156