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