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