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