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