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