• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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.
4
5// CanvasKit.onRuntimeInitialized is called after the WASM library has loaded.
6// Anything that modifies an exposed class (e.g. Path) should be set
7// after onRuntimeInitialized, otherwise, it can happen outside of that scope.
8CanvasKit.onRuntimeInitialized = function() {
9  // All calls to 'this' need to go in externs.js so closure doesn't minify them away.
10
11  _scratchColor = CanvasKit.Malloc(Float32Array, 4); // 4 color scalars.
12  _scratchColorPtr = _scratchColor['byteOffset'];
13
14  _scratch4x4Matrix = CanvasKit.Malloc(Float32Array, 16); // 16 matrix scalars.
15  _scratch4x4MatrixPtr = _scratch4x4Matrix['byteOffset'];
16
17  _scratch3x3Matrix = CanvasKit.Malloc(Float32Array, 9); // 9 matrix scalars.
18  _scratch3x3MatrixPtr = _scratch3x3Matrix['byteOffset'];
19
20  _scratchRRect = CanvasKit.Malloc(Float32Array, 12); // 4 scalars for rrect, 8 for radii.
21  _scratchRRectPtr = _scratchRRect['byteOffset'];
22
23  _scratchRRect2 = CanvasKit.Malloc(Float32Array, 12); // 4 scalars for rrect, 8 for radii.
24  _scratchRRect2Ptr = _scratchRRect2['byteOffset'];
25
26  _scratchFourFloatsA = CanvasKit.Malloc(Float32Array, 4);
27  _scratchFourFloatsAPtr = _scratchFourFloatsA['byteOffset'];
28
29  _scratchFourFloatsB = CanvasKit.Malloc(Float32Array, 4);
30  _scratchFourFloatsBPtr = _scratchFourFloatsB['byteOffset'];
31
32  _scratchThreeFloatsA = CanvasKit.Malloc(Float32Array, 3); // 3 floats to represent SkVector3
33  _scratchThreeFloatsAPtr = _scratchThreeFloatsA['byteOffset'];
34
35  _scratchThreeFloatsB = CanvasKit.Malloc(Float32Array, 3); // 3 floats to represent SkVector3
36  _scratchThreeFloatsBPtr = _scratchThreeFloatsB['byteOffset'];
37
38  _scratchIRect = CanvasKit.Malloc(Int32Array, 4);
39  _scratchIRectPtr = _scratchIRect['byteOffset'];
40
41  // Create single copies of all three supported color spaces
42  // These are sk_sp<ColorSpace>
43  CanvasKit.ColorSpace.SRGB = CanvasKit.ColorSpace._MakeSRGB();
44  CanvasKit.ColorSpace.DISPLAY_P3 = CanvasKit.ColorSpace._MakeDisplayP3();
45  CanvasKit.ColorSpace.ADOBE_RGB = CanvasKit.ColorSpace._MakeAdobeRGB();
46
47  // Use quotes to tell closure compiler not to minify the names
48  CanvasKit['GlyphRunFlags'] = {
49    'IsWhiteSpace': CanvasKit['_GlyphRunFlags_isWhiteSpace'],
50  };
51
52  CanvasKit.Path.MakeFromCmds = function(cmds) {
53    var cmdPtr = copy1dArray(cmds, 'HEAPF32');
54    var path = CanvasKit.Path._MakeFromCmds(cmdPtr, cmds.length);
55    freeArraysThatAreNotMallocedByUsers(cmdPtr, cmds);
56    return path;
57  };
58
59  // The weights array is optional (only used for conics).
60  CanvasKit.Path.MakeFromVerbsPointsWeights = function(verbs, pts, weights) {
61    var verbsPtr = copy1dArray(verbs, 'HEAPU8');
62    var pointsPtr = copy1dArray(pts, 'HEAPF32');
63    var weightsPtr = copy1dArray(weights, 'HEAPF32');
64    var numWeights = (weights && weights.length) || 0;
65    var path = CanvasKit.Path._MakeFromVerbsPointsWeights(
66        verbsPtr, verbs.length, pointsPtr, pts.length, weightsPtr, numWeights);
67    freeArraysThatAreNotMallocedByUsers(verbsPtr, verbs);
68    freeArraysThatAreNotMallocedByUsers(pointsPtr, pts);
69    freeArraysThatAreNotMallocedByUsers(weightsPtr, weights);
70    return path;
71  };
72
73  CanvasKit.Path.prototype.addArc = function(oval, startAngle, sweepAngle) {
74    // see arc() for the HTMLCanvas version
75    // note input angles are degrees.
76    var oPtr = copyRectToWasm(oval);
77    this._addArc(oPtr, startAngle, sweepAngle);
78    return this;
79  };
80
81  CanvasKit.Path.prototype.addOval = function(oval, isCCW, startIndex) {
82    if (startIndex === undefined) {
83      startIndex = 1;
84    }
85    var oPtr = copyRectToWasm(oval);
86    this._addOval(oPtr, !!isCCW, startIndex);
87    return this;
88  };
89
90  // TODO(kjlubick) clean up this API - split it apart if necessary
91  CanvasKit.Path.prototype.addPath = function() {
92    // Takes 1, 2, 7, or 10 required args, where the first arg is always the path.
93    // The last arg is optional and chooses between add or extend mode.
94    // The options for the remaining args are:
95    //   - an array of 6 or 9 parameters (perspective is optional)
96    //   - the 9 parameters of a full matrix or
97    //     the 6 non-perspective params of a matrix.
98    var args = Array.prototype.slice.call(arguments);
99    var path = args[0];
100    var extend = false;
101    if (typeof args[args.length-1] === 'boolean') {
102      extend = args.pop();
103    }
104    if (args.length === 1) {
105      // Add path, unchanged.  Use identity matrix
106      this._addPath(path, 1, 0, 0,
107                          0, 1, 0,
108                          0, 0, 1,
109                          extend);
110    } else if (args.length === 2) {
111      // User provided the 9 params of a full matrix as an array.
112      var a = args[1];
113      this._addPath(path, a[0],      a[1],      a[2],
114                          a[3],      a[4],      a[5],
115                          a[6] || 0, a[7] || 0, a[8] || 1,
116                          extend);
117    } else if (args.length === 7 || args.length === 10) {
118      // User provided the 9 params of a (full) matrix directly.
119      // (or just the 6 non perspective ones)
120      // These are in the same order as what Skia expects.
121      var a = args;
122      this._addPath(path, a[1],      a[2],      a[3],
123                          a[4],      a[5],      a[6],
124                          a[7] || 0, a[8] || 0, a[9] || 1,
125                          extend);
126    } else {
127      Debug('addPath expected to take 1, 2, 7, or 10 required args. Got ' + args.length);
128      return null;
129    }
130    return this;
131  };
132
133  // points is a 1d array of length 2n representing n points where the even indices
134  // will be treated as x coordinates and the odd indices will be treated as y coordinates.
135  // Like other APIs, this accepts a malloced type array or malloc obj.
136  CanvasKit.Path.prototype.addPoly = function(points, close) {
137    var ptr = copy1dArray(points, 'HEAPF32');
138    this._addPoly(ptr, points.length / 2, close);
139    freeArraysThatAreNotMallocedByUsers(ptr, points);
140    return this;
141  };
142
143  CanvasKit.Path.prototype.addRect = function(rect, isCCW) {
144    var rPtr = copyRectToWasm(rect);
145    this._addRect(rPtr, !!isCCW);
146    return this;
147  };
148
149  CanvasKit.Path.prototype.addRRect = function(rrect, isCCW) {
150    var rPtr = copyRRectToWasm(rrect);
151    this._addRRect(rPtr, !!isCCW);
152    return this;
153  };
154
155  // The weights array is optional (only used for conics).
156  CanvasKit.Path.prototype.addVerbsPointsWeights = function(verbs, points, weights) {
157    var verbsPtr = copy1dArray(verbs, 'HEAPU8');
158    var pointsPtr = copy1dArray(points, 'HEAPF32');
159    var weightsPtr = copy1dArray(weights, 'HEAPF32');
160    var numWeights = (weights && weights.length) || 0;
161    this._addVerbsPointsWeights(verbsPtr, verbs.length, pointsPtr, points.length,
162                                weightsPtr, numWeights);
163    freeArraysThatAreNotMallocedByUsers(verbsPtr, verbs);
164    freeArraysThatAreNotMallocedByUsers(pointsPtr, points);
165    freeArraysThatAreNotMallocedByUsers(weightsPtr, weights);
166  };
167
168  CanvasKit.Path.prototype.arc = function(x, y, radius, startAngle, endAngle, ccw) {
169    // emulates the HTMLCanvas behavior.  See addArc() for the Path version.
170    // Note input angles are radians.
171    var bounds = CanvasKit.LTRBRect(x-radius, y-radius, x+radius, y+radius);
172    var sweep = radiansToDegrees(endAngle - startAngle) - (360 * !!ccw);
173    var temp = new CanvasKit.Path();
174    temp.addArc(bounds, radiansToDegrees(startAngle), sweep);
175    this.addPath(temp, true);
176    temp.delete();
177    return this;
178  };
179
180  // Appends arc to Path. Arc added is part of ellipse
181  // bounded by oval, from startAngle through sweepAngle. Both startAngle and
182  // sweepAngle are measured in degrees, where zero degrees is aligned with the
183  // positive x-axis, and positive sweeps extends arc clockwise.
184  CanvasKit.Path.prototype.arcToOval = function(oval, startAngle, sweepAngle, forceMoveTo) {
185    var oPtr = copyRectToWasm(oval);
186    this._arcToOval(oPtr, startAngle, sweepAngle, forceMoveTo);
187    return this;
188  };
189
190  // Appends arc to Path. Arc is implemented by one or more conics weighted to
191  // describe part of oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc
192  // curves from last point to (x, y), choosing one of four possible routes:
193  // clockwise or counterclockwise, and smaller or larger.
194
195  // Arc sweep is always less than 360 degrees. arcTo() appends line to (x, y) if
196  // either radii are zero, or if last point equals (x, y). arcTo() scales radii
197  // (rx, ry) to fit last point and (x, y) if both are greater than zero but
198  // too small.
199
200  // arcToRotated() appends up to four conic curves.
201  // arcToRotated() implements the functionality of SVG arc, although SVG sweep-flag value
202  // is opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise,
203  // while kCW_Direction cast to int is zero.
204  CanvasKit.Path.prototype.arcToRotated = function(rx, ry, xAxisRotate, useSmallArc, isCCW, x, y) {
205    this._arcToRotated(rx, ry, xAxisRotate, !!useSmallArc, !!isCCW, x, y);
206    return this;
207  };
208
209  // Appends arc to Path, after appending line if needed. Arc is implemented by conic
210  // weighted to describe part of circle. Arc is contained by tangent from
211  // last Path point to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
212  // is part of circle sized to radius, positioned so it touches both tangent lines.
213
214  // If last Path Point does not start Arc, arcTo appends connecting Line to Path.
215  // The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
216
217  // Arc sweep is always less than 180 degrees. If radius is zero, or if
218  // tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
219
220  // arcToTangent appends at most one Line and one conic.
221  // arcToTangent implements the functionality of PostScript arct and HTML Canvas arcTo.
222  CanvasKit.Path.prototype.arcToTangent = function(x1, y1, x2, y2, radius) {
223    this._arcToTangent(x1, y1, x2, y2, radius);
224    return this;
225  };
226
227  CanvasKit.Path.prototype.close = function() {
228    this._close();
229    return this;
230  };
231
232  CanvasKit.Path.prototype.conicTo = function(x1, y1, x2, y2, w) {
233    this._conicTo(x1, y1, x2, y2, w);
234    return this;
235  };
236
237  // Clients can pass in a Float32Array with length 4 to this and the results
238  // will be copied into that array. Otherwise, a new TypedArray will be allocated
239  // and returned.
240  CanvasKit.Path.prototype.computeTightBounds = function(optionalOutputArray) {
241    this._computeTightBounds(_scratchFourFloatsAPtr);
242    var ta = _scratchFourFloatsA['toTypedArray']();
243    if (optionalOutputArray) {
244      optionalOutputArray.set(ta);
245      return optionalOutputArray;
246    }
247    return ta.slice();
248  };
249
250  CanvasKit.Path.prototype.cubicTo = function(cp1x, cp1y, cp2x, cp2y, x, y) {
251    this._cubicTo(cp1x, cp1y, cp2x, cp2y, x, y);
252    return this;
253  };
254
255  CanvasKit.Path.prototype.dash = function(on, off, phase) {
256    if (this._dash(on, off, phase)) {
257      return this;
258    }
259    return null;
260  };
261
262  // Clients can pass in a Float32Array with length 4 to this and the results
263  // will be copied into that array. Otherwise, a new TypedArray will be allocated
264  // and returned.
265  CanvasKit.Path.prototype.getBounds = function(optionalOutputArray) {
266    this._getBounds(_scratchFourFloatsAPtr);
267    var ta = _scratchFourFloatsA['toTypedArray']();
268    if (optionalOutputArray) {
269      optionalOutputArray.set(ta);
270      return optionalOutputArray;
271    }
272    return ta.slice();
273  };
274
275  CanvasKit.Path.prototype.lineTo = function(x, y) {
276    this._lineTo(x, y);
277    return this;
278  };
279
280  CanvasKit.Path.prototype.moveTo = function(x, y) {
281    this._moveTo(x, y);
282    return this;
283  };
284
285  CanvasKit.Path.prototype.offset = function(dx, dy) {
286    this._transform(1, 0, dx,
287                    0, 1, dy,
288                    0, 0, 1);
289    return this;
290  };
291
292  CanvasKit.Path.prototype.quadTo = function(cpx, cpy, x, y) {
293    this._quadTo(cpx, cpy, x, y);
294    return this;
295  };
296
297 CanvasKit.Path.prototype.rArcTo = function(rx, ry, xAxisRotate, useSmallArc, isCCW, dx, dy) {
298    this._rArcTo(rx, ry, xAxisRotate, useSmallArc, isCCW, dx, dy);
299    return this;
300  };
301
302  CanvasKit.Path.prototype.rConicTo = function(dx1, dy1, dx2, dy2, w) {
303    this._rConicTo(dx1, dy1, dx2, dy2, w);
304    return this;
305  };
306
307  // These params are all relative
308  CanvasKit.Path.prototype.rCubicTo = function(cp1x, cp1y, cp2x, cp2y, x, y) {
309    this._rCubicTo(cp1x, cp1y, cp2x, cp2y, x, y);
310    return this;
311  };
312
313  CanvasKit.Path.prototype.rLineTo = function(dx, dy) {
314    this._rLineTo(dx, dy);
315    return this;
316  };
317
318  CanvasKit.Path.prototype.rMoveTo = function(dx, dy) {
319    this._rMoveTo(dx, dy);
320    return this;
321  };
322
323  // These params are all relative
324  CanvasKit.Path.prototype.rQuadTo = function(cpx, cpy, x, y) {
325    this._rQuadTo(cpx, cpy, x, y);
326    return this;
327  };
328
329  CanvasKit.Path.prototype.stroke = function(opts) {
330    // Fill out any missing values with the default values.
331    opts = opts || {};
332    opts['width'] = opts['width'] || 1;
333    opts['miter_limit'] = opts['miter_limit'] || 4;
334    opts['cap'] = opts['cap'] || CanvasKit.StrokeCap.Butt;
335    opts['join'] = opts['join'] || CanvasKit.StrokeJoin.Miter;
336    opts['precision'] = opts['precision'] || 1;
337    if (this._stroke(opts)) {
338      return this;
339    }
340    return null;
341  };
342
343  // TODO(kjlubick) Change this to take a 3x3 or 4x4 matrix (optionally malloc'd)
344  CanvasKit.Path.prototype.transform = function() {
345    // Takes 1 or 9 args
346    if (arguments.length === 1) {
347      // argument 1 should be a 6 or 9 element array.
348      var a = arguments[0];
349      this._transform(a[0], a[1], a[2],
350                      a[3], a[4], a[5],
351                      a[6] || 0, a[7] || 0, a[8] || 1);
352    } else if (arguments.length === 6 || arguments.length === 9) {
353      // these arguments are the 6 or 9 members of the matrix
354      var a = arguments;
355      this._transform(a[0], a[1], a[2],
356                      a[3], a[4], a[5],
357                      a[6] || 0, a[7] || 0, a[8] || 1);
358    } else {
359      throw 'transform expected to take 1 or 9 arguments. Got ' + arguments.length;
360    }
361    return this;
362  };
363  // isComplement is optional, defaults to false
364  CanvasKit.Path.prototype.trim = function(startT, stopT, isComplement) {
365    if (this._trim(startT, stopT, !!isComplement)) {
366      return this;
367    }
368    return null;
369  };
370
371  // makeShaderCubic returns a shader for a given image, allowing it to be used on
372  // a paint as well as other purposes. This shader will be higher quality than
373  // other shader functions. See CubicResampler in SkSamplingOptions.h for more information
374  // on the cubicResampler params.
375  CanvasKit.Image.prototype.makeShaderCubic = function(xTileMode, yTileMode,
376                                                       cubicResamplerB, cubicResamplerC,
377                                                       localMatrix) {
378    var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
379    return this._makeShaderCubic(xTileMode, yTileMode, cubicResamplerB,
380                                 cubicResamplerC, localMatrixPtr);
381  };
382
383  // makeShaderCubic returns a shader for a given image, allowing it to be used on
384  // a paint as well as other purposes. This shader will draw more quickly than
385  // other shader functions, but at a lower quality.
386  CanvasKit.Image.prototype.makeShaderOptions = function(xTileMode, yTileMode,
387                                                         filterMode, mipmapMode,
388                                                         localMatrix) {
389    var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
390    return this._makeShaderOptions(xTileMode, yTileMode, filterMode, mipmapMode, localMatrixPtr);
391  };
392
393  function readPixels(source, srcX, srcY, imageInfo, destMallocObj, bytesPerRow) {
394    if (!bytesPerRow) {
395      bytesPerRow = 4 * imageInfo['width'];
396      if (imageInfo['colorType'] === CanvasKit.ColorType.RGBA_F16) {
397        bytesPerRow *= 2;
398      }
399      else if (imageInfo['colorType'] === CanvasKit.ColorType.RGBA_F32) {
400        bytesPerRow *= 4;
401      }
402    }
403    var pBytes = bytesPerRow * imageInfo.height;
404    var pPtr;
405    if (destMallocObj) {
406      pPtr = destMallocObj['byteOffset'];
407    } else {
408      pPtr = CanvasKit._malloc(pBytes);
409    }
410
411    if (!source._readPixels(imageInfo, pPtr, bytesPerRow, srcX, srcY)) {
412      Debug('Could not read pixels with the given inputs');
413      if (!destMallocObj) {
414        CanvasKit._free(pPtr);
415      }
416      return null;
417    }
418
419    // If the user provided us a buffer to copy into, we don't need to allocate a new TypedArray.
420    if (destMallocObj) {
421      return destMallocObj['toTypedArray'](); // Return the typed array wrapper w/o allocating.
422    }
423
424    // Put those pixels into a typed array of the right format and then
425    // make a copy with slice() that we can return.
426    var retVal = null;
427    switch (imageInfo['colorType']) {
428      case CanvasKit.ColorType.RGBA_8888:
429      case CanvasKit.ColorType.RGBA_F16: // there is no half-float JS type, so we return raw bytes.
430        retVal = new Uint8Array(CanvasKit.HEAPU8.buffer, pPtr, pBytes).slice();
431        break;
432      case CanvasKit.ColorType.RGBA_F32:
433        retVal = new Float32Array(CanvasKit.HEAPU8.buffer, pPtr, pBytes).slice();
434        break;
435      default:
436        Debug('ColorType not yet supported');
437        return null;
438    }
439
440    // Free the allocated pixels in the WASM memory
441    CanvasKit._free(pPtr);
442    return retVal;
443  }
444
445  CanvasKit.Image.prototype.readPixels = function(srcX, srcY, imageInfo, destMallocObj,
446                                                  bytesPerRow) {
447    return readPixels(this, srcX, srcY, imageInfo, destMallocObj, bytesPerRow);
448  };
449
450  // Accepts an array of four numbers in the range of 0-1 representing a 4f color
451  CanvasKit.Canvas.prototype.clear = function(color4f) {
452    CanvasKit.setCurrentContext(this._context);
453    var cPtr = copyColorToWasm(color4f);
454    this._clear(cPtr);
455  };
456
457  CanvasKit.Canvas.prototype.clipRRect = function(rrect, op, antialias) {
458    CanvasKit.setCurrentContext(this._context);
459    var rPtr = copyRRectToWasm(rrect);
460    this._clipRRect(rPtr, op, antialias);
461  };
462
463  CanvasKit.Canvas.prototype.clipRect = function(rect, op, antialias) {
464    CanvasKit.setCurrentContext(this._context);
465    var rPtr = copyRectToWasm(rect);
466    this._clipRect(rPtr, op, antialias);
467  };
468
469  // concat takes a 3x2, a 3x3, or a 4x4 matrix and upscales it (if needed) to 4x4. This is because
470  // under the hood, SkCanvas uses a 4x4 matrix.
471  CanvasKit.Canvas.prototype.concat = function(matr) {
472    CanvasKit.setCurrentContext(this._context);
473    var matrPtr = copy4x4MatrixToWasm(matr);
474    this._concat(matrPtr);
475  };
476
477  CanvasKit.Canvas.prototype.drawArc = function(oval, startAngle, sweepAngle, useCenter, paint) {
478    CanvasKit.setCurrentContext(this._context);
479    var oPtr = copyRectToWasm(oval);
480    this._drawArc(oPtr, startAngle, sweepAngle, useCenter, paint);
481  };
482
483  // atlas is an Image, e.g. from CanvasKit.MakeImageFromEncoded
484  // srcRects, dstXformsshould be arrays of floats of length 4*number of destinations.
485  // The colors param is optional and is used to tint the drawn images using the optional blend
486  // mode. Colors can be a Uint32Array of int colors or a flat Float32Array of float colors.
487  CanvasKit.Canvas.prototype.drawAtlas = function(atlas, srcRects, dstXforms, paint,
488                                       /* optional */ blendMode, /* optional */ colors,
489                                       /* optional */ sampling) {
490    if (!atlas || !paint || !srcRects || !dstXforms) {
491      Debug('Doing nothing since missing a required input');
492      return;
493    }
494
495    // builder arguments report the length as the number of rects, but when passed as arrays
496    // their.length attribute is 4x higher because it's the number of total components of all rects.
497    // colors is always going to report the same length, at least until floats colors are supported
498    // by this function.
499    if (srcRects.length !== dstXforms.length) {
500      Debug('Doing nothing since input arrays length mismatches');
501      return;
502    }
503    CanvasKit.setCurrentContext(this._context);
504    if (!blendMode) {
505      blendMode = CanvasKit.BlendMode.SrcOver;
506    }
507
508    var srcRectPtr = copy1dArray(srcRects, 'HEAPF32');
509
510    var dstXformPtr = copy1dArray(dstXforms, 'HEAPF32');
511    var count = dstXforms.length / 4;
512
513    var colorPtr = copy1dArray(assureIntColors(colors), 'HEAPU32');
514
515    // We require one of these:
516    // 1. sampling is null (we default to linear/none)
517    // 2. sampling.B and sampling.C --> CubicResampler
518    // 3. sampling.filter [and sampling.mipmap] --> FilterOptions
519    //
520    // Thus if all fields are available, we will choose cubic (since we search for B,C first)
521
522    if (sampling && ('B' in sampling) && ('C' in sampling)) {
523        this._drawAtlasCubic(atlas, dstXformPtr, srcRectPtr, colorPtr, count, blendMode,
524                             sampling['B'], sampling['C'], paint);
525    } else {
526        let filter = CanvasKit.FilterMode.Linear;
527        let mipmap = CanvasKit.MipmapMode.None;
528        if (sampling) {
529            filter = sampling['filter'];    // 'filter' is a required field
530            if ('mipmap' in sampling) {     // 'mipmap' is optional
531                mipmap = sampling['mipmap'];
532            }
533        }
534        this._drawAtlasOptions(atlas, dstXformPtr, srcRectPtr, colorPtr, count, blendMode,
535                               filter, mipmap, paint);
536    }
537
538    freeArraysThatAreNotMallocedByUsers(srcRectPtr, srcRects);
539    freeArraysThatAreNotMallocedByUsers(dstXformPtr, dstXforms);
540    freeArraysThatAreNotMallocedByUsers(colorPtr, colors);
541  };
542
543  CanvasKit.Canvas.prototype.drawCircle = function(cx, cy, r, paint) {
544    CanvasKit.setCurrentContext(this._context);
545    this._drawCircle(cx, cy, r, paint);
546  }
547
548  CanvasKit.Canvas.prototype.drawColor = function(color4f, mode) {
549    CanvasKit.setCurrentContext(this._context);
550    var cPtr = copyColorToWasm(color4f);
551    if (mode !== undefined) {
552      this._drawColor(cPtr, mode);
553    } else {
554      this._drawColor(cPtr);
555    }
556  };
557
558  CanvasKit.Canvas.prototype.drawColorInt = function(color, mode) {
559    CanvasKit.setCurrentContext(this._context);
560    this._drawColorInt(color, mode || CanvasKit.BlendMode.SrcOver);
561  }
562
563  CanvasKit.Canvas.prototype.drawColorComponents = function(r, g, b, a, mode) {
564    CanvasKit.setCurrentContext(this._context);
565    var cPtr = copyColorComponentsToWasm(r, g, b, a);
566    if (mode !== undefined) {
567      this._drawColor(cPtr, mode);
568    } else {
569      this._drawColor(cPtr);
570    }
571  };
572
573  CanvasKit.Canvas.prototype.drawDRRect = function(outer, inner, paint) {
574    CanvasKit.setCurrentContext(this._context);
575    var oPtr = copyRRectToWasm(outer, _scratchRRectPtr);
576    var iPtr = copyRRectToWasm(inner, _scratchRRect2Ptr);
577    this._drawDRRect(oPtr, iPtr, paint);
578  };
579
580  CanvasKit.Canvas.prototype.drawGlyphs = function(glyphs, positions, x, y, font, paint) {
581    if (!(glyphs.length*2 <= positions.length)) {
582        throw 'Not enough positions for the array of gyphs';
583    }
584    CanvasKit.setCurrentContext(this._context);
585    const glyphs_ptr    = copy1dArray(glyphs, 'HEAPU16');
586    const positions_ptr = copy1dArray(positions, 'HEAPF32');
587
588    this._drawGlyphs(glyphs.length, glyphs_ptr, positions_ptr, x, y, font, paint);
589
590    freeArraysThatAreNotMallocedByUsers(positions_ptr, positions);
591    freeArraysThatAreNotMallocedByUsers(glyphs_ptr,    glyphs);
592  };
593
594  CanvasKit.Canvas.prototype.drawImage = function(img, x, y, paint) {
595    CanvasKit.setCurrentContext(this._context);
596    this._drawImage(img, x, y, paint || null);
597  };
598
599  CanvasKit.Canvas.prototype.drawImageCubic = function(img, x, y, b, c, paint) {
600    CanvasKit.setCurrentContext(this._context);
601    this._drawImageCubic(img, x, y, b, c, paint || null);
602  };
603
604  CanvasKit.Canvas.prototype.drawImageOptions = function(img, x, y, filter, mipmap, paint) {
605    CanvasKit.setCurrentContext(this._context);
606    this._drawImageOptions(img, x, y, filter, mipmap, paint || null);
607  };
608
609  CanvasKit.Canvas.prototype.drawImageNine = function(img, center, dest, filter, paint) {
610    CanvasKit.setCurrentContext(this._context);
611    var cPtr = copyIRectToWasm(center);
612    var dPtr = copyRectToWasm(dest);
613    this._drawImageNine(img, cPtr, dPtr, filter, paint || null);
614  };
615
616  CanvasKit.Canvas.prototype.drawImageRect = function(img, src, dest, paint, fastSample) {
617    CanvasKit.setCurrentContext(this._context);
618    copyRectToWasm(src,  _scratchFourFloatsAPtr);
619    copyRectToWasm(dest, _scratchFourFloatsBPtr);
620    this._drawImageRect(img, _scratchFourFloatsAPtr, _scratchFourFloatsBPtr, paint, !!fastSample);
621  };
622
623  CanvasKit.Canvas.prototype.drawImageRectCubic = function(img, src, dest, B, C, paint) {
624    CanvasKit.setCurrentContext(this._context);
625    copyRectToWasm(src,  _scratchFourFloatsAPtr);
626    copyRectToWasm(dest, _scratchFourFloatsBPtr);
627    this._drawImageRectCubic(img, _scratchFourFloatsAPtr, _scratchFourFloatsBPtr, B, C,
628      paint || null);
629  };
630
631  CanvasKit.Canvas.prototype.drawImageRectOptions = function(img, src, dest, filter, mipmap, paint) {
632    CanvasKit.setCurrentContext(this._context);
633    copyRectToWasm(src,  _scratchFourFloatsAPtr);
634    copyRectToWasm(dest, _scratchFourFloatsBPtr);
635    this._drawImageRectOptions(img, _scratchFourFloatsAPtr, _scratchFourFloatsBPtr, filter, mipmap,
636      paint || null);
637  };
638
639  CanvasKit.Canvas.prototype.drawLine = function(x1, y1, x2, y2, paint) {
640    CanvasKit.setCurrentContext(this._context);
641    this._drawLine(x1, y1, x2, y2, paint);
642  }
643
644  CanvasKit.Canvas.prototype.drawOval = function(oval, paint) {
645    CanvasKit.setCurrentContext(this._context);
646    var oPtr = copyRectToWasm(oval);
647    this._drawOval(oPtr, paint);
648  };
649
650  CanvasKit.Canvas.prototype.drawPaint = function(paint) {
651    CanvasKit.setCurrentContext(this._context);
652    this._drawPaint(paint);
653  }
654
655  CanvasKit.Canvas.prototype.drawParagraph = function(p, x, y) {
656    CanvasKit.setCurrentContext(this._context);
657    this._drawParagraph(p, x, y);
658  }
659
660  CanvasKit.Canvas.prototype.drawPatch = function(cubics, colors, texs, mode, paint) {
661    if (cubics.length < 24) {
662        throw 'Need 12 cubic points';
663    }
664    if (colors && colors.length < 4) {
665        throw 'Need 4 colors';
666    }
667    if (texs && texs.length < 8) {
668        throw 'Need 4 shader coordinates';
669    }
670    CanvasKit.setCurrentContext(this._context);
671
672    const cubics_ptr =          copy1dArray(cubics, 'HEAPF32');
673    const colors_ptr = colors ? copy1dArray(assureIntColors(colors), 'HEAPU32') : nullptr;
674    const texs_ptr   = texs   ? copy1dArray(texs,   'HEAPF32') : nullptr;
675    if (!mode) {
676        mode = CanvasKit.BlendMode.Modulate;
677    }
678
679    this._drawPatch(cubics_ptr, colors_ptr, texs_ptr, mode, paint);
680
681    freeArraysThatAreNotMallocedByUsers(texs_ptr,   texs);
682    freeArraysThatAreNotMallocedByUsers(colors_ptr, colors);
683    freeArraysThatAreNotMallocedByUsers(cubics_ptr, cubics);
684  };
685
686  CanvasKit.Canvas.prototype.drawPath = function(path, paint) {
687    CanvasKit.setCurrentContext(this._context);
688    this._drawPath(path, paint);
689  }
690
691  CanvasKit.Canvas.prototype.drawPicture = function(pic) {
692    CanvasKit.setCurrentContext(this._context);
693    this._drawPicture(pic);
694  }
695
696  // points is a 1d array of length 2n representing n points where the even indices
697  // will be treated as x coordinates and the odd indices will be treated as y coordinates.
698  // Like other APIs, this accepts a malloced type array or malloc obj.
699  CanvasKit.Canvas.prototype.drawPoints = function(mode, points, paint) {
700    CanvasKit.setCurrentContext(this._context);
701    var ptr = copy1dArray(points, 'HEAPF32');
702    this._drawPoints(mode, ptr, points.length / 2, paint);
703    freeArraysThatAreNotMallocedByUsers(ptr, points);
704  };
705
706  CanvasKit.Canvas.prototype.drawRRect = function(rrect, paint) {
707    CanvasKit.setCurrentContext(this._context);
708    var rPtr = copyRRectToWasm(rrect);
709    this._drawRRect(rPtr, paint);
710  };
711
712  CanvasKit.Canvas.prototype.drawRect = function(rect, paint) {
713    CanvasKit.setCurrentContext(this._context);
714    var rPtr = copyRectToWasm(rect);
715    this._drawRect(rPtr, paint);
716  };
717
718  CanvasKit.Canvas.prototype.drawRect4f = function(l, t, r, b, paint) {
719    CanvasKit.setCurrentContext(this._context);
720    this._drawRect4f(l, t, r, b, paint);
721  }
722
723  CanvasKit.Canvas.prototype.drawShadow = function(path, zPlaneParams, lightPos, lightRadius,
724                                                   ambientColor, spotColor, flags) {
725    CanvasKit.setCurrentContext(this._context);
726    var ambiPtr = copyColorToWasmNoScratch(ambientColor);
727    var spotPtr = copyColorToWasmNoScratch(spotColor);
728    // We use the return value from copy1dArray in case the passed in arrays are malloc'd.
729    var zPlanePtr = copy1dArray(zPlaneParams, 'HEAPF32', _scratchThreeFloatsAPtr);
730    var lightPosPtr = copy1dArray(lightPos, 'HEAPF32', _scratchThreeFloatsBPtr);
731    this._drawShadow(path, zPlanePtr, lightPosPtr, lightRadius, ambiPtr, spotPtr, flags);
732    freeArraysThatAreNotMallocedByUsers(ambiPtr, ambientColor);
733    freeArraysThatAreNotMallocedByUsers(spotPtr, spotColor);
734  };
735
736  CanvasKit.getShadowLocalBounds = function(ctm, path, zPlaneParams, lightPos, lightRadius,
737                                            flags, optOutputRect) {
738    var ctmPtr = copy3x3MatrixToWasm(ctm);
739    // We use the return value from copy1dArray in case the passed in arrays are malloc'd.
740    var zPlanePtr = copy1dArray(zPlaneParams, 'HEAPF32', _scratchThreeFloatsAPtr);
741    var lightPosPtr = copy1dArray(lightPos, 'HEAPF32', _scratchThreeFloatsBPtr);
742    var ok = this._getShadowLocalBounds(ctmPtr, path, zPlanePtr, lightPosPtr, lightRadius,
743                                        flags, _scratchFourFloatsAPtr);
744    if (!ok) {
745      return null;
746    }
747    var ta = _scratchFourFloatsA['toTypedArray']();
748    if (optOutputRect) {
749      optOutputRect.set(ta);
750      return optOutputRect;
751    }
752    return ta.slice();
753  };
754
755  CanvasKit.Canvas.prototype.drawTextBlob = function(blob, x, y, paint) {
756    CanvasKit.setCurrentContext(this._context);
757    this._drawTextBlob(blob, x, y, paint);
758  }
759
760  CanvasKit.Canvas.prototype.drawVertices = function(verts, mode, paint) {
761    CanvasKit.setCurrentContext(this._context);
762    this._drawVertices(verts, mode, paint);
763  }
764
765  // getLocalToDevice returns a 4x4 matrix.
766  CanvasKit.Canvas.prototype.getLocalToDevice = function() {
767    // _getLocalToDevice will copy the values into the pointer.
768    this._getLocalToDevice(_scratch4x4MatrixPtr);
769    return copy4x4MatrixFromWasm(_scratch4x4MatrixPtr);
770  };
771
772  // findMarkedCTM returns a 4x4 matrix, or null if a matrix was not found at
773  // the provided marker.
774  CanvasKit.Canvas.prototype.findMarkedCTM = function(marker) {
775    // _getLocalToDevice will copy the values into the pointer.
776    var found = this._findMarkedCTM(marker, _scratch4x4MatrixPtr);
777    if (!found) {
778      return null;
779    }
780    return copy4x4MatrixFromWasm(_scratch4x4MatrixPtr);
781  };
782
783  // getTotalMatrix returns the current matrix as a 3x3 matrix.
784  CanvasKit.Canvas.prototype.getTotalMatrix = function() {
785    // _getTotalMatrix will copy the values into the pointer.
786    this._getTotalMatrix(_scratch3x3MatrixPtr);
787    // read them out into an array. TODO(kjlubick): If we change Matrix to be
788    // typedArrays, then we should return a typed array here too.
789    var rv = new Array(9);
790    for (var i = 0; i < 9; i++) {
791      rv[i] = CanvasKit.HEAPF32[_scratch3x3MatrixPtr/4 + i]; // divide by 4 to "cast" to float.
792    }
793    return rv;
794  };
795
796  CanvasKit.Canvas.prototype.makeSurface = function(imageInfo) {
797    var s = this._makeSurface(imageInfo);
798    s._context = this._context;
799    return s;
800  };
801
802  CanvasKit.Canvas.prototype.readPixels = function(srcX, srcY, imageInfo, destMallocObj,
803                                                   bytesPerRow) {
804    CanvasKit.setCurrentContext(this._context);
805    return readPixels(this, srcX, srcY, imageInfo, destMallocObj, bytesPerRow);
806  };
807
808  CanvasKit.Canvas.prototype.saveLayer = function(paint, boundsRect, backdrop, flags) {
809    // bPtr will be 0 (nullptr) if boundsRect is undefined/null.
810    var bPtr = copyRectToWasm(boundsRect);
811    // These or clauses help emscripten, which does not deal with undefined well.
812    return this._saveLayer(paint || null, bPtr, backdrop || null, flags || 0);
813  };
814
815  // pixels should be a Uint8Array or a plain JS array.
816  CanvasKit.Canvas.prototype.writePixels = function(pixels, srcWidth, srcHeight,
817                                                      destX, destY, alphaType, colorType, colorSpace) {
818    if (pixels.byteLength % (srcWidth * srcHeight)) {
819      throw 'pixels length must be a multiple of the srcWidth * srcHeight';
820    }
821    CanvasKit.setCurrentContext(this._context);
822    var bytesPerPixel = pixels.byteLength / (srcWidth * srcHeight);
823    // supply defaults (which are compatible with HTMLCanvas's putImageData)
824    alphaType = alphaType || CanvasKit.AlphaType.Unpremul;
825    colorType = colorType || CanvasKit.ColorType.RGBA_8888;
826    colorSpace = colorSpace || CanvasKit.ColorSpace.SRGB;
827    var srcRowBytes = bytesPerPixel * srcWidth;
828
829    var pptr = copy1dArray(pixels, 'HEAPU8');
830    var ok = this._writePixels({
831      'width': srcWidth,
832      'height': srcHeight,
833      'colorType': colorType,
834      'alphaType': alphaType,
835      'colorSpace': colorSpace,
836    }, pptr, srcRowBytes, destX, destY);
837
838    freeArraysThatAreNotMallocedByUsers(pptr, pixels);
839    return ok;
840  };
841
842  CanvasKit.ColorFilter.MakeBlend = function(color4f, mode) {
843    var cPtr = copyColorToWasm(color4f);
844    return CanvasKit.ColorFilter._MakeBlend(cPtr, mode);
845  };
846
847  // colorMatrix is an ColorMatrix (e.g. Float32Array of length 20)
848  CanvasKit.ColorFilter.MakeMatrix = function(colorMatrix) {
849    if (!colorMatrix || colorMatrix.length !== 20) {
850      throw 'invalid color matrix';
851    }
852    var fptr = copy1dArray(colorMatrix, 'HEAPF32');
853    // We know skia memcopies the floats, so we can free our memory after the call returns.
854    var m = CanvasKit.ColorFilter._makeMatrix(fptr);
855    freeArraysThatAreNotMallocedByUsers(fptr, colorMatrix);
856    return m;
857  };
858
859  CanvasKit.ContourMeasure.prototype.getPosTan = function(distance, optionalOutput) {
860    this._getPosTan(distance, _scratchFourFloatsAPtr);
861    var ta = _scratchFourFloatsA['toTypedArray']();
862    if (optionalOutput) {
863      optionalOutput.set(ta);
864      return optionalOutput;
865    }
866    return ta.slice();
867  };
868
869  CanvasKit.ImageFilter.MakeMatrixTransform = function(matrix, sampling, input) {
870    var matrPtr = copy3x3MatrixToWasm(matrix);
871
872    if ('B' in sampling && 'C' in sampling) {
873        return CanvasKit.ImageFilter._MakeMatrixTransformCubic(matrPtr,
874                                                               sampling.B, sampling.C,
875                                                               input);
876    } else {
877        const filter = sampling['filter'];  // 'filter' is a required field
878        let mipmap = CanvasKit.MipmapMode.None;
879        if ('mipmap' in sampling) {         // 'mipmap' is optional
880            mipmap = sampling['mipmap'];
881        }
882        return CanvasKit.ImageFilter._MakeMatrixTransformOptions(matrPtr,
883                                                                 filter, mipmap,
884                                                                 input);
885    }
886  };
887
888  CanvasKit.Paint.prototype.getColor = function() {
889    this._getColor(_scratchColorPtr);
890    return copyColorFromWasm(_scratchColorPtr);
891  };
892
893  CanvasKit.Paint.prototype.setColor = function(color4f, colorSpace) {
894    colorSpace = colorSpace || null; // null will be replaced with sRGB in the C++ method.
895    // emscripten wouldn't bind undefined to the sk_sp<ColorSpace> expected here.
896    var cPtr = copyColorToWasm(color4f);
897    this._setColor(cPtr, colorSpace);
898  };
899
900  // The color components here are expected to be floating point values (nominally between
901  // 0.0 and 1.0, but with wider color gamuts, the values could exceed this range). To convert
902  // between standard 8 bit colors and floats, just divide by 255 before passing them in.
903  CanvasKit.Paint.prototype.setColorComponents = function(r, g, b, a, colorSpace) {
904    colorSpace = colorSpace || null; // null will be replaced with sRGB in the C++ method.
905    // emscripten wouldn't bind undefined to the sk_sp<ColorSpace> expected here.
906    var cPtr = copyColorComponentsToWasm(r, g, b, a);
907    this._setColor(cPtr, colorSpace);
908  };
909
910  CanvasKit.Path.prototype.getPoint = function(idx, optionalOutput) {
911    // This will copy 2 floats into a space for 4 floats
912    this._getPoint(idx, _scratchFourFloatsAPtr);
913    var ta = _scratchFourFloatsA['toTypedArray']();
914    if (optionalOutput) {
915      // We cannot call optionalOutput.set() because it is an error to call .set() with
916      // a source bigger than the destination.
917      optionalOutput[0] = ta[0];
918      optionalOutput[1] = ta[1];
919      return optionalOutput;
920    }
921    // Be sure to return a copy of just the first 2 values.
922    return ta.slice(0, 2);
923  };
924
925  CanvasKit.PictureRecorder.prototype.beginRecording = function(bounds) {
926    var bPtr = copyRectToWasm(bounds);
927    return this._beginRecording(bPtr);
928  };
929
930  CanvasKit.Surface.prototype.getCanvas = function() {
931    var c = this._getCanvas();
932    c._context = this._context;
933    return c;
934  };
935
936  CanvasKit.Surface.prototype.makeImageSnapshot = function(optionalBoundsRect) {
937    CanvasKit.setCurrentContext(this._context);
938    var bPtr = copyIRectToWasm(optionalBoundsRect);
939    return this._makeImageSnapshot(bPtr);
940  };
941
942  CanvasKit.Surface.prototype.makeSurface = function(imageInfo) {
943    CanvasKit.setCurrentContext(this._context);
944    var s = this._makeSurface(imageInfo);
945    s._context = this._context;
946    return s;
947  };
948
949  CanvasKit.Surface.prototype.requestAnimationFrame = function(callback, dirtyRect) {
950    if (!this._cached_canvas) {
951      this._cached_canvas = this.getCanvas();
952    }
953    requestAnimationFrame(function() {
954      CanvasKit.setCurrentContext(this._context);
955
956      callback(this._cached_canvas);
957
958      // We do not dispose() of the Surface here, as the client will typically
959      // call requestAnimationFrame again from within the supplied callback.
960      // For drawing a single frame, prefer drawOnce().
961      this.flush(dirtyRect);
962    }.bind(this));
963  };
964
965  // drawOnce will dispose of the surface after drawing the frame using the provided
966  // callback.
967  CanvasKit.Surface.prototype.drawOnce = function(callback, dirtyRect) {
968    if (!this._cached_canvas) {
969      this._cached_canvas = this.getCanvas();
970    }
971    requestAnimationFrame(function() {
972      CanvasKit.setCurrentContext(this._context);
973      callback(this._cached_canvas);
974
975      this.flush(dirtyRect);
976      this.dispose();
977    }.bind(this));
978  };
979
980  CanvasKit.PathEffect.MakeDash = function(intervals, phase) {
981    if (!phase) {
982      phase = 0;
983    }
984    if (!intervals.length || intervals.length % 2 === 1) {
985      throw 'Intervals array must have even length';
986    }
987    var ptr = copy1dArray(intervals, 'HEAPF32');
988    var dpe = CanvasKit.PathEffect._MakeDash(ptr, intervals.length, phase);
989    freeArraysThatAreNotMallocedByUsers(ptr, intervals);
990    return dpe;
991  };
992
993  CanvasKit.Shader.MakeColor = function(color4f, colorSpace) {
994    colorSpace = colorSpace || null;
995    var cPtr = copyColorToWasm(color4f);
996    return CanvasKit.Shader._MakeColor(cPtr, colorSpace);
997  };
998
999  // TODO(kjlubick) remove deprecated names.
1000  CanvasKit.Shader.Blend = CanvasKit.Shader.MakeBlend;
1001  CanvasKit.Shader.Color = CanvasKit.Shader.MakeColor;
1002
1003  CanvasKit.Shader.MakeLinearGradient = function(start, end, colors, pos, mode, localMatrix, flags, colorSpace) {
1004    colorSpace = colorSpace || null;
1005    var cPtrInfo = copyFlexibleColorArray(colors);
1006    var posPtr = copy1dArray(pos, 'HEAPF32');
1007    flags = flags || 0;
1008    var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
1009
1010    // Copy start and end to _scratchFourFloatsAPtr.
1011    var startEndPts = _scratchFourFloatsA['toTypedArray']();
1012    startEndPts.set(start);
1013    startEndPts.set(end, 2);
1014
1015    var lgs = CanvasKit.Shader._MakeLinearGradient(_scratchFourFloatsAPtr, cPtrInfo.colorPtr, cPtrInfo.colorType, posPtr,
1016                                                   cPtrInfo.count, mode, flags, localMatrixPtr, colorSpace);
1017
1018    freeArraysThatAreNotMallocedByUsers(cPtrInfo.colorPtr, colors);
1019    pos && freeArraysThatAreNotMallocedByUsers(posPtr, pos);
1020    return lgs;
1021  };
1022
1023  CanvasKit.Shader.MakeRadialGradient = function(center, radius, colors, pos, mode, localMatrix, flags, colorSpace) {
1024    colorSpace = colorSpace || null;
1025    var cPtrInfo = copyFlexibleColorArray(colors);
1026    var posPtr = copy1dArray(pos, 'HEAPF32');
1027    flags = flags || 0;
1028    var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
1029
1030    var rgs = CanvasKit.Shader._MakeRadialGradient(center[0], center[1], radius, cPtrInfo.colorPtr,
1031                                                   cPtrInfo.colorType, posPtr, cPtrInfo.count, mode,
1032                                                   flags, localMatrixPtr, colorSpace);
1033
1034    freeArraysThatAreNotMallocedByUsers(cPtrInfo.colorPtr, colors);
1035    pos && freeArraysThatAreNotMallocedByUsers(posPtr, pos);
1036    return rgs;
1037  };
1038
1039  CanvasKit.Shader.MakeSweepGradient = function(cx, cy, colors, pos, mode, localMatrix, flags, startAngle, endAngle, colorSpace) {
1040    colorSpace = colorSpace || null;
1041    var cPtrInfo = copyFlexibleColorArray(colors);
1042    var posPtr = copy1dArray(pos, 'HEAPF32');
1043    flags = flags || 0;
1044    startAngle = startAngle || 0;
1045    endAngle = endAngle || 360;
1046    var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
1047
1048    var sgs = CanvasKit.Shader._MakeSweepGradient(cx, cy, cPtrInfo.colorPtr, cPtrInfo.colorType, posPtr,
1049                                                  cPtrInfo.count, mode,
1050                                                  startAngle, endAngle, flags,
1051                                                  localMatrixPtr, colorSpace);
1052
1053    freeArraysThatAreNotMallocedByUsers(cPtrInfo.colorPtr, colors);
1054    pos && freeArraysThatAreNotMallocedByUsers(posPtr, pos);
1055    return sgs;
1056  };
1057
1058  CanvasKit.Shader.MakeTwoPointConicalGradient = function(start, startRadius, end, endRadius,
1059                                                          colors, pos, mode, localMatrix, flags, colorSpace) {
1060    colorSpace = colorSpace || null;
1061    var cPtrInfo = copyFlexibleColorArray(colors);
1062    var posPtr =   copy1dArray(pos, 'HEAPF32');
1063    flags = flags || 0;
1064    var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
1065
1066    // Copy start and end to _scratchFourFloatsAPtr.
1067    var startEndPts = _scratchFourFloatsA['toTypedArray']();
1068    startEndPts.set(start);
1069    startEndPts.set(end, 2);
1070
1071    var rgs = CanvasKit.Shader._MakeTwoPointConicalGradient(_scratchFourFloatsAPtr,
1072                          startRadius, endRadius, cPtrInfo.colorPtr, cPtrInfo.colorType,
1073                          posPtr, cPtrInfo.count, mode, flags, localMatrixPtr, colorSpace);
1074
1075    freeArraysThatAreNotMallocedByUsers(cPtrInfo.colorPtr, colors);
1076    pos && freeArraysThatAreNotMallocedByUsers(posPtr, pos);
1077    return rgs;
1078  };
1079
1080  // Clients can pass in a Float32Array with length 4 to this and the results
1081  // will be copied into that array. Otherwise, a new TypedArray will be allocated
1082  // and returned.
1083  CanvasKit.Vertices.prototype.bounds = function(optionalOutputArray) {
1084    this._bounds(_scratchFourFloatsAPtr);
1085    var ta = _scratchFourFloatsA['toTypedArray']();
1086    if (optionalOutputArray) {
1087      optionalOutputArray.set(ta);
1088      return optionalOutputArray;
1089    }
1090    return ta.slice();
1091  };
1092
1093  // Run through the JS files that are added at compile time.
1094  if (CanvasKit._extraInitializations) {
1095    CanvasKit._extraInitializations.forEach(function(init) {
1096      init();
1097    });
1098  }
1099}; // end CanvasKit.onRuntimeInitialized, that is, anything changing prototypes or dynamic.
1100
1101// Accepts an object holding two canvaskit colors.
1102// {
1103//    ambient: [r, g, b, a],
1104//    spot: [r, g, b, a],
1105// }
1106// Returns the same format. Note, if malloced colors are passed in, the memory
1107// housing the passed in colors passed in will be overwritten with the computed
1108// tonal colors.
1109CanvasKit.computeTonalColors = function(tonalColors) {
1110    // copy the colors into WASM
1111    var cPtrAmbi = copyColorToWasmNoScratch(tonalColors['ambient']);
1112    var cPtrSpot = copyColorToWasmNoScratch(tonalColors['spot']);
1113    // The output of this function will be the same pointers we passed in.
1114    this._computeTonalColors(cPtrAmbi, cPtrSpot);
1115    // Read the results out.
1116    var result =  {
1117      'ambient': copyColorFromWasm(cPtrAmbi),
1118      'spot': copyColorFromWasm(cPtrSpot),
1119    };
1120    // If the user passed us malloced colors in here, we don't want to clean them up.
1121    freeArraysThatAreNotMallocedByUsers(cPtrAmbi, tonalColors['ambient']);
1122    freeArraysThatAreNotMallocedByUsers(cPtrSpot, tonalColors['spot']);
1123    return result;
1124};
1125
1126CanvasKit.LTRBRect = function(l, t, r, b) {
1127  return Float32Array.of(l, t, r, b);
1128};
1129
1130CanvasKit.XYWHRect = function(x, y, w, h) {
1131  return Float32Array.of(x, y, x+w, y+h);
1132};
1133
1134CanvasKit.LTRBiRect = function(l, t, r, b) {
1135  return Int32Array.of(l, t, r, b);
1136};
1137
1138CanvasKit.XYWHiRect = function(x, y, w, h) {
1139  return Int32Array.of(x, y, x+w, y+h);
1140};
1141
1142// RRectXY returns a TypedArray representing an RRect with the given rect and a radiusX and
1143// radiusY for all 4 corners.
1144CanvasKit.RRectXY = function(rect, rx, ry) {
1145  return Float32Array.of(
1146    rect[0], rect[1], rect[2], rect[3],
1147    rx, ry,
1148    rx, ry,
1149    rx, ry,
1150    rx, ry,
1151  );
1152};
1153
1154// data is a TypedArray or ArrayBuffer e.g. from fetch().then(resp.arrayBuffer())
1155CanvasKit.MakeAnimatedImageFromEncoded = function(data) {
1156  data = new Uint8Array(data);
1157
1158  var iptr = CanvasKit._malloc(data.byteLength);
1159  CanvasKit.HEAPU8.set(data, iptr);
1160  var img = CanvasKit._decodeAnimatedImage(iptr, data.byteLength);
1161  if (!img) {
1162    Debug('Could not decode animated image');
1163    return null;
1164  }
1165  return img;
1166};
1167
1168// data is a TypedArray or ArrayBuffer e.g. from fetch().then(resp.arrayBuffer())
1169CanvasKit.MakeImageFromEncoded = function(data) {
1170  data = new Uint8Array(data);
1171
1172  var iptr = CanvasKit._malloc(data.byteLength);
1173  CanvasKit.HEAPU8.set(data, iptr);
1174  var img = CanvasKit._decodeImage(iptr, data.byteLength);
1175  if (!img) {
1176    Debug('Could not decode image');
1177    return null;
1178  }
1179  return img;
1180};
1181
1182// A variable to hold a canvasElement which can be reused once created the first time.
1183var memoizedCanvas2dElement = null;
1184
1185// Alternative to CanvasKit.MakeImageFromEncoded. Allows for CanvasKit users to take advantage of
1186// browser APIs to decode images instead of using codecs included in the CanvasKit wasm binary.
1187// Expects that the canvasImageSource has already loaded/decoded.
1188// CanvasImageSource reference: https://developer.mozilla.org/en-US/docs/Web/API/CanvasImageSource
1189CanvasKit.MakeImageFromCanvasImageSource = function(canvasImageSource) {
1190  var width = canvasImageSource.width;
1191  var height = canvasImageSource.height;
1192
1193  if (!memoizedCanvas2dElement) {
1194    memoizedCanvas2dElement = document.createElement('canvas');
1195  }
1196  memoizedCanvas2dElement.width = width;
1197  memoizedCanvas2dElement.height = height;
1198
1199  var ctx2d = memoizedCanvas2dElement.getContext('2d');
1200  ctx2d.drawImage(canvasImageSource, 0, 0);
1201
1202  var imageData = ctx2d.getImageData(0, 0, width, height);
1203
1204  return CanvasKit.MakeImage({
1205      'width': width,
1206      'height': height,
1207      'alphaType': CanvasKit.AlphaType.Unpremul,
1208      'colorType': CanvasKit.ColorType.RGBA_8888,
1209      'colorSpace': CanvasKit.ColorSpace.SRGB
1210    }, imageData.data, 4 * width);
1211};
1212
1213// pixels may be an array but Uint8Array or Uint8ClampedArray is recommended,
1214// with the bytes representing the pixel values.
1215// (e.g. each set of 4 bytes could represent RGBA values for a single pixel).
1216CanvasKit.MakeImage = function(info, pixels, bytesPerRow) {
1217  var pptr = CanvasKit._malloc(pixels.length);
1218  CanvasKit.HEAPU8.set(pixels, pptr); // We always want to copy the bytes into the WASM heap.
1219  // No need to _free pptr, Image takes it with SkData::MakeFromMalloc
1220  return CanvasKit._MakeImage(info, pptr, pixels.length, bytesPerRow);
1221};
1222
1223// Colors may be a Uint32Array of int colors, a Flat Float32Array of float colors
1224// or a 2d Array of Float32Array(4) (deprecated)
1225// the underlying Skia function accepts only int colors so it is recommended
1226// to pass an array of int colors to avoid an extra conversion.
1227CanvasKit.MakeVertices = function(mode, positions, textureCoordinates, colors,
1228                                  indices, isVolatile) {
1229  // Default isVolatile to true if not set
1230  isVolatile = isVolatile === undefined ? true : isVolatile;
1231  var idxCount = (indices && indices.length) || 0;
1232
1233  var flags = 0;
1234  // These flags are from SkVertices.h and should be kept in sync with those.
1235  if (textureCoordinates && textureCoordinates.length) {
1236    flags |= (1 << 0);
1237  }
1238  if (colors && colors.length) {
1239    flags |= (1 << 1);
1240  }
1241  if (!isVolatile) {
1242    flags |= (1 << 2);
1243  }
1244
1245  var builder = new CanvasKit._VerticesBuilder(mode, positions.length / 2, idxCount, flags);
1246
1247  copy1dArray(positions, 'HEAPF32', builder.positions());
1248  if (builder.texCoords()) {
1249    copy1dArray(textureCoordinates, 'HEAPF32', builder.texCoords());
1250  }
1251  if (builder.colors()) {
1252      copy1dArray(assureIntColors(colors), 'HEAPU32', builder.colors());
1253  }
1254  if (builder.indices()) {
1255    copy1dArray(indices, 'HEAPU16', builder.indices());
1256  }
1257
1258  // Create the vertices, which owns the memory that the builder had allocated.
1259  return builder.detach();
1260};
1261