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