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