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