blob: 27edd7de738aebf3ed4598c0040a73947bb21ae3 [file] [log] [blame]
Kevin Lubick217056c2018-09-20 17:39:31 -04001/*
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
Kevin Lubick53965c92018-10-11 08:51:55 -04008#if SK_SUPPORT_GPU
Kevin Lubick217056c2018-09-20 17:39:31 -04009#include "GrBackendSurface.h"
10#include "GrContext.h"
11#include "GrGLInterface.h"
12#include "GrGLTypes.h"
Kevin Lubick53965c92018-10-11 08:51:55 -040013#endif
14
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040015#include "SkBlendMode.h"
Kevin Lubickea905ec2018-11-30 14:05:58 -050016#include "SkBlurTypes.h"
Kevin Lubick217056c2018-09-20 17:39:31 -040017#include "SkCanvas.h"
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040018#include "SkColor.h"
Kevin Lubick217056c2018-09-20 17:39:31 -040019#include "SkCornerPathEffect.h"
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040020#include "SkDashPathEffect.h"
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040021#include "SkData.h"
Kevin Lubick217056c2018-09-20 17:39:31 -040022#include "SkDiscretePathEffect.h"
Alexander Khovansky3e119332018-11-15 02:01:19 +030023#include "SkEncodedImageFormat.h"
Kevin Lubick0a1293c2018-12-03 12:31:04 -050024#include "SkFilterQuality.h"
Kevin Lubick35ac0382019-01-02 15:13:57 -050025#include "SkFont.h"
Kevin Lubick217056c2018-09-20 17:39:31 -040026#include "SkFontMgr.h"
27#include "SkFontMgrPriv.h"
Kevin Lubick35ac0382019-01-02 15:13:57 -050028#include "SkFontTypes.h"
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040029#include "SkGradientShader.h"
Kevin Lubick0a1293c2018-12-03 12:31:04 -050030#include "SkImage.h"
Kevin Lubickea905ec2018-11-30 14:05:58 -050031#include "SkImageInfo.h"
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040032#include "SkImageShader.h"
Florin Malita91af8d82018-11-30 16:46:45 -050033#include "SkMakeUnique.h"
Kevin Lubick61ef7b22018-11-27 13:26:59 -050034#include "SkMaskFilter.h"
Kevin Lubick217056c2018-09-20 17:39:31 -040035#include "SkPaint.h"
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040036#include "SkParsePath.h"
Kevin Lubick217056c2018-09-20 17:39:31 -040037#include "SkPath.h"
38#include "SkPathEffect.h"
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040039#include "SkPathOps.h"
Kevin Lubick217056c2018-09-20 17:39:31 -040040#include "SkScalar.h"
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040041#include "SkShader.h"
Kevin Lubick61ef7b22018-11-27 13:26:59 -050042#include "SkShadowUtils.h"
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040043#include "SkString.h"
44#include "SkStrokeRec.h"
Kevin Lubick217056c2018-09-20 17:39:31 -040045#include "SkSurface.h"
46#include "SkSurfaceProps.h"
Kevin Lubickec4903d2019-01-14 08:36:08 -050047#include "SkTextBlob.h"
Kevin Lubick46839422019-01-03 14:27:27 -050048#include "SkTrimPathEffect.h"
Kevin Lubickddd0a332018-12-12 10:35:13 -050049#include "SkTypeface.h"
50#include "SkTypes.h"
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040051#include "SkVertices.h"
52
Kevin Lubick217056c2018-09-20 17:39:31 -040053#include <iostream>
54#include <string>
Kevin Lubick217056c2018-09-20 17:39:31 -040055
Kevin Lubick46839422019-01-03 14:27:27 -050056#include "WasmAliases.h"
Kevin Lubick217056c2018-09-20 17:39:31 -040057#include <emscripten.h>
58#include <emscripten/bind.h>
Kevin Lubick46839422019-01-03 14:27:27 -050059
Kevin Lubick53965c92018-10-11 08:51:55 -040060#if SK_SUPPORT_GPU
61#include <GL/gl.h>
Kevin Lubick217056c2018-09-20 17:39:31 -040062#include <emscripten/html5.h>
Kevin Lubick53965c92018-10-11 08:51:55 -040063#endif
Kevin Lubick217056c2018-09-20 17:39:31 -040064
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040065// Aliases for less typing
66using BoneIndices = SkVertices::BoneIndices;
67using BoneWeights = SkVertices::BoneWeights;
68using Bone = SkVertices::Bone;
Kevin Lubick217056c2018-09-20 17:39:31 -040069
Kevin Lubick53965c92018-10-11 08:51:55 -040070#if SK_SUPPORT_GPU
Kevin Lubick217056c2018-09-20 17:39:31 -040071// Wraps the WebGL context in an SkSurface and returns it.
Kevin Lubick9e40e6f2018-10-22 12:08:22 -040072// This function based on the work of
73// https://github.com/Zubnix/skia-wasm-port/, used under the terms of the MIT license.
Kevin Lubick5f1692c2019-01-03 16:20:04 -050074sk_sp<SkSurface> getWebGLSurface(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context, int width, int height) {
Kevin Lubick217056c2018-09-20 17:39:31 -040075 EMSCRIPTEN_RESULT r = emscripten_webgl_make_context_current(context);
76 if (r < 0) {
Kevin Lubick5f1692c2019-01-03 16:20:04 -050077 printf("failed to make webgl context current %d\n", r);
Kevin Lubick217056c2018-09-20 17:39:31 -040078 return nullptr;
79 }
80
81 glClearColor(0, 0, 0, 0);
82 glClearStencil(0);
83 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
84
85 // setup GrContext
86 auto interface = GrGLMakeNativeInterface();
87
88 // setup contexts
89 sk_sp<GrContext> grContext(GrContext::MakeGL(interface));
90
91 // Wrap the frame buffer object attached to the screen in a Skia render target so Skia can
92 // render to it
93 GrGLint buffer;
94 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &buffer);
95 GrGLFramebufferInfo info;
96 info.fFBOID = (GrGLuint) buffer;
97 SkColorType colorType;
98
99 info.fFormat = GL_RGBA8;
100 colorType = kRGBA_8888_SkColorType;
101
102 GrBackendRenderTarget target(width, height, 0, 8, info);
103
104 sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget(grContext.get(), target,
105 kBottomLeft_GrSurfaceOrigin,
106 colorType, nullptr, nullptr));
107 return surface;
108}
Kevin Lubick53965c92018-10-11 08:51:55 -0400109#endif
Kevin Lubick217056c2018-09-20 17:39:31 -0400110
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400111struct SimpleMatrix {
112 SkScalar scaleX, skewX, transX;
113 SkScalar skewY, scaleY, transY;
114 SkScalar pers0, pers1, pers2;
115};
116
117SkMatrix toSkMatrix(const SimpleMatrix& sm) {
118 return SkMatrix::MakeAll(sm.scaleX, sm.skewX , sm.transX,
119 sm.skewY , sm.scaleY, sm.transY,
120 sm.pers0 , sm.pers1 , sm.pers2);
Kevin Lubick217056c2018-09-20 17:39:31 -0400121}
122
Kevin Lubick5d5723c2018-12-07 10:09:11 -0500123SimpleMatrix toSimpleSkMatrix(const SkMatrix& sm) {
124 SimpleMatrix m {sm[0], sm[1], sm[2],
125 sm[3], sm[4], sm[5],
126 sm[6], sm[7], sm[8]};
127 return m;
128}
129
Kevin Lubickea905ec2018-11-30 14:05:58 -0500130struct SimpleImageInfo {
131 int width;
132 int height;
133 SkColorType colorType;
134 SkAlphaType alphaType;
135 // TODO color spaces?
136};
137
138SkImageInfo toSkImageInfo(const SimpleImageInfo& sii) {
139 return SkImageInfo::Make(sii.width, sii.height, sii.colorType, sii.alphaType);
140}
141
Kevin Lubick217056c2018-09-20 17:39:31 -0400142//========================================================================================
143// Path things
144//========================================================================================
145
146// All these Apply* methods are simple wrappers to avoid returning an object.
147// The default WASM bindings produce code that will leak if a return value
148// isn't assigned to a JS variable and has delete() called on it.
149// These Apply methods, combined with the smarter binding code allow for chainable
150// commands that don't leak if the return value is ignored (i.e. when used intuitively).
151
Kevin Lubick1a05fce2018-11-20 12:51:16 -0500152void ApplyAddArc(SkPath& orig, const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle) {
153 orig.addArc(oval, startAngle, sweepAngle);
154}
155
Kevin Lubick217056c2018-09-20 17:39:31 -0400156void ApplyAddPath(SkPath& orig, const SkPath& newPath,
157 SkScalar scaleX, SkScalar skewX, SkScalar transX,
158 SkScalar skewY, SkScalar scaleY, SkScalar transY,
Kevin Lubick1a05fce2018-11-20 12:51:16 -0500159 SkScalar pers0, SkScalar pers1, SkScalar pers2,
160 bool extendPath) {
Kevin Lubick217056c2018-09-20 17:39:31 -0400161 SkMatrix m = SkMatrix::MakeAll(scaleX, skewX , transX,
162 skewY , scaleY, transY,
163 pers0 , pers1 , pers2);
Kevin Lubick1a05fce2018-11-20 12:51:16 -0500164 orig.addPath(newPath, m, extendPath ? SkPath::kExtend_AddPathMode :
165 SkPath::kAppend_AddPathMode);
Kevin Lubick217056c2018-09-20 17:39:31 -0400166}
167
Kevin Lubick1a05fce2018-11-20 12:51:16 -0500168void ApplyAddRect(SkPath& path, SkScalar left, SkScalar top,
169 SkScalar right, SkScalar bottom, bool ccw) {
170 path.addRect(left, top, right, bottom,
Kevin Lubick1646e7d2018-12-07 13:03:08 -0500171 ccw ? SkPath::Direction::kCCW_Direction :
172 SkPath::Direction::kCW_Direction);
Alexander Khovansky3e119332018-11-15 02:01:19 +0300173}
174
Kevin Lubickda3d8ac2019-01-07 11:08:55 -0500175void ApplyAddRoundRect(SkPath& path, SkScalar left, SkScalar top,
176 SkScalar right, SkScalar bottom, uintptr_t /* SkScalar* */ rPtr,
177 bool ccw) {
178 // See comment below for uintptr_t explanation
179 const SkScalar* radii = reinterpret_cast<const SkScalar*>(rPtr);
180 path.addRoundRect(SkRect::MakeLTRB(left, top, right, bottom), radii,
181 ccw ? SkPath::Direction::kCCW_Direction : SkPath::Direction::kCW_Direction);
182}
183
184
Kevin Lubick217056c2018-09-20 17:39:31 -0400185void ApplyArcTo(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
186 SkScalar radius) {
187 p.arcTo(x1, y1, x2, y2, radius);
188}
189
Kevin Lubick1646e7d2018-12-07 13:03:08 -0500190void ApplyArcToAngle(SkPath& p, SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) {
191 p.arcTo(oval, startAngle, sweepAngle, forceMoveTo);
192}
193
Kevin Lubick217056c2018-09-20 17:39:31 -0400194void ApplyClose(SkPath& p) {
195 p.close();
196}
197
198void ApplyConicTo(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
199 SkScalar w) {
200 p.conicTo(x1, y1, x2, y2, w);
201}
202
203void ApplyCubicTo(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
204 SkScalar x3, SkScalar y3) {
205 p.cubicTo(x1, y1, x2, y2, x3, y3);
206}
207
208void ApplyLineTo(SkPath& p, SkScalar x, SkScalar y) {
209 p.lineTo(x, y);
210}
211
212void ApplyMoveTo(SkPath& p, SkScalar x, SkScalar y) {
213 p.moveTo(x, y);
214}
215
Kevin Lubickda3d8ac2019-01-07 11:08:55 -0500216void ApplyReset(SkPath& p) {
217 p.reset();
218}
219
220void ApplyRewind(SkPath& p) {
221 p.rewind();
222}
223
Kevin Lubick217056c2018-09-20 17:39:31 -0400224void ApplyQuadTo(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
225 p.quadTo(x1, y1, x2, y2);
226}
227
228void ApplyTransform(SkPath& orig,
229 SkScalar scaleX, SkScalar skewX, SkScalar transX,
230 SkScalar skewY, SkScalar scaleY, SkScalar transY,
231 SkScalar pers0, SkScalar pers1, SkScalar pers2) {
232 SkMatrix m = SkMatrix::MakeAll(scaleX, skewX , transX,
233 skewY , scaleY, transY,
234 pers0 , pers1 , pers2);
235 orig.transform(m);
236}
237
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400238bool EMSCRIPTEN_KEEPALIVE ApplySimplify(SkPath& path) {
239 return Simplify(path, &path);
240}
241
242bool EMSCRIPTEN_KEEPALIVE ApplyPathOp(SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
243 return Op(pathOne, pathTwo, op, &pathOne);
244}
245
246JSString EMSCRIPTEN_KEEPALIVE ToSVGString(const SkPath& path) {
247 SkString s;
248 SkParsePath::ToSVGString(path, &s);
249 return emscripten::val(s.c_str());
250}
251
Kevin Lubicka40f8322018-12-17 16:01:36 -0500252SkPathOrNull EMSCRIPTEN_KEEPALIVE MakePathFromSVGString(std::string str) {
253 SkPath path;
254 if (SkParsePath::FromSVGString(str.c_str(), &path)) {
255 return emscripten::val(path);
256 }
257 return emscripten::val::null();
258}
259
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400260SkPathOrNull EMSCRIPTEN_KEEPALIVE MakePathFromOp(const SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
261 SkPath out;
262 if (Op(pathOne, pathTwo, op, &out)) {
263 return emscripten::val(out);
264 }
265 return emscripten::val::null();
266}
267
Kevin Lubick217056c2018-09-20 17:39:31 -0400268SkPath EMSCRIPTEN_KEEPALIVE CopyPath(const SkPath& a) {
269 SkPath copy(a);
270 return copy;
271}
272
273bool EMSCRIPTEN_KEEPALIVE Equals(const SkPath& a, const SkPath& b) {
274 return a == b;
275}
276
Kevin Lubickda3d8ac2019-01-07 11:08:55 -0500277// =================================================================================
278// Creating/Exporting Paths with cmd arrays
279// =================================================================================
280
281static const int MOVE = 0;
282static const int LINE = 1;
283static const int QUAD = 2;
284static const int CONIC = 3;
285static const int CUBIC = 4;
286static const int CLOSE = 5;
287
288template <typename VisitFunc>
289void VisitPath(const SkPath& p, VisitFunc&& f) {
290 SkPath::RawIter iter(p);
291 SkPoint pts[4];
292 SkPath::Verb verb;
293 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
294 f(verb, pts, iter);
295 }
296}
297
298JSArray EMSCRIPTEN_KEEPALIVE ToCmds(const SkPath& path) {
299 JSArray cmds = emscripten::val::array();
300
301 VisitPath(path, [&cmds](SkPath::Verb verb, const SkPoint pts[4], SkPath::RawIter iter) {
302 JSArray cmd = emscripten::val::array();
303 switch (verb) {
304 case SkPath::kMove_Verb:
305 cmd.call<void>("push", MOVE, pts[0].x(), pts[0].y());
306 break;
307 case SkPath::kLine_Verb:
308 cmd.call<void>("push", LINE, pts[1].x(), pts[1].y());
309 break;
310 case SkPath::kQuad_Verb:
311 cmd.call<void>("push", QUAD, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
312 break;
313 case SkPath::kConic_Verb:
314 cmd.call<void>("push", CONIC,
315 pts[1].x(), pts[1].y(),
316 pts[2].x(), pts[2].y(), iter.conicWeight());
317 break;
318 case SkPath::kCubic_Verb:
319 cmd.call<void>("push", CUBIC,
320 pts[1].x(), pts[1].y(),
321 pts[2].x(), pts[2].y(),
322 pts[3].x(), pts[3].y());
323 break;
324 case SkPath::kClose_Verb:
325 cmd.call<void>("push", CLOSE);
326 break;
327 case SkPath::kDone_Verb:
328 SkASSERT(false);
329 break;
330 }
331 cmds.call<void>("push", cmd);
332 });
333 return cmds;
334}
335
336// This type signature is a mess, but it's necessary. See, we can't use "bind" (EMSCRIPTEN_BINDINGS)
337// and pointers to primitive types (Only bound types like SkPoint). We could if we used
338// cwrap (see https://becominghuman.ai/passing-and-returning-webassembly-array-parameters-a0f572c65d97)
339// but that requires us to stick to C code and, AFAIK, doesn't allow us to return nice things like
340// SkPath or SkOpBuilder.
341//
342// So, basically, if we are using C++ and EMSCRIPTEN_BINDINGS, we can't have primative pointers
343// in our function type signatures. (this gives an error message like "Cannot call foo due to unbound
344// types Pi, Pf"). But, we can just pretend they are numbers and cast them to be pointers and
345// the compiler is happy.
346SkPathOrNull EMSCRIPTEN_KEEPALIVE MakePathFromCmds(uintptr_t /* float* */ cptr, int numCmds) {
347 const auto* cmds = reinterpret_cast<const float*>(cptr);
348 SkPath path;
349 float x1, y1, x2, y2, x3, y3;
350
351 // if there are not enough arguments, bail with the path we've constructed so far.
352 #define CHECK_NUM_ARGS(n) \
353 if ((i + n) > numCmds) { \
354 SkDebugf("Not enough args to match the verbs. Saw %d commands\n", numCmds); \
355 return emscripten::val::null(); \
356 }
357
358 for(int i = 0; i < numCmds;){
359 switch (sk_float_floor2int(cmds[i++])) {
360 case MOVE:
361 CHECK_NUM_ARGS(2);
362 x1 = cmds[i++], y1 = cmds[i++];
363 path.moveTo(x1, y1);
364 break;
365 case LINE:
366 CHECK_NUM_ARGS(2);
367 x1 = cmds[i++], y1 = cmds[i++];
368 path.lineTo(x1, y1);
369 break;
370 case QUAD:
371 CHECK_NUM_ARGS(4);
372 x1 = cmds[i++], y1 = cmds[i++];
373 x2 = cmds[i++], y2 = cmds[i++];
374 path.quadTo(x1, y1, x2, y2);
375 break;
376 case CONIC:
377 CHECK_NUM_ARGS(5);
378 x1 = cmds[i++], y1 = cmds[i++];
379 x2 = cmds[i++], y2 = cmds[i++];
380 x3 = cmds[i++]; // weight
381 path.conicTo(x1, y1, x2, y2, x3);
382 break;
383 case CUBIC:
384 CHECK_NUM_ARGS(6);
385 x1 = cmds[i++], y1 = cmds[i++];
386 x2 = cmds[i++], y2 = cmds[i++];
387 x3 = cmds[i++], y3 = cmds[i++];
388 path.cubicTo(x1, y1, x2, y2, x3, y3);
389 break;
390 case CLOSE:
391 path.close();
392 break;
393 default:
394 SkDebugf(" path: UNKNOWN command %f, aborting dump...\n", cmds[i-1]);
395 return emscripten::val::null();
396 }
397 }
398
399 #undef CHECK_NUM_ARGS
400
401 return emscripten::val(path);
402}
403
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400404//========================================================================================
405// Path Effects
406//========================================================================================
407
408bool ApplyDash(SkPath& path, SkScalar on, SkScalar off, SkScalar phase) {
409 SkScalar intervals[] = { on, off };
410 auto pe = SkDashPathEffect::Make(intervals, 2, phase);
411 if (!pe) {
412 SkDebugf("Invalid args to dash()\n");
413 return false;
414 }
415 SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle);
416 if (pe->filterPath(&path, path, &rec, nullptr)) {
417 return true;
418 }
419 SkDebugf("Could not make dashed path\n");
420 return false;
Kevin Lubick217056c2018-09-20 17:39:31 -0400421}
422
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400423bool ApplyTrim(SkPath& path, SkScalar startT, SkScalar stopT, bool isComplement) {
424 auto mode = isComplement ? SkTrimPathEffect::Mode::kInverted : SkTrimPathEffect::Mode::kNormal;
425 auto pe = SkTrimPathEffect::Make(startT, stopT, mode);
426 if (!pe) {
427 SkDebugf("Invalid args to trim(): startT and stopT must be in [0,1]\n");
428 return false;
429 }
430 SkStrokeRec rec(SkStrokeRec::InitStyle::kHairline_InitStyle);
431 if (pe->filterPath(&path, path, &rec, nullptr)) {
432 return true;
433 }
434 SkDebugf("Could not trim path\n");
435 return false;
436}
437
438struct StrokeOpts {
Kevin Lubickb9db3902018-11-26 11:47:54 -0500439 // Default values are set in interface.js which allows clients
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400440 // to set any number of them. Otherwise, the binding code complains if
441 // any are omitted.
442 SkScalar width;
443 SkScalar miter_limit;
444 SkPaint::Join join;
445 SkPaint::Cap cap;
Kevin Lubick1646e7d2018-12-07 13:03:08 -0500446 float precision;
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400447};
448
449bool ApplyStroke(SkPath& path, StrokeOpts opts) {
450 SkPaint p;
451 p.setStyle(SkPaint::kStroke_Style);
452 p.setStrokeCap(opts.cap);
453 p.setStrokeJoin(opts.join);
454 p.setStrokeWidth(opts.width);
455 p.setStrokeMiter(opts.miter_limit);
456
Kevin Lubick1646e7d2018-12-07 13:03:08 -0500457 return p.getFillPath(path, &path, nullptr, opts.precision);
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400458}
459
460// to map from raw memory to a uint8array
461Uint8Array getSkDataBytes(const SkData *data) {
462 return Uint8Array(typed_memory_view(data->size(), data->bytes()));
463}
464
465// These objects have private destructors / delete mthods - I don't think
466// we need to do anything other than tell emscripten to do nothing.
Kevin Lubick217056c2018-09-20 17:39:31 -0400467namespace emscripten {
468 namespace internal {
469 template<typename ClassType>
470 void raw_destructor(ClassType *);
471
472 template<>
473 void raw_destructor<SkData>(SkData *ptr) {
474 }
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400475
476 template<>
Kevin Lubickddd0a332018-12-12 10:35:13 -0500477 void raw_destructor<SkTypeface>(SkTypeface *ptr) {
478 }
479
480 template<>
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400481 void raw_destructor<SkVertices>(SkVertices *ptr) {
482 }
Kevin Lubickec4903d2019-01-14 08:36:08 -0500483
484 template<>
485 void raw_destructor<SkTextBlob>(SkTextBlob *ptr) {
486 }
Kevin Lubick217056c2018-09-20 17:39:31 -0400487 }
488}
489
490// Some timesignatures below have uintptr_t instead of a pointer to a primative
491// type (e.g. SkScalar). This is necessary because we can't use "bind" (EMSCRIPTEN_BINDINGS)
492// and pointers to primitive types (Only bound types like SkPoint). We could if we used
493// cwrap (see https://becominghuman.ai/passing-and-returning-webassembly-array-parameters-a0f572c65d97)
494// but that requires us to stick to C code and, AFAIK, doesn't allow us to return nice things like
495// SkPath or SkCanvas.
496//
497// So, basically, if we are using C++ and EMSCRIPTEN_BINDINGS, we can't have primative pointers
498// in our function type signatures. (this gives an error message like "Cannot call foo due to unbound
499// types Pi, Pf"). But, we can just pretend they are numbers and cast them to be pointers and
500// the compiler is happy.
501EMSCRIPTEN_BINDINGS(Skia) {
Kevin Lubick53965c92018-10-11 08:51:55 -0400502#if SK_SUPPORT_GPU
Kevin Lubick217056c2018-09-20 17:39:31 -0400503 function("_getWebGLSurface", &getWebGLSurface, allow_raw_pointers());
Kevin Lubick53965c92018-10-11 08:51:55 -0400504 function("currentContext", &emscripten_webgl_get_current_context);
505 function("setCurrentContext", &emscripten_webgl_make_context_current);
Kevin Lubick3d99b1e2018-10-16 10:15:01 -0400506 constant("gpu", true);
Kevin Lubickb07204a2018-11-20 14:07:42 -0500507#endif
Kevin Lubick0a1293c2018-12-03 12:31:04 -0500508 function("_decodeImage", optional_override([](uintptr_t /* uint8_t* */ iptr,
509 size_t length)->sk_sp<SkImage> {
510 uint8_t* imgData = reinterpret_cast<uint8_t*>(iptr);
511 sk_sp<SkData> bytes = SkData::MakeWithoutCopy(imgData, length);
512 return SkImage::MakeFromEncoded(bytes);
513 }), allow_raw_pointers());
Kevin Lubickea905ec2018-11-30 14:05:58 -0500514 function("_getRasterDirectSurface", optional_override([](const SimpleImageInfo ii,
Kevin Lubick52b9f372018-12-04 13:57:36 -0500515 uintptr_t /* uint8_t* */ pPtr,
Kevin Lubickea905ec2018-11-30 14:05:58 -0500516 size_t rowBytes)->sk_sp<SkSurface> {
Kevin Lubick52b9f372018-12-04 13:57:36 -0500517 uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
Kevin Lubickea905ec2018-11-30 14:05:58 -0500518 SkImageInfo imageInfo = toSkImageInfo(ii);
519 return SkSurface::MakeRasterDirect(imageInfo, pixels, rowBytes, nullptr);
520 }), allow_raw_pointers());
Kevin Lubick53965c92018-10-11 08:51:55 -0400521 function("_getRasterN32PremulSurface", optional_override([](int width, int height)->sk_sp<SkSurface> {
522 return SkSurface::MakeRasterN32Premul(width, height, nullptr);
523 }), allow_raw_pointers());
Kevin Lubickb07204a2018-11-20 14:07:42 -0500524
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400525 function("getSkDataBytes", &getSkDataBytes, allow_raw_pointers());
Kevin Lubick217056c2018-09-20 17:39:31 -0400526 function("MakeSkCornerPathEffect", &SkCornerPathEffect::Make, allow_raw_pointers());
527 function("MakeSkDiscretePathEffect", &SkDiscretePathEffect::Make, allow_raw_pointers());
Kevin Lubick61ef7b22018-11-27 13:26:59 -0500528 function("MakeBlurMaskFilter", optional_override([](SkBlurStyle style, SkScalar sigma, bool respectCTM)->sk_sp<SkMaskFilter> {
529 // Adds a little helper because emscripten doesn't expose default params.
530 return SkMaskFilter::MakeBlur(style, sigma, respectCTM);
531 }), allow_raw_pointers());
Kevin Lubickda3d8ac2019-01-07 11:08:55 -0500532 function("_MakePathFromCmds", &MakePathFromCmds);
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400533 function("MakePathFromOp", &MakePathFromOp);
Kevin Lubicka40f8322018-12-17 16:01:36 -0500534 function("MakePathFromSVGString", &MakePathFromSVGString);
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400535
536 // These won't be called directly, there's a JS helper to deal with typed arrays.
Kevin Lubick217056c2018-09-20 17:39:31 -0400537 function("_MakeSkDashPathEffect", optional_override([](uintptr_t /* float* */ cptr, int count, SkScalar phase)->sk_sp<SkPathEffect> {
538 // See comment above for uintptr_t explanation
539 const float* intervals = reinterpret_cast<const float*>(cptr);
540 return SkDashPathEffect::Make(intervals, count, phase);
541 }), allow_raw_pointers());
Kevin Lubick52b9f372018-12-04 13:57:36 -0500542 function("_MakeImage", optional_override([](SimpleImageInfo ii,
543 uintptr_t /* uint8_t* */ pPtr, int plen,
544 size_t rowBytes)->sk_sp<SkImage> {
545 // See comment above for uintptr_t explanation
546 uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
547 SkImageInfo info = toSkImageInfo(ii);
548 sk_sp<SkData> pixelData = SkData::MakeFromMalloc(pixels, plen);
549
550 return SkImage::MakeRasterData(info, pixelData, rowBytes);
551 }), allow_raw_pointers());
Kevin Lubickd29edd72018-12-07 08:29:52 -0500552 // Allow localMatrix to be optional, so we have 2 declarations of these shaders
553 function("_MakeImageShader", optional_override([](sk_sp<SkImage> img,
554 SkShader::TileMode tx, SkShader::TileMode ty,
555 bool clampAsIfUnpremul)->sk_sp<SkShader> {
556 return SkImageShader::Make(img, tx, ty, nullptr, clampAsIfUnpremul);
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400557 }), allow_raw_pointers());
Kevin Lubickd29edd72018-12-07 08:29:52 -0500558 function("_MakeImageShader", optional_override([](sk_sp<SkImage> img,
559 SkShader::TileMode tx, SkShader::TileMode ty,
560 bool clampAsIfUnpremul, const SimpleMatrix& lm)->sk_sp<SkShader> {
561 SkMatrix localMatrix = toSkMatrix(lm);
562
563 return SkImageShader::Make(img, tx, ty, &localMatrix, clampAsIfUnpremul);
564 }), allow_raw_pointers());
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400565 function("_MakeLinearGradientShader", optional_override([](SkPoint start, SkPoint end,
566 uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
567 int count, SkShader::TileMode mode, uint32_t flags)->sk_sp<SkShader> {
568 SkPoint points[] = { start, end };
569 // See comment above for uintptr_t explanation
570 const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
571 const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
572
573 return SkGradientShader::MakeLinear(points, colors, positions, count,
574 mode, flags, nullptr);
575 }), allow_raw_pointers());
576 function("_MakeLinearGradientShader", optional_override([](SkPoint start, SkPoint end,
577 uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
578 int count, SkShader::TileMode mode, uint32_t flags,
579 const SimpleMatrix& lm)->sk_sp<SkShader> {
580 SkPoint points[] = { start, end };
581 // See comment above for uintptr_t explanation
582 const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
583 const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
584
585 SkMatrix localMatrix = toSkMatrix(lm);
586
587 return SkGradientShader::MakeLinear(points, colors, positions, count,
588 mode, flags, &localMatrix);
589 }), allow_raw_pointers());
590 function("_MakeRadialGradientShader", optional_override([](SkPoint center, SkScalar radius,
591 uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
592 int count, SkShader::TileMode mode, uint32_t flags)->sk_sp<SkShader> {
593 // See comment above for uintptr_t explanation
594 const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
595 const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
596
597 return SkGradientShader::MakeRadial(center, radius, colors, positions, count,
598 mode, flags, nullptr);
599 }), allow_raw_pointers());
600 function("_MakeRadialGradientShader", optional_override([](SkPoint center, SkScalar radius,
601 uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
602 int count, SkShader::TileMode mode, uint32_t flags,
603 const SimpleMatrix& lm)->sk_sp<SkShader> {
604 // See comment above for uintptr_t explanation
605 const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
606 const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
607
608 SkMatrix localMatrix = toSkMatrix(lm);
609 return SkGradientShader::MakeRadial(center, radius, colors, positions, count,
610 mode, flags, &localMatrix);
611 }), allow_raw_pointers());
Kevin Lubickeb2f6b02018-11-29 15:07:02 -0500612 function("_MakeTwoPointConicalGradientShader", optional_override([](
613 SkPoint start, SkScalar startRadius,
614 SkPoint end, SkScalar endRadius,
615 uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
616 int count, SkShader::TileMode mode, uint32_t flags)->sk_sp<SkShader> {
617 // See comment above for uintptr_t explanation
618 const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
619 const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
620
621 return SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius,
622 colors, positions, count, mode,
623 flags, nullptr);
624 }), allow_raw_pointers());
625 function("_MakeTwoPointConicalGradientShader", optional_override([](
626 SkPoint start, SkScalar startRadius,
627 SkPoint end, SkScalar endRadius,
628 uintptr_t /* SkColor* */ cPtr, uintptr_t /* SkScalar* */ pPtr,
629 int count, SkShader::TileMode mode, uint32_t flags,
630 const SimpleMatrix& lm)->sk_sp<SkShader> {
631 // See comment above for uintptr_t explanation
632 const SkColor* colors = reinterpret_cast<const SkColor*> (cPtr);
633 const SkScalar* positions = reinterpret_cast<const SkScalar*>(pPtr);
634
635 SkMatrix localMatrix = toSkMatrix(lm);
636 return SkGradientShader::MakeTwoPointConical(start, startRadius, end, endRadius,
637 colors, positions, count, mode,
638 flags, &localMatrix);
639 }), allow_raw_pointers());
640
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400641 function("_MakeSkVertices", optional_override([](SkVertices::VertexMode mode, int vertexCount,
642 uintptr_t /* SkPoint* */ pPtr, uintptr_t /* SkPoint* */ tPtr,
643 uintptr_t /* SkColor* */ cPtr,
644 uintptr_t /* BoneIndices* */ biPtr, uintptr_t /* BoneWeights* */ bwPtr,
645 int indexCount, uintptr_t /* uint16_t * */ iPtr)->sk_sp<SkVertices> {
646 // See comment above for uintptr_t explanation
647 const SkPoint* positions = reinterpret_cast<const SkPoint*>(pPtr);
648 const SkPoint* texs = reinterpret_cast<const SkPoint*>(tPtr);
649 const SkColor* colors = reinterpret_cast<const SkColor*>(cPtr);
650 const BoneIndices* boneIndices = reinterpret_cast<const BoneIndices*>(biPtr);
651 const BoneWeights* boneWeights = reinterpret_cast<const BoneWeights*>(bwPtr);
652 const uint16_t* indices = reinterpret_cast<const uint16_t*>(iPtr);
653
654 return SkVertices::MakeCopy(mode, vertexCount, positions, texs, colors,
655 boneIndices, boneWeights, indexCount, indices);
656 }), allow_raw_pointers());
Kevin Lubick217056c2018-09-20 17:39:31 -0400657
658 class_<SkCanvas>("SkCanvas")
659 .constructor<>()
660 .function("clear", optional_override([](SkCanvas& self, JSColor color)->void {
661 // JS side gives us a signed int instead of an unsigned int for color
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400662 // Add a optional_override to change it out.
Kevin Lubick217056c2018-09-20 17:39:31 -0400663 self.clear(SkColor(color));
664 }))
Kevin Lubickeb2f6b02018-11-29 15:07:02 -0500665 .function("clipPath", select_overload<void (const SkPath&, SkClipOp, bool)>(&SkCanvas::clipPath))
Kevin Lubick52b9f372018-12-04 13:57:36 -0500666 .function("clipRect", select_overload<void (const SkRect&, SkClipOp, bool)>(&SkCanvas::clipRect))
667 .function("concat", optional_override([](SkCanvas& self, const SimpleMatrix& m) {
668 self.concat(toSkMatrix(m));
669 }))
Kevin Lubickda3d8ac2019-01-07 11:08:55 -0500670 .function("drawArc", &SkCanvas::drawArc)
Kevin Lubick0a1293c2018-12-03 12:31:04 -0500671 .function("drawImage", select_overload<void (const sk_sp<SkImage>&, SkScalar, SkScalar, const SkPaint*)>(&SkCanvas::drawImage), allow_raw_pointers())
672 .function("drawImageRect", optional_override([](SkCanvas& self, const sk_sp<SkImage>& image,
673 SkRect src, SkRect dst,
674 const SkPaint* paint, bool fastSample)->void {
675 self.drawImageRect(image, src, dst, paint,
676 fastSample ? SkCanvas::kFast_SrcRectConstraint :
677 SkCanvas::kStrict_SrcRectConstraint);
678 }), allow_raw_pointers())
Kevin Lubickda3d8ac2019-01-07 11:08:55 -0500679 .function("drawLine", select_overload<void (SkScalar, SkScalar, SkScalar, SkScalar, const SkPaint&)>(&SkCanvas::drawLine))
680 .function("drawOval", &SkCanvas::drawOval)
Kevin Lubick217056c2018-09-20 17:39:31 -0400681 .function("drawPaint", &SkCanvas::drawPaint)
682 .function("drawPath", &SkCanvas::drawPath)
683 .function("drawRect", &SkCanvas::drawRect)
Kevin Lubickda3d8ac2019-01-07 11:08:55 -0500684 .function("drawRoundRect", &SkCanvas::drawRoundRect)
Kevin Lubick61ef7b22018-11-27 13:26:59 -0500685 .function("drawShadow", optional_override([](SkCanvas& self, const SkPath& path,
686 const SkPoint3& zPlaneParams,
687 const SkPoint3& lightPos, SkScalar lightRadius,
688 JSColor ambientColor, JSColor spotColor,
689 uint32_t flags) {
690 SkShadowUtils::DrawShadow(&self, path, zPlaneParams, lightPos, lightRadius,
691 SkColor(ambientColor), SkColor(spotColor), flags);
692 }))
Kevin Lubickec4903d2019-01-14 08:36:08 -0500693 .function("_drawSimpleText", optional_override([](SkCanvas& self, uintptr_t /* char* */ sptr,
694 size_t len, SkScalar x, SkScalar y, const SkFont& font,
695 const SkPaint& paint) {
696 // See comment above for uintptr_t explanation
697 const char* str = reinterpret_cast<const char*>(sptr);
698
699 self.drawSimpleText(str, len, SkTextEncoding::kUTF8, x, y, font, paint);
Kevin Lubick217056c2018-09-20 17:39:31 -0400700 }))
Kevin Lubickec4903d2019-01-14 08:36:08 -0500701 .function("drawTextBlob", select_overload<void (const sk_sp<SkTextBlob>&, SkScalar, SkScalar, const SkPaint&)>(&SkCanvas::drawTextBlob))
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400702 .function("drawVertices", select_overload<void (const sk_sp<SkVertices>&, SkBlendMode, const SkPaint&)>(&SkCanvas::drawVertices))
Kevin Lubick217056c2018-09-20 17:39:31 -0400703 .function("flush", &SkCanvas::flush)
Kevin Lubick5d5723c2018-12-07 10:09:11 -0500704 .function("getTotalMatrix", optional_override([](const SkCanvas& self)->SimpleMatrix {
705 SkMatrix m = self.getTotalMatrix();
706 return toSimpleSkMatrix(m);
707 }))
Kevin Lubick52b9f372018-12-04 13:57:36 -0500708 .function("_readPixels", optional_override([](SkCanvas& self, SimpleImageInfo di,
709 uintptr_t /* uint8_t* */ pPtr,
710 size_t dstRowBytes, int srcX, int srcY) {
711 uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
712 SkImageInfo dstInfo = toSkImageInfo(di);
713
714 return self.readPixels(dstInfo, pixels, dstRowBytes, srcX, srcY);
715 }))
Kevin Lubickeb2f6b02018-11-29 15:07:02 -0500716 .function("restore", &SkCanvas::restore)
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400717 .function("rotate", select_overload<void (SkScalar, SkScalar, SkScalar)>(&SkCanvas::rotate))
Kevin Lubick217056c2018-09-20 17:39:31 -0400718 .function("save", &SkCanvas::save)
Kevin Lubick006a6f32018-10-19 14:34:34 -0400719 .function("scale", &SkCanvas::scale)
Kevin Lubick006a6f32018-10-19 14:34:34 -0400720 .function("skew", &SkCanvas::skew)
Kevin Lubick52b9f372018-12-04 13:57:36 -0500721 .function("translate", &SkCanvas::translate)
722 .function("_writePixels", optional_override([](SkCanvas& self, SimpleImageInfo di,
723 uintptr_t /* uint8_t* */ pPtr,
724 size_t srcRowBytes, int dstX, int dstY) {
725 uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
726 SkImageInfo dstInfo = toSkImageInfo(di);
727
728 return self.writePixels(dstInfo, pixels, srcRowBytes, dstX, dstY);
729 }))
730 ;
Kevin Lubick217056c2018-09-20 17:39:31 -0400731
732 class_<SkData>("SkData")
733 .smart_ptr<sk_sp<SkData>>("sk_sp<SkData>>")
734 .function("size", &SkData::size);
735
Kevin Lubick35ac0382019-01-02 15:13:57 -0500736 class_<SkFont>("SkFont")
737 .constructor<>()
738 .constructor<sk_sp<SkTypeface>>()
739 .constructor<sk_sp<SkTypeface>, SkScalar>()
740 .constructor<sk_sp<SkTypeface>, SkScalar, SkScalar, SkScalar>()
741 .function("getScaleX", &SkFont::getScaleX)
742 .function("getSize", &SkFont::getSize)
743 .function("getSkewX", &SkFont::getSkewX)
744 .function("getTypeface", &SkFont::getTypeface, allow_raw_pointers())
745 .function("measureText", optional_override([](SkFont& self, std::string text) {
746 // TODO(kjlubick): This does not work well for non-ascii
747 // Need to maybe add a helper in interface.js that supports UTF-8
748 // Otherwise, go with std::wstring and set UTF-32 encoding.
749 return self.measureText(text.c_str(), text.length(), SkTextEncoding::kUTF8);
750 }))
751 .function("setScaleX", &SkFont::setScaleX)
752 .function("setSize", &SkFont::setSize)
753 .function("setSkewX", &SkFont::setSkewX)
754 .function("setTypeface", &SkFont::setTypeface, allow_raw_pointers());
755
Kevin Lubickddd0a332018-12-12 10:35:13 -0500756 class_<SkFontMgr>("SkFontMgr")
757 .smart_ptr<sk_sp<SkFontMgr>>("sk_sp<SkFontMgr>")
758 .class_function("RefDefault", &SkFontMgr::RefDefault)
759#ifdef SK_DEBUG
760 .function("dumpFamilies", optional_override([](SkFontMgr& self) {
761 int numFam = self.countFamilies();
762 SkDebugf("There are %d font families\n");
763 for (int i = 0 ; i< numFam; i++) {
764 SkString s;
765 self.getFamilyName(i, &s);
766 SkDebugf("\t%s", s.c_str());
767 }
768 }))
769#endif
770 .function("countFamilies", &SkFontMgr::countFamilies)
771 .function("_makeTypefaceFromData", optional_override([](SkFontMgr& self,
772 uintptr_t /* uint8_t* */ fPtr,
773 int flen)->sk_sp<SkTypeface> {
774 // See comment above for uintptr_t explanation
775 uint8_t* font = reinterpret_cast<uint8_t*>(fPtr);
776 sk_sp<SkData> fontData = SkData::MakeFromMalloc(font, flen);
777
778 return self.makeFromData(fontData);
779 }), allow_raw_pointers());
780
Kevin Lubick217056c2018-09-20 17:39:31 -0400781 class_<SkImage>("SkImage")
782 .smart_ptr<sk_sp<SkImage>>("sk_sp<SkImage>")
Kevin Lubick0a1293c2018-12-03 12:31:04 -0500783 .function("height", &SkImage::height)
784 .function("width", &SkImage::width)
Alexander Khovansky3e119332018-11-15 02:01:19 +0300785 .function("_encodeToData", select_overload<sk_sp<SkData>()const>(&SkImage::encodeToData))
786 .function("_encodeToDataWithFormat", select_overload<sk_sp<SkData>(SkEncodedImageFormat encodedImageFormat, int quality)const>(&SkImage::encodeToData));
Kevin Lubick217056c2018-09-20 17:39:31 -0400787
Kevin Lubick61ef7b22018-11-27 13:26:59 -0500788 class_<SkMaskFilter>("SkMaskFilter")
789 .smart_ptr<sk_sp<SkMaskFilter>>("sk_sp<SkMaskFilter>");
790
Kevin Lubick217056c2018-09-20 17:39:31 -0400791 class_<SkPaint>("SkPaint")
792 .constructor<>()
793 .function("copy", optional_override([](const SkPaint& self)->SkPaint {
794 SkPaint p(self);
795 return p;
796 }))
Kevin Lubick12c0e502018-11-28 12:51:56 -0500797 .function("getBlendMode", &SkPaint::getBlendMode)
Kevin Lubick61ef7b22018-11-27 13:26:59 -0500798 .function("getColor", optional_override([](SkPaint& self)->JSColor {
799 // JS side gives us a signed int instead of an unsigned int for color
800 // Add a optional_override to change it out.
801 return JSColor(self.getColor());
802 }))
Kevin Lubick0a1293c2018-12-03 12:31:04 -0500803 .function("getFilterQuality", &SkPaint::getFilterQuality)
Kevin Lubickb9db3902018-11-26 11:47:54 -0500804 .function("getStrokeCap", &SkPaint::getStrokeCap)
805 .function("getStrokeJoin", &SkPaint::getStrokeJoin)
Kevin Lubick0a1293c2018-12-03 12:31:04 -0500806 .function("getStrokeMiter", &SkPaint::getStrokeMiter)
807 .function("getStrokeWidth", &SkPaint::getStrokeWidth)
Kevin Lubick217056c2018-09-20 17:39:31 -0400808 .function("setAntiAlias", &SkPaint::setAntiAlias)
Kevin Lubick12c0e502018-11-28 12:51:56 -0500809 .function("setBlendMode", &SkPaint::setBlendMode)
Kevin Lubick217056c2018-09-20 17:39:31 -0400810 .function("setColor", optional_override([](SkPaint& self, JSColor color)->void {
811 // JS side gives us a signed int instead of an unsigned int for color
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400812 // Add a optional_override to change it out.
Kevin Lubick217056c2018-09-20 17:39:31 -0400813 self.setColor(SkColor(color));
814 }))
Kevin Lubick0a1293c2018-12-03 12:31:04 -0500815 .function("setFilterQuality", &SkPaint::setFilterQuality)
Kevin Lubick61ef7b22018-11-27 13:26:59 -0500816 .function("setMaskFilter", &SkPaint::setMaskFilter)
Kevin Lubick217056c2018-09-20 17:39:31 -0400817 .function("setPathEffect", &SkPaint::setPathEffect)
818 .function("setShader", &SkPaint::setShader)
Kevin Lubickb9db3902018-11-26 11:47:54 -0500819 .function("setStrokeCap", &SkPaint::setStrokeCap)
820 .function("setStrokeJoin", &SkPaint::setStrokeJoin)
Kevin Lubick0a1293c2018-12-03 12:31:04 -0500821 .function("setStrokeMiter", &SkPaint::setStrokeMiter)
822 .function("setStrokeWidth", &SkPaint::setStrokeWidth)
Kevin Lubickec4903d2019-01-14 08:36:08 -0500823 .function("setStyle", &SkPaint::setStyle);
Kevin Lubick217056c2018-09-20 17:39:31 -0400824
825 class_<SkPathEffect>("SkPathEffect")
826 .smart_ptr<sk_sp<SkPathEffect>>("sk_sp<SkPathEffect>");
827
Kevin Lubick217056c2018-09-20 17:39:31 -0400828 class_<SkPath>("SkPath")
829 .constructor<>()
830 .constructor<const SkPath&>()
Kevin Lubick1a05fce2018-11-20 12:51:16 -0500831 .function("_addArc", &ApplyAddArc)
Kevin Lubick217056c2018-09-20 17:39:31 -0400832 // interface.js has 3 overloads of addPath
833 .function("_addPath", &ApplyAddPath)
Kevin Lubick1a05fce2018-11-20 12:51:16 -0500834 // interface.js has 4 overloads of addRect
835 .function("_addRect", &ApplyAddRect)
Kevin Lubickda3d8ac2019-01-07 11:08:55 -0500836 // interface.js has 4 overloads of addRoundRect
837 .function("_addRoundRect", &ApplyAddRoundRect)
Kevin Lubick217056c2018-09-20 17:39:31 -0400838 .function("_arcTo", &ApplyArcTo)
Kevin Lubick1646e7d2018-12-07 13:03:08 -0500839 .function("_arcTo", &ApplyArcToAngle)
Kevin Lubick217056c2018-09-20 17:39:31 -0400840 .function("_close", &ApplyClose)
841 .function("_conicTo", &ApplyConicTo)
Kevin Lubickb9db3902018-11-26 11:47:54 -0500842 .function("countPoints", &SkPath::countPoints)
Kevin Lubick1646e7d2018-12-07 13:03:08 -0500843 .function("contains", &SkPath::contains)
Kevin Lubick217056c2018-09-20 17:39:31 -0400844 .function("_cubicTo", &ApplyCubicTo)
Kevin Lubickb9db3902018-11-26 11:47:54 -0500845 .function("getPoint", &SkPath::getPoint)
Kevin Lubick1646e7d2018-12-07 13:03:08 -0500846 .function("isEmpty", &SkPath::isEmpty)
Kevin Lubick2b79d1c2018-12-14 16:10:38 -0500847 .function("isVolatile", &SkPath::isVolatile)
Kevin Lubick217056c2018-09-20 17:39:31 -0400848 .function("_lineTo", &ApplyLineTo)
849 .function("_moveTo", &ApplyMoveTo)
Kevin Lubickda3d8ac2019-01-07 11:08:55 -0500850 .function("reset", &ApplyReset)
851 .function("rewind", &ApplyRewind)
Kevin Lubick217056c2018-09-20 17:39:31 -0400852 .function("_quadTo", &ApplyQuadTo)
Kevin Lubick2b79d1c2018-12-14 16:10:38 -0500853 .function("setIsVolatile", &SkPath::setIsVolatile)
Kevin Lubick1a05fce2018-11-20 12:51:16 -0500854 .function("_transform", select_overload<void(SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&ApplyTransform))
Kevin Lubick217056c2018-09-20 17:39:31 -0400855
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400856 // PathEffects
857 .function("_dash", &ApplyDash)
858 .function("_trim", &ApplyTrim)
859 .function("_stroke", &ApplyStroke)
860
861 // PathOps
862 .function("_simplify", &ApplySimplify)
863 .function("_op", &ApplyPathOp)
864
865 // Exporting
866 .function("toSVGString", &ToSVGString)
Kevin Lubickda3d8ac2019-01-07 11:08:55 -0500867 .function("toCmds", &ToCmds)
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400868
Kevin Lubick217056c2018-09-20 17:39:31 -0400869 .function("setFillType", &SkPath::setFillType)
870 .function("getFillType", &SkPath::getFillType)
871 .function("getBounds", &SkPath::getBounds)
872 .function("computeTightBounds", &SkPath::computeTightBounds)
873 .function("equals", &Equals)
Kevin Lubickb9db3902018-11-26 11:47:54 -0500874 .function("copy", &CopyPath)
875#ifdef SK_DEBUG
876 .function("dump", select_overload<void() const>(&SkPath::dump))
877 .function("dumpHex", select_overload<void() const>(&SkPath::dumpHex))
878#endif
879 ;
Kevin Lubick217056c2018-09-20 17:39:31 -0400880
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400881 class_<SkShader>("SkShader")
882 .smart_ptr<sk_sp<SkShader>>("sk_sp<SkShader>");
883
Kevin Lubick217056c2018-09-20 17:39:31 -0400884 class_<SkSurface>("SkSurface")
885 .smart_ptr<sk_sp<SkSurface>>("sk_sp<SkSurface>")
886 .function("width", &SkSurface::width)
887 .function("height", &SkSurface::height)
Kevin Lubick3d99b1e2018-10-16 10:15:01 -0400888 .function("_flush", &SkSurface::flush)
Mike Reed114bde82018-11-21 09:12:09 -0500889 .function("makeImageSnapshot", select_overload<sk_sp<SkImage>()>(&SkSurface::makeImageSnapshot))
890 .function("makeImageSnapshot", select_overload<sk_sp<SkImage>(const SkIRect& bounds)>(&SkSurface::makeImageSnapshot))
Kevin Lubick217056c2018-09-20 17:39:31 -0400891 .function("getCanvas", &SkSurface::getCanvas, allow_raw_pointers());
892
Kevin Lubickec4903d2019-01-14 08:36:08 -0500893 class_<SkTextBlob>("SkTextBlob")
894 .smart_ptr<sk_sp<SkTextBlob>>("sk_sp<SkTextBlob>>")
895 .class_function("_MakeFromText",optional_override([](uintptr_t /* char* */ sptr,
896 size_t len, const SkFont& font,
897 SkTextEncoding encoding)->sk_sp<SkTextBlob> {
898 // See comment above for uintptr_t explanation
899 const char* str = reinterpret_cast<const char*>(sptr);
900 return SkTextBlob::MakeFromText(str, len, font, encoding);
901 }), allow_raw_pointers());
902
903
Kevin Lubickddd0a332018-12-12 10:35:13 -0500904 class_<SkTypeface>("SkTypeface")
905 .smart_ptr<sk_sp<SkTypeface>>("sk_sp<SkTypeface>");
906
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400907 class_<SkVertices>("SkVertices")
908 .smart_ptr<sk_sp<SkVertices>>("sk_sp<SkVertices>")
909 .function("_applyBones", optional_override([](SkVertices& self, uintptr_t /* Bone* */ bptr, int boneCount)->sk_sp<SkVertices> {
910 // See comment above for uintptr_t explanation
911 const Bone* bones = reinterpret_cast<const Bone*>(bptr);
912 return self.applyBones(bones, boneCount);
913 }))
914 .function("bounds", &SkVertices::bounds)
915 .function("mode", &SkVertices::mode)
916 .function("uniqueID", &SkVertices::uniqueID)
Kevin Lubick12c0e502018-11-28 12:51:56 -0500917#ifdef SK_DEBUG
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400918 .function("dumpPositions", optional_override([](SkVertices& self)->void {
919 auto pos = self.positions();
920 for(int i = 0; i< self.vertexCount(); i++) {
921 SkDebugf("position[%d] = (%f, %f)\n", i, pos[i].x(), pos[i].y());
922 }
923 }))
Kevin Lubick12c0e502018-11-28 12:51:56 -0500924#endif
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400925 .function("vertexCount", &SkVertices::vertexCount);
926
Kevin Lubickea905ec2018-11-30 14:05:58 -0500927 enum_<SkAlphaType>("AlphaType")
928 .value("Opaque", SkAlphaType::kOpaque_SkAlphaType)
929 .value("Premul", SkAlphaType::kPremul_SkAlphaType)
930 .value("Unpremul", SkAlphaType::kUnpremul_SkAlphaType);
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400931
932 enum_<SkBlendMode>("BlendMode")
933 .value("Clear", SkBlendMode::kClear)
934 .value("Src", SkBlendMode::kSrc)
935 .value("Dst", SkBlendMode::kDst)
936 .value("SrcOver", SkBlendMode::kSrcOver)
937 .value("DstOver", SkBlendMode::kDstOver)
938 .value("SrcIn", SkBlendMode::kSrcIn)
939 .value("DstIn", SkBlendMode::kDstIn)
940 .value("SrcOut", SkBlendMode::kSrcOut)
941 .value("DstOut", SkBlendMode::kDstOut)
942 .value("SrcATop", SkBlendMode::kSrcATop)
943 .value("DstATop", SkBlendMode::kDstATop)
944 .value("Xor", SkBlendMode::kXor)
945 .value("Plus", SkBlendMode::kPlus)
946 .value("Modulate", SkBlendMode::kModulate)
947 .value("Screen", SkBlendMode::kScreen)
948 .value("Overlay", SkBlendMode::kOverlay)
949 .value("Darken", SkBlendMode::kDarken)
950 .value("Lighten", SkBlendMode::kLighten)
951 .value("ColorDodge", SkBlendMode::kColorDodge)
952 .value("ColorBurn", SkBlendMode::kColorBurn)
953 .value("HardLight", SkBlendMode::kHardLight)
954 .value("SoftLight", SkBlendMode::kSoftLight)
955 .value("Difference", SkBlendMode::kDifference)
956 .value("Exclusion", SkBlendMode::kExclusion)
957 .value("Multiply", SkBlendMode::kMultiply)
958 .value("Hue", SkBlendMode::kHue)
959 .value("Saturation", SkBlendMode::kSaturation)
960 .value("Color", SkBlendMode::kColor)
961 .value("Luminosity", SkBlendMode::kLuminosity);
Kevin Lubick217056c2018-09-20 17:39:31 -0400962
Kevin Lubick61ef7b22018-11-27 13:26:59 -0500963 enum_<SkBlurStyle>("BlurStyle")
964 .value("Normal", SkBlurStyle::kNormal_SkBlurStyle)
965 .value("Solid", SkBlurStyle::kSolid_SkBlurStyle)
966 .value("Outer", SkBlurStyle::kOuter_SkBlurStyle)
967 .value("Inner", SkBlurStyle::kInner_SkBlurStyle);
Kevin Lubick217056c2018-09-20 17:39:31 -0400968
Kevin Lubickeb2f6b02018-11-29 15:07:02 -0500969 enum_<SkClipOp>("ClipOp")
970 .value("Difference", SkClipOp::kDifference)
971 .value("Intersect", SkClipOp::kIntersect);
972
Kevin Lubickea905ec2018-11-30 14:05:58 -0500973 enum_<SkColorType>("ColorType")
974 .value("Alpha_8", SkColorType::kAlpha_8_SkColorType)
975 .value("RGB_565", SkColorType::kRGB_565_SkColorType)
976 .value("ARGB_4444", SkColorType::kARGB_4444_SkColorType)
977 .value("RGBA_8888", SkColorType::kRGBA_8888_SkColorType)
978 .value("RGB_888x", SkColorType::kRGB_888x_SkColorType)
979 .value("BGRA_8888", SkColorType::kBGRA_8888_SkColorType)
980 .value("RGBA_1010102", SkColorType::kRGBA_1010102_SkColorType)
981 .value("RGB_101010x", SkColorType::kRGB_101010x_SkColorType)
982 .value("Gray_8", SkColorType::kGray_8_SkColorType)
983 .value("RGBA_F16", SkColorType::kRGBA_F16_SkColorType)
984 .value("RGBA_F32", SkColorType::kRGBA_F32_SkColorType);
985
Kevin Lubick217056c2018-09-20 17:39:31 -0400986 enum_<SkPath::FillType>("FillType")
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400987 .value("Winding", SkPath::FillType::kWinding_FillType)
988 .value("EvenOdd", SkPath::FillType::kEvenOdd_FillType)
989 .value("InverseWinding", SkPath::FillType::kInverseWinding_FillType)
990 .value("InverseEvenOdd", SkPath::FillType::kInverseEvenOdd_FillType);
991
Kevin Lubick0a1293c2018-12-03 12:31:04 -0500992 enum_<SkFilterQuality>("FilterQuality")
993 .value("None", SkFilterQuality::kNone_SkFilterQuality)
994 .value("Low", SkFilterQuality::kLow_SkFilterQuality)
995 .value("Medium", SkFilterQuality::kMedium_SkFilterQuality)
996 .value("High", SkFilterQuality::kHigh_SkFilterQuality);
997
Kevin Lubick61ef7b22018-11-27 13:26:59 -0500998 enum_<SkEncodedImageFormat>("ImageFormat")
999 .value("PNG", SkEncodedImageFormat::kPNG)
1000 .value("JPEG", SkEncodedImageFormat::kJPEG);
1001
1002 enum_<SkPaint::Style>("PaintStyle")
1003 .value("Fill", SkPaint::Style::kFill_Style)
1004 .value("Stroke", SkPaint::Style::kStroke_Style)
1005 .value("StrokeAndFill", SkPaint::Style::kStrokeAndFill_Style);
1006
Kevin Lubickb5ae3b52018-11-03 07:51:19 -04001007 enum_<SkPathOp>("PathOp")
1008 .value("Difference", SkPathOp::kDifference_SkPathOp)
1009 .value("Intersect", SkPathOp::kIntersect_SkPathOp)
1010 .value("Union", SkPathOp::kUnion_SkPathOp)
1011 .value("XOR", SkPathOp::kXOR_SkPathOp)
1012 .value("ReverseDifference", SkPathOp::kReverseDifference_SkPathOp);
1013
Kevin Lubickb9db3902018-11-26 11:47:54 -05001014 enum_<SkPaint::Cap>("StrokeCap")
1015 .value("Butt", SkPaint::Cap::kButt_Cap)
1016 .value("Round", SkPaint::Cap::kRound_Cap)
1017 .value("Square", SkPaint::Cap::kSquare_Cap);
1018
1019 enum_<SkPaint::Join>("StrokeJoin")
1020 .value("Miter", SkPaint::Join::kMiter_Join)
1021 .value("Round", SkPaint::Join::kRound_Join)
1022 .value("Bevel", SkPaint::Join::kBevel_Join);
1023
Kevin Lubickec4903d2019-01-14 08:36:08 -05001024 enum_<SkTextEncoding>("TextEncoding")
1025 .value("UTF8", SkTextEncoding::kUTF8)
1026 .value("UTF16", SkTextEncoding::kUTF16)
1027 .value("UTF32", SkTextEncoding::kUTF32)
1028 .value("GlyphID", SkTextEncoding::kGlyphID);
Kevin Lubickb9db3902018-11-26 11:47:54 -05001029
Kevin Lubickb5ae3b52018-11-03 07:51:19 -04001030 enum_<SkShader::TileMode>("TileMode")
1031 .value("Clamp", SkShader::TileMode::kClamp_TileMode)
1032 .value("Repeat", SkShader::TileMode::kRepeat_TileMode)
Kevin Lubickd29edd72018-12-07 08:29:52 -05001033 .value("Mirror", SkShader::TileMode::kMirror_TileMode)
1034 // Decal mode only works in the SW backend, not WebGl (yet).
1035 .value("Decal", SkShader::TileMode::kDecal_TileMode);
Kevin Lubickb5ae3b52018-11-03 07:51:19 -04001036
1037 enum_<SkVertices::VertexMode>("VertexMode")
1038 .value("Triangles", SkVertices::VertexMode::kTriangles_VertexMode)
1039 .value("TrianglesStrip", SkVertices::VertexMode::kTriangleStrip_VertexMode)
Kevin Lubickb9db3902018-11-26 11:47:54 -05001040 .value("TriangleFan", SkVertices::VertexMode::kTriangleFan_VertexMode);
Kevin Lubickb5ae3b52018-11-03 07:51:19 -04001041
Kevin Lubick217056c2018-09-20 17:39:31 -04001042
1043 // A value object is much simpler than a class - it is returned as a JS
1044 // object and does not require delete().
1045 // https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html#value-types
1046 value_object<SkRect>("SkRect")
1047 .field("fLeft", &SkRect::fLeft)
1048 .field("fTop", &SkRect::fTop)
1049 .field("fRight", &SkRect::fRight)
1050 .field("fBottom", &SkRect::fBottom);
1051
Mike Reed114bde82018-11-21 09:12:09 -05001052 value_object<SkIRect>("SkIRect")
1053 .field("fLeft", &SkIRect::fLeft)
1054 .field("fTop", &SkIRect::fTop)
1055 .field("fRight", &SkIRect::fRight)
1056 .field("fBottom", &SkIRect::fBottom);
1057
Kevin Lubickea905ec2018-11-30 14:05:58 -05001058 value_object<SimpleImageInfo>("SkImageInfo")
1059 .field("width", &SimpleImageInfo::width)
1060 .field("height", &SimpleImageInfo::height)
1061 .field("colorType", &SimpleImageInfo::colorType)
1062 .field("alphaType", &SimpleImageInfo::alphaType);
1063
Kevin Lubick217056c2018-09-20 17:39:31 -04001064 // SkPoints can be represented by [x, y]
1065 value_array<SkPoint>("SkPoint")
1066 .element(&SkPoint::fX)
1067 .element(&SkPoint::fY);
1068
Kevin Lubick61ef7b22018-11-27 13:26:59 -05001069 // SkPoint3s can be represented by [x, y, z]
1070 value_array<SkPoint3>("SkPoint3")
1071 .element(&SkPoint3::fX)
1072 .element(&SkPoint3::fY)
1073 .element(&SkPoint3::fZ);
1074
Kevin Lubick217056c2018-09-20 17:39:31 -04001075 // {"w": Number, "h", Number}
1076 value_object<SkSize>("SkSize")
1077 .field("w", &SkSize::fWidth)
1078 .field("h", &SkSize::fHeight);
1079
1080 value_object<SkISize>("SkISize")
1081 .field("w", &SkISize::fWidth)
1082 .field("h", &SkISize::fHeight);
1083
Kevin Lubickec4903d2019-01-14 08:36:08 -05001084 value_object<StrokeOpts>("StrokeOpts")
1085 .field("width", &StrokeOpts::width)
1086 .field("miter_limit", &StrokeOpts::miter_limit)
1087 .field("join", &StrokeOpts::join)
1088 .field("cap", &StrokeOpts::cap)
1089 .field("precision", &StrokeOpts::precision);
1090
Kevin Lubickb5ae3b52018-11-03 07:51:19 -04001091 // Allows clients to supply a 1D array of 9 elements and the bindings
1092 // will automatically turn it into a 3x3 2D matrix.
1093 // e.g. path.transform([0,1,2,3,4,5,6,7,8])
1094 // This is likely simpler for the client than exposing SkMatrix
1095 // directly and requiring them to do a lot of .delete().
1096 value_array<SimpleMatrix>("SkMatrix")
1097 .element(&SimpleMatrix::scaleX)
1098 .element(&SimpleMatrix::skewX)
1099 .element(&SimpleMatrix::transX)
1100
1101 .element(&SimpleMatrix::skewY)
1102 .element(&SimpleMatrix::scaleY)
1103 .element(&SimpleMatrix::transY)
1104
1105 .element(&SimpleMatrix::pers0)
1106 .element(&SimpleMatrix::pers1)
1107 .element(&SimpleMatrix::pers2);
1108
1109 constant("TRANSPARENT", (JSColor) SK_ColorTRANSPARENT);
1110 constant("RED", (JSColor) SK_ColorRED);
1111 constant("BLUE", (JSColor) SK_ColorBLUE);
1112 constant("YELLOW", (JSColor) SK_ColorYELLOW);
1113 constant("CYAN", (JSColor) SK_ColorCYAN);
Kevin Lubick61ef7b22018-11-27 13:26:59 -05001114 constant("BLACK", (JSColor) SK_ColorBLACK);
Kevin Lubickea905ec2018-11-30 14:05:58 -05001115 constant("WHITE", (JSColor) SK_ColorWHITE);
Kevin Lubickb5ae3b52018-11-03 07:51:19 -04001116 // TODO(?)
1117
Kevin Lubickda3d8ac2019-01-07 11:08:55 -05001118 constant("MOVE_VERB", MOVE);
1119 constant("LINE_VERB", LINE);
1120 constant("QUAD_VERB", QUAD);
1121 constant("CONIC_VERB", CONIC);
1122 constant("CUBIC_VERB", CUBIC);
1123 constant("CLOSE_VERB", CLOSE);
Kevin Lubick217056c2018-09-20 17:39:31 -04001124}