blob: be9cab1a8354a18ef0f78dc2eed1d3c507f80e60 [file] [log] [blame]
Kevin Lubick217056c2018-09-20 17:39:31 -04001// Adds JS functions to augment the CanvasKit interface.
2// For example, if there is a wrapper around the C++ call or logic to allow
3// chaining, it should go here.
Kevin Lubickb5ae3b52018-11-03 07:51:19 -04004(function(CanvasKit) {
Kevin Lubick217056c2018-09-20 17:39:31 -04005 // CanvasKit.onRuntimeInitialized is called after the WASM library has loaded.
6 // Anything that modifies an exposed class (e.g. SkPath) should be set
7 // after onRuntimeInitialized, otherwise, it can happen outside of that scope.
8 CanvasKit.onRuntimeInitialized = function() {
9 // All calls to 'this' need to go in externs.js so closure doesn't minify them away.
10 CanvasKit.SkPath.prototype.addPath = function() {
11 // Takes 1, 2, or 10 args, where the first arg is always the path.
12 // The options for the remaining args are:
13 // - an array of 9 parameters
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040014 // - the 9 parameters of a full matrix
15 // an array of 6 parameters (omitting perspective)
16 // the 6 non-perspective params of a matrix.
Kevin Lubick217056c2018-09-20 17:39:31 -040017 if (arguments.length === 1) {
18 // Add path, unchanged. Use identify matrix
19 this._addPath(arguments[0], 1, 0, 0,
20 0, 1, 0,
21 0, 0, 1);
22 } else if (arguments.length === 2) {
23 // User provided the 9 params of a full matrix as an array.
24 var sm = arguments[1];
25 this._addPath(arguments[0], a[1], a[2], a[3],
26 a[4], a[5], a[6],
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040027 a[7] || 0, a[8] || 0, a[9] || 1);
28 } else if (arguments.length === 7 || arguments.length === 10) {
Kevin Lubick217056c2018-09-20 17:39:31 -040029 // User provided the 9 params of a (full) matrix directly.
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040030 // (or just the 6 non perspective ones)
Kevin Lubick217056c2018-09-20 17:39:31 -040031 // These are in the same order as what Skia expects.
32 var a = arguments;
33 this._addPath(arguments[0], a[1], a[2], a[3],
34 a[4], a[5], a[6],
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040035 a[7] || 0, a[8] || 0, a[9] || 1);
Kevin Lubick217056c2018-09-20 17:39:31 -040036 } else {
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040037 console.err('addPath expected to take 1, 2, 7, or 10 args. Got ' + arguments.length);
Kevin Lubick217056c2018-09-20 17:39:31 -040038 return null;
39 }
40 return this;
41 };
42
43 CanvasKit.SkPath.prototype.arcTo = function(x1, y1, x2, y2, radius) {
44 this._arcTo(x1, y1, x2, y2, radius);
45 return this;
46 };
47
48 CanvasKit.SkPath.prototype.close = function() {
49 this._close();
50 return this;
51 };
52
53 CanvasKit.SkPath.prototype.conicTo = function(x1, y1, x2, y2, w) {
54 this._conicTo(x1, y1, x2, y2, w);
55 return this;
56 };
57
58 CanvasKit.SkPath.prototype.cubicTo = function(cp1x, cp1y, cp2x, cp2y, x, y) {
59 this._cubicTo(cp1x, cp1y, cp2x, cp2y, x, y);
60 return this;
61 };
62
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040063 CanvasKit.SkPath.prototype.dash = function(on, off, phase) {
64 if (this._dash(on, off, phase)) {
65 return this;
66 }
67 return null;
68 };
69
Kevin Lubick217056c2018-09-20 17:39:31 -040070 CanvasKit.SkPath.prototype.lineTo = function(x, y) {
71 this._lineTo(x, y);
72 return this;
73 };
74
75 CanvasKit.SkPath.prototype.moveTo = function(x, y) {
76 this._moveTo(x, y);
77 return this;
78 };
79
80 CanvasKit.SkPath.prototype.op = function(otherPath, op) {
81 if (this._op(otherPath, op)) {
82 return this;
83 }
84 return null;
85 };
86
87 CanvasKit.SkPath.prototype.quadTo = function(cpx, cpy, x, y) {
88 this._quadTo(cpx, cpy, x, y);
89 return this;
90 };
91
92 CanvasKit.SkPath.prototype.simplify = function() {
93 if (this._simplify()) {
94 return this;
95 }
96 return null;
97 };
98
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040099 CanvasKit.SkPath.prototype.stroke = function(opts) {
100 // Fill out any missing values with the default values.
101 /**
102 * See externs.js for this definition
103 * @type {StrokeOpts}
104 */
105 opts = opts || {};
106 opts.width = opts.width || 1;
107 opts.miter_limit = opts.miter_limit || 4;
108 opts.cap = opts.cap || CanvasKit.StrokeCap.BUTT;
109 opts.join = opts.join || CanvasKit.StrokeJoin.MITER;
110 if (this._stroke(opts)) {
111 return this;
112 }
113 return null;
114 };
115
Kevin Lubick217056c2018-09-20 17:39:31 -0400116 CanvasKit.SkPath.prototype.transform = function() {
117 // Takes 1 or 9 args
118 if (arguments.length === 1) {
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400119 // argument 1 should be a 6 or 9 element array.
Kevin Lubick217056c2018-09-20 17:39:31 -0400120 var a = arguments[0];
121 this._transform(a[0], a[1], a[2],
122 a[3], a[4], a[5],
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400123 a[6] || 0, a[7] || 0, a[8] || 1);
124 } else if (arguments.length === 6 || arguments.length === 9) {
125 // these arguments are the 6 or 9 members of the matrix
Kevin Lubick217056c2018-09-20 17:39:31 -0400126 var a = arguments;
127 this._transform(a[0], a[1], a[2],
128 a[3], a[4], a[5],
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400129 a[6] || 0, a[7] || 0, a[8] || 1);
Kevin Lubick217056c2018-09-20 17:39:31 -0400130 } else {
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400131 throw 'transform expected to take 1 or 9 arguments. Got ' + arguments.length;
Kevin Lubick217056c2018-09-20 17:39:31 -0400132 }
133 return this;
134 };
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400135 // isComplement is optional, defaults to false
136 CanvasKit.SkPath.prototype.trim = function(startT, stopT, isComplement) {
137 if (this._trim(startT, stopT, !!isComplement)) {
138 return this;
139 }
140 return null;
141 };
142
143 // bones should be a 3d array.
144 // Each bone is a 3x2 transformation matrix in column major order:
145 // | scaleX skewX transX |
146 // | skewY scaleY transY |
147 // and bones is an array of those matrices.
148 // Returns a copy of this (SkVertices) with the bones applied.
149 CanvasKit.SkVertices.prototype.applyBones = function(bones) {
150 var bPtr = copy3dArray(bones, CanvasKit.HEAPF32);
151 var vert = this._applyBones(bPtr, bones.length);
152 CanvasKit._free(bPtr);
153 return vert;
154 }
Kevin Lubick53965c92018-10-11 08:51:55 -0400155
Kevin Lubick5b90b842018-10-17 07:57:18 -0400156 // Run through the JS files that are added at compile time.
157 if (CanvasKit._extraInitializations) {
158 CanvasKit._extraInitializations.forEach(function(init) {
159 init();
160 });
Kevin Lubick217056c2018-09-20 17:39:31 -0400161 }
Kevin Lubick3d99b1e2018-10-16 10:15:01 -0400162 } // end CanvasKit.onRuntimeInitialized, that is, anything changing prototypes or dynamic.
Kevin Lubick53965c92018-10-11 08:51:55 -0400163
Kevin Lubick217056c2018-09-20 17:39:31 -0400164 // Likely only used for tests.
165 CanvasKit.LTRBRect = function(l, t, r, b) {
166 return {
167 fLeft: l,
168 fTop: t,
169 fRight: r,
170 fBottom: b,
171 };
172 }
173
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400174 var nullptr = 0; // emscripten doesn't like to take null as uintptr_t
175
176 // arr can be a normal JS array or a TypedArray
177 // dest is something like CanvasKit.HEAPF32
178 function copy1dArray(arr, dest) {
179 if (!arr || !arr.length) {
180 return nullptr;
181 }
182 var ptr = CanvasKit._malloc(arr.length * dest.BYTES_PER_ELEMENT);
183 // In c++ terms, the WASM heap is a uint8_t*, a long buffer/array of single
184 // byte elements. When we run _malloc, we always get an offset/pointer into
185 // that block of memory.
186 // CanvasKit exposes some different views to make it easier to work with
187 // different types. HEAPF32 for example, exposes it as a float*
188 // However, to make the ptr line up, we have to do some pointer arithmetic.
189 // Concretely, we need to convert ptr to go from an index into a 1-byte-wide
190 // buffer to an index into a 4-byte-wide buffer (in the case of HEAPF32)
191 // and thus we divide ptr by 4.
192 dest.set(arr, ptr / dest.BYTES_PER_ELEMENT);
193 return ptr;
194 }
195
196 // arr should be a non-jagged 2d JS array (TypeyArrays can't be nested
197 // inside themselves.)
198 // dest is something like CanvasKit.HEAPF32
199 function copy2dArray(arr, dest) {
200 if (!arr || !arr.length) {
201 return nullptr;
202 }
203 var ptr = CanvasKit._malloc(arr.length * arr[0].length * dest.BYTES_PER_ELEMENT);
204 var idx = 0;
205 var adjustedPtr = ptr / dest.BYTES_PER_ELEMENT;
206 for (var r = 0; r < arr.length; r++) {
207 for (var c = 0; c < arr[0].length; c++) {
208 dest[adjustedPtr + idx] = arr[r][c];
209 idx++;
210 }
211 }
212 return ptr;
213 }
214
215 // arr should be a non-jagged 3d JS array (TypeyArrays can't be nested
216 // inside themselves.)
217 // dest is something like CanvasKit.HEAPF32
218 function copy3dArray(arr, dest) {
219 if (!arr || !arr.length || !arr[0].length) {
220 return nullptr;
221 }
222 var ptr = CanvasKit._malloc(arr.length * arr[0].length * arr[0][0].length * dest.BYTES_PER_ELEMENT);
223 var idx = 0;
224 var adjustedPtr = ptr / dest.BYTES_PER_ELEMENT;
225 for (var x = 0; x < arr.length; x++) {
226 for (var y = 0; y < arr[0].length; y++) {
227 for (var z = 0; z < arr[0][0].length; z++) {
228 dest[adjustedPtr + idx] = arr[x][y][z];
229 idx++;
230 }
231 }
232 }
233 return ptr;
234 }
235
Kevin Lubick217056c2018-09-20 17:39:31 -0400236 CanvasKit.MakeSkDashPathEffect = function(intervals, phase) {
237 if (!phase) {
238 phase = 0;
239 }
240 if (!intervals.length || intervals.length % 2 === 1) {
241 throw 'Intervals array must have even length';
242 }
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400243 var ptr = copy1dArray(intervals, CanvasKit.HEAPF32);
244 var dpe = CanvasKit._MakeSkDashPathEffect(ptr, intervals.length, phase);
245 CanvasKit._free(ptr);
246 return dpe;
247 }
248
249 CanvasKit.MakeImageShader = function(imgData, xTileMode, yTileMode) {
250 var iptr = CanvasKit._malloc(imgData.byteLength);
251 CanvasKit.HEAPU8.set(new Uint8Array(imgData), iptr);
252 // No need to _free iptr, ImageShader takes it with SkData::MakeFromMalloc
253
254 return CanvasKit._MakeImageShader(iptr, imgData.byteLength, xTileMode, yTileMode);
255 }
256
257 CanvasKit.MakeLinearGradientShader = function(start, end, colors, pos, mode, localMatrix, flags) {
258 var colorPtr = copy1dArray(colors, CanvasKit.HEAP32);
259 var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
260 flags = flags || 0;
261
262 if (localMatrix) {
263 // Add perspective args if not provided.
264 if (localMatrix.length === 6) {
265 localMatrix.push(0, 0, 1);
266 }
267 var lgs = CanvasKit._MakeLinearGradientShader(start, end, colorPtr, posPtr,
268 colors.length, mode, flags, localMatrix);
269 } else {
270 var lgs = CanvasKit._MakeLinearGradientShader(start, end, colorPtr, posPtr,
271 colors.length, mode, flags);
Kevin Lubick217056c2018-09-20 17:39:31 -0400272 }
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400273
274 CanvasKit._free(colorPtr);
275 CanvasKit._free(posPtr);
276 return lgs;
277 }
278
279 CanvasKit.MakeRadialGradientShader = function(center, radius, colors, pos, mode, localMatrix, flags) {
280 // TODO: matrix and flags
281 var colorPtr = copy1dArray(colors, CanvasKit.HEAP32);
282 var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
283 flags = flags || 0;
284
285 if (localMatrix) {
286 // Add perspective args if not provided.
287 if (localMatrix.length === 6) {
288 localMatrix.push(0, 0, 1);
289 }
290 var rgs = CanvasKit._MakeRadialGradientShader(center, radius, colorPtr, posPtr,
291 colors.length, mode, flags, localMatrix);
292 } else {
293 var rgs = CanvasKit._MakeRadialGradientShader(center, radius, colorPtr, posPtr,
294 colors.length, mode, flags);
295 }
296
297 CanvasKit._free(colorPtr);
298 CanvasKit._free(posPtr);
299 return rgs;
300 }
301
302 CanvasKit.MakeSkVertices = function(mode, positions, textureCoordinates, colors,
303 boneIndices, boneWeights, indices) {
304 var positionPtr = copy2dArray(positions, CanvasKit.HEAPF32);
305 var texPtr = copy2dArray(textureCoordinates, CanvasKit.HEAPF32);
306 // Since we write the colors to memory as signed integers (JSColor), we can
307 // read them out on the other side as unsigned ints (SkColor) just fine
308 // - it's effectively casting.
309 var colorPtr = copy1dArray(colors, CanvasKit.HEAP32);
310
311 var boneIdxPtr = copy2dArray(boneIndices, CanvasKit.HEAP32);
312 var boneWtPtr = copy2dArray(boneWeights, CanvasKit.HEAPF32);
313 var idxPtr = copy1dArray(indices, CanvasKit.HEAPU16);
314
315 var idxCount = (indices && indices.length) || 0;
316 // _MakeVertices will copy all the values in, so we are free to release
317 // the memory after.
318 var vertices = CanvasKit._MakeSkVertices(mode, positions.length, positionPtr,
319 texPtr, colorPtr, boneIdxPtr, boneWtPtr,
320 idxCount, idxPtr);
321 positionPtr && CanvasKit._free(positionPtr);
322 texPtr && CanvasKit._free(texPtr);
323 colorPtr && CanvasKit._free(colorPtr);
324 idxPtr && CanvasKit._free(idxPtr);
325 boneIdxPtr && CanvasKit._free(boneIdxPtr);
326 boneWtPtr && CanvasKit._free(boneWtPtr);
327 return vertices;
Kevin Lubick217056c2018-09-20 17:39:31 -0400328 }
329
Kevin Lubick134be1d2018-10-30 15:05:04 -0400330 CanvasKit.MakeNimaActor = function(nimaFile, nimaTexture) {
331 var nptr = CanvasKit._malloc(nimaFile.byteLength);
332 CanvasKit.HEAPU8.set(new Uint8Array(nimaFile), nptr);
333 var tptr = CanvasKit._malloc(nimaTexture.byteLength);
334 CanvasKit.HEAPU8.set(new Uint8Array(nimaTexture), tptr);
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400335 // No need to _free these ptrs, NimaActor takes them with SkData::MakeFromMalloc
Kevin Lubick134be1d2018-10-30 15:05:04 -0400336
337 return CanvasKit._MakeNimaActor(nptr, nimaFile.byteLength, tptr, nimaTexture.byteLength);
338 }
339
Kevin Lubick217056c2018-09-20 17:39:31 -0400340}(Module)); // When this file is loaded in, the high level object is "Module";