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