blob: b6713698909b3a47d869598a1625a4969cfc92cb [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
Alexander Khovansky3e119332018-11-15 02:01:19 +030043 CanvasKit.SkPath.prototype.arc = function(x, y, radius, startAngle, endAngle, ccw) {
44 this._arc(x, y, radius, startAngle, endAngle, !!ccw);
45 return this;
46 };
47
Kevin Lubick217056c2018-09-20 17:39:31 -040048 CanvasKit.SkPath.prototype.arcTo = function(x1, y1, x2, y2, radius) {
49 this._arcTo(x1, y1, x2, y2, radius);
50 return this;
51 };
52
53 CanvasKit.SkPath.prototype.close = function() {
54 this._close();
55 return this;
56 };
57
58 CanvasKit.SkPath.prototype.conicTo = function(x1, y1, x2, y2, w) {
59 this._conicTo(x1, y1, x2, y2, w);
60 return this;
61 };
62
63 CanvasKit.SkPath.prototype.cubicTo = function(cp1x, cp1y, cp2x, cp2y, x, y) {
64 this._cubicTo(cp1x, cp1y, cp2x, cp2y, x, y);
65 return this;
66 };
67
Kevin Lubickb5ae3b52018-11-03 07:51:19 -040068 CanvasKit.SkPath.prototype.dash = function(on, off, phase) {
69 if (this._dash(on, off, phase)) {
70 return this;
71 }
72 return null;
73 };
74
Kevin Lubick217056c2018-09-20 17:39:31 -040075 CanvasKit.SkPath.prototype.lineTo = function(x, y) {
76 this._lineTo(x, y);
77 return this;
78 };
79
80 CanvasKit.SkPath.prototype.moveTo = function(x, y) {
81 this._moveTo(x, y);
82 return this;
83 };
84
85 CanvasKit.SkPath.prototype.op = function(otherPath, op) {
86 if (this._op(otherPath, op)) {
87 return this;
88 }
89 return null;
90 };
91
92 CanvasKit.SkPath.prototype.quadTo = function(cpx, cpy, x, y) {
93 this._quadTo(cpx, cpy, x, y);
94 return this;
95 };
96
97 CanvasKit.SkPath.prototype.simplify = function() {
98 if (this._simplify()) {
99 return this;
100 }
101 return null;
102 };
103
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400104 CanvasKit.SkPath.prototype.stroke = function(opts) {
105 // Fill out any missing values with the default values.
106 /**
107 * See externs.js for this definition
108 * @type {StrokeOpts}
109 */
110 opts = opts || {};
111 opts.width = opts.width || 1;
112 opts.miter_limit = opts.miter_limit || 4;
113 opts.cap = opts.cap || CanvasKit.StrokeCap.BUTT;
114 opts.join = opts.join || CanvasKit.StrokeJoin.MITER;
115 if (this._stroke(opts)) {
116 return this;
117 }
118 return null;
119 };
120
Kevin Lubick217056c2018-09-20 17:39:31 -0400121 CanvasKit.SkPath.prototype.transform = function() {
122 // Takes 1 or 9 args
123 if (arguments.length === 1) {
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400124 // argument 1 should be a 6 or 9 element array.
Kevin Lubick217056c2018-09-20 17:39:31 -0400125 var a = arguments[0];
126 this._transform(a[0], a[1], a[2],
127 a[3], a[4], a[5],
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400128 a[6] || 0, a[7] || 0, a[8] || 1);
129 } else if (arguments.length === 6 || arguments.length === 9) {
130 // these arguments are the 6 or 9 members of the matrix
Kevin Lubick217056c2018-09-20 17:39:31 -0400131 var a = arguments;
132 this._transform(a[0], a[1], a[2],
133 a[3], a[4], a[5],
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400134 a[6] || 0, a[7] || 0, a[8] || 1);
Kevin Lubick217056c2018-09-20 17:39:31 -0400135 } else {
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400136 throw 'transform expected to take 1 or 9 arguments. Got ' + arguments.length;
Kevin Lubick217056c2018-09-20 17:39:31 -0400137 }
138 return this;
139 };
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400140 // isComplement is optional, defaults to false
141 CanvasKit.SkPath.prototype.trim = function(startT, stopT, isComplement) {
142 if (this._trim(startT, stopT, !!isComplement)) {
143 return this;
144 }
145 return null;
146 };
147
148 // bones should be a 3d array.
149 // Each bone is a 3x2 transformation matrix in column major order:
150 // | scaleX skewX transX |
151 // | skewY scaleY transY |
152 // and bones is an array of those matrices.
153 // Returns a copy of this (SkVertices) with the bones applied.
154 CanvasKit.SkVertices.prototype.applyBones = function(bones) {
155 var bPtr = copy3dArray(bones, CanvasKit.HEAPF32);
156 var vert = this._applyBones(bPtr, bones.length);
157 CanvasKit._free(bPtr);
158 return vert;
159 }
Kevin Lubick53965c92018-10-11 08:51:55 -0400160
Alexander Khovansky3e119332018-11-15 02:01:19 +0300161 CanvasKit.SkImage.prototype.encodeToData = function() {
162 if (arguments.length === 0) {
163 return this._encodeToData();
164 }
165
166 if (arguments.length === 2) {
167 var a = arguments;
168 return this._encodeToDataWithFormat(a[0], a[1]);
169 }
170
171 throw 'encodeToData expected to take 0 or 2 arguments. Got ' + arguments.length;
172 }
173
Kevin Lubick5b90b842018-10-17 07:57:18 -0400174 // Run through the JS files that are added at compile time.
175 if (CanvasKit._extraInitializations) {
176 CanvasKit._extraInitializations.forEach(function(init) {
177 init();
178 });
Kevin Lubick217056c2018-09-20 17:39:31 -0400179 }
Kevin Lubick3d99b1e2018-10-16 10:15:01 -0400180 } // end CanvasKit.onRuntimeInitialized, that is, anything changing prototypes or dynamic.
Kevin Lubick53965c92018-10-11 08:51:55 -0400181
Kevin Lubick217056c2018-09-20 17:39:31 -0400182 // Likely only used for tests.
183 CanvasKit.LTRBRect = function(l, t, r, b) {
184 return {
185 fLeft: l,
186 fTop: t,
187 fRight: r,
188 fBottom: b,
189 };
190 }
191
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400192 var nullptr = 0; // emscripten doesn't like to take null as uintptr_t
193
194 // arr can be a normal JS array or a TypedArray
195 // dest is something like CanvasKit.HEAPF32
196 function copy1dArray(arr, dest) {
197 if (!arr || !arr.length) {
198 return nullptr;
199 }
200 var ptr = CanvasKit._malloc(arr.length * dest.BYTES_PER_ELEMENT);
201 // In c++ terms, the WASM heap is a uint8_t*, a long buffer/array of single
202 // byte elements. When we run _malloc, we always get an offset/pointer into
203 // that block of memory.
204 // CanvasKit exposes some different views to make it easier to work with
205 // different types. HEAPF32 for example, exposes it as a float*
206 // However, to make the ptr line up, we have to do some pointer arithmetic.
207 // Concretely, we need to convert ptr to go from an index into a 1-byte-wide
208 // buffer to an index into a 4-byte-wide buffer (in the case of HEAPF32)
209 // and thus we divide ptr by 4.
210 dest.set(arr, ptr / dest.BYTES_PER_ELEMENT);
211 return ptr;
212 }
213
214 // arr should be a non-jagged 2d JS array (TypeyArrays can't be nested
215 // inside themselves.)
216 // dest is something like CanvasKit.HEAPF32
217 function copy2dArray(arr, dest) {
218 if (!arr || !arr.length) {
219 return nullptr;
220 }
221 var ptr = CanvasKit._malloc(arr.length * arr[0].length * dest.BYTES_PER_ELEMENT);
222 var idx = 0;
223 var adjustedPtr = ptr / dest.BYTES_PER_ELEMENT;
224 for (var r = 0; r < arr.length; r++) {
225 for (var c = 0; c < arr[0].length; c++) {
226 dest[adjustedPtr + idx] = arr[r][c];
227 idx++;
228 }
229 }
230 return ptr;
231 }
232
233 // arr should be a non-jagged 3d JS array (TypeyArrays can't be nested
234 // inside themselves.)
235 // dest is something like CanvasKit.HEAPF32
236 function copy3dArray(arr, dest) {
237 if (!arr || !arr.length || !arr[0].length) {
238 return nullptr;
239 }
240 var ptr = CanvasKit._malloc(arr.length * arr[0].length * arr[0][0].length * dest.BYTES_PER_ELEMENT);
241 var idx = 0;
242 var adjustedPtr = ptr / dest.BYTES_PER_ELEMENT;
243 for (var x = 0; x < arr.length; x++) {
244 for (var y = 0; y < arr[0].length; y++) {
245 for (var z = 0; z < arr[0][0].length; z++) {
246 dest[adjustedPtr + idx] = arr[x][y][z];
247 idx++;
248 }
249 }
250 }
251 return ptr;
252 }
253
Kevin Lubick217056c2018-09-20 17:39:31 -0400254 CanvasKit.MakeSkDashPathEffect = function(intervals, phase) {
255 if (!phase) {
256 phase = 0;
257 }
258 if (!intervals.length || intervals.length % 2 === 1) {
259 throw 'Intervals array must have even length';
260 }
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400261 var ptr = copy1dArray(intervals, CanvasKit.HEAPF32);
262 var dpe = CanvasKit._MakeSkDashPathEffect(ptr, intervals.length, phase);
263 CanvasKit._free(ptr);
264 return dpe;
265 }
266
267 CanvasKit.MakeImageShader = function(imgData, xTileMode, yTileMode) {
268 var iptr = CanvasKit._malloc(imgData.byteLength);
269 CanvasKit.HEAPU8.set(new Uint8Array(imgData), iptr);
270 // No need to _free iptr, ImageShader takes it with SkData::MakeFromMalloc
271
272 return CanvasKit._MakeImageShader(iptr, imgData.byteLength, xTileMode, yTileMode);
273 }
274
275 CanvasKit.MakeLinearGradientShader = function(start, end, colors, pos, mode, localMatrix, flags) {
276 var colorPtr = copy1dArray(colors, CanvasKit.HEAP32);
277 var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
278 flags = flags || 0;
279
280 if (localMatrix) {
281 // Add perspective args if not provided.
282 if (localMatrix.length === 6) {
283 localMatrix.push(0, 0, 1);
284 }
285 var lgs = CanvasKit._MakeLinearGradientShader(start, end, colorPtr, posPtr,
286 colors.length, mode, flags, localMatrix);
287 } else {
288 var lgs = CanvasKit._MakeLinearGradientShader(start, end, colorPtr, posPtr,
289 colors.length, mode, flags);
Kevin Lubick217056c2018-09-20 17:39:31 -0400290 }
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400291
292 CanvasKit._free(colorPtr);
293 CanvasKit._free(posPtr);
294 return lgs;
295 }
296
297 CanvasKit.MakeRadialGradientShader = function(center, radius, colors, pos, mode, localMatrix, flags) {
298 // TODO: matrix and flags
299 var colorPtr = copy1dArray(colors, CanvasKit.HEAP32);
300 var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
301 flags = flags || 0;
302
303 if (localMatrix) {
304 // Add perspective args if not provided.
305 if (localMatrix.length === 6) {
306 localMatrix.push(0, 0, 1);
307 }
308 var rgs = CanvasKit._MakeRadialGradientShader(center, radius, colorPtr, posPtr,
309 colors.length, mode, flags, localMatrix);
310 } else {
311 var rgs = CanvasKit._MakeRadialGradientShader(center, radius, colorPtr, posPtr,
312 colors.length, mode, flags);
313 }
314
315 CanvasKit._free(colorPtr);
316 CanvasKit._free(posPtr);
317 return rgs;
318 }
319
320 CanvasKit.MakeSkVertices = function(mode, positions, textureCoordinates, colors,
321 boneIndices, boneWeights, indices) {
322 var positionPtr = copy2dArray(positions, CanvasKit.HEAPF32);
323 var texPtr = copy2dArray(textureCoordinates, CanvasKit.HEAPF32);
324 // Since we write the colors to memory as signed integers (JSColor), we can
325 // read them out on the other side as unsigned ints (SkColor) just fine
326 // - it's effectively casting.
327 var colorPtr = copy1dArray(colors, CanvasKit.HEAP32);
328
329 var boneIdxPtr = copy2dArray(boneIndices, CanvasKit.HEAP32);
330 var boneWtPtr = copy2dArray(boneWeights, CanvasKit.HEAPF32);
331 var idxPtr = copy1dArray(indices, CanvasKit.HEAPU16);
332
333 var idxCount = (indices && indices.length) || 0;
334 // _MakeVertices will copy all the values in, so we are free to release
335 // the memory after.
336 var vertices = CanvasKit._MakeSkVertices(mode, positions.length, positionPtr,
337 texPtr, colorPtr, boneIdxPtr, boneWtPtr,
338 idxCount, idxPtr);
339 positionPtr && CanvasKit._free(positionPtr);
340 texPtr && CanvasKit._free(texPtr);
341 colorPtr && CanvasKit._free(colorPtr);
342 idxPtr && CanvasKit._free(idxPtr);
343 boneIdxPtr && CanvasKit._free(boneIdxPtr);
344 boneWtPtr && CanvasKit._free(boneWtPtr);
345 return vertices;
Kevin Lubick217056c2018-09-20 17:39:31 -0400346 }
347
Kevin Lubick134be1d2018-10-30 15:05:04 -0400348 CanvasKit.MakeNimaActor = function(nimaFile, nimaTexture) {
349 var nptr = CanvasKit._malloc(nimaFile.byteLength);
350 CanvasKit.HEAPU8.set(new Uint8Array(nimaFile), nptr);
351 var tptr = CanvasKit._malloc(nimaTexture.byteLength);
352 CanvasKit.HEAPU8.set(new Uint8Array(nimaTexture), tptr);
Kevin Lubickb5ae3b52018-11-03 07:51:19 -0400353 // No need to _free these ptrs, NimaActor takes them with SkData::MakeFromMalloc
Kevin Lubick134be1d2018-10-30 15:05:04 -0400354
355 return CanvasKit._MakeNimaActor(nptr, nimaFile.byteLength, tptr, nimaTexture.byteLength);
356 }
357
Kevin Lubick217056c2018-09-20 17:39:31 -0400358}(Module)); // When this file is loaded in, the high level object is "Module";