[canvaskit] Use scratch arrays for colors and matrices

At startup, we allocate a few scratch arrays and then use those
instead of having to malloc and free a bunch of arrays during
runtime.

The benchmark that was added is a bit noisy (probably because
of the garbage collection going on from the created Float32Arrays),
but a few percent faster.

We also don't set the paragraph background/foreground colors to
transparent because we check them being falsey before sending them
over the wire. I noticed that if foreground was transparent black,
no text shows up at all, which was unexpected.

Change-Id: I9f3a590a122d7de222cb5f58ea40e86b2d261c96
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/292685
Reviewed-by: Nathaniel Nifong <nifong@google.com>
diff --git a/modules/canvaskit/interface.js b/modules/canvaskit/interface.js
index 05ff59e..7b5017a 100644
--- a/modules/canvaskit/interface.js
+++ b/modules/canvaskit/interface.js
@@ -8,6 +8,13 @@
 CanvasKit.onRuntimeInitialized = function() {
   // All calls to 'this' need to go in externs.js so closure doesn't minify them away.
 
+  _scratchColorPtr = CanvasKit._malloc(4 * 4); // 4 32bit floats
+
+  _scratch4x4Matrix = CanvasKit.Malloc(Float32Array, 16); // 16 matrix scalars.
+  _scratch4x4MatrixPtr = _scratch4x4Matrix.byteOffset;
+
+  _scratch3x3Matrix = CanvasKit.Malloc(Float32Array, 9); // 9 matrix scalars.
+  _scratch3x3MatrixPtr = _scratch3x3Matrix.byteOffset;
   // Create single copies of all three supported color spaces
   // These are sk_sp<SkColorSpace>
   CanvasKit.SkColorSpace.SRGB = CanvasKit.SkColorSpace._MakeSRGB();
@@ -755,16 +762,12 @@
 
   CanvasKit.SkPath.prototype.stroke = function(opts) {
     // Fill out any missing values with the default values.
-    /**
-     * See externs.js for this definition
-     * @type {StrokeOpts}
-     */
     opts = opts || {};
-    opts.width = opts.width || 1;
-    opts.miter_limit = opts.miter_limit || 4;
-    opts.cap = opts.cap || CanvasKit.StrokeCap.Butt;
-    opts.join = opts.join || CanvasKit.StrokeJoin.Miter;
-    opts.precision = opts.precision || 1;
+    opts['width'] = opts['width'] || 1;
+    opts['miter_limit'] = opts['miter_limit'] || 4;
+    opts['cap'] = opts['cap'] || CanvasKit.StrokeCap.Butt;
+    opts['join'] = opts['join'] || CanvasKit.StrokeJoin.Miter;
+    opts['precision'] = opts['precision'] || 1;
     if (this._stroke(opts)) {
       return this;
     }
@@ -813,9 +816,7 @@
 
   CanvasKit.SkImage.prototype.makeShader = function(xTileMode, yTileMode, localMatrix) {
     var localMatrixPtr = copy3x3MatrixToWasm(localMatrix);
-    var shader = this._makeShader(xTileMode, yTileMode, localMatrixPtr);
-    freeArraysThatAreNotMallocedByUsers(localMatrixPtr, localMatrix);
-    return shader;
+    return this._makeShader(xTileMode, yTileMode, localMatrixPtr);
   }
 
   CanvasKit.SkImage.prototype.readPixels = function(imageInfo, srcX, srcY) {
@@ -860,9 +861,8 @@
 
   // Accepts an array of four numbers in the range of 0-1 representing a 4f color
   CanvasKit.SkCanvas.prototype.clear = function (color4f) {
-    var cPtr = copy1dArray(color4f, CanvasKit.HEAPF32);
+    var cPtr = copyColorToWasm(color4f);
     this._clear(cPtr);
-    freeArraysThatAreNotMallocedByUsers(cPtr, color4f);
   }
 
   // concat takes a 3x2, a 3x3, or a 4x4 matrix and upscales it (if needed) to 4x4. This is because
@@ -870,7 +870,6 @@
   CanvasKit.SkCanvas.prototype.concat = function(matr) {
     var matrPtr = copy4x4MatrixToWasm(matr);
     this._concat(matrPtr);
-    freeArraysThatAreNotMallocedByUsers(matrPtr, matr);
   }
 
   // Deprecated - just use concat
@@ -940,13 +939,12 @@
   }
 
   CanvasKit.SkCanvas.prototype.drawColor = function (color4f, mode) {
-    var cPtr = copy1dArray(color4f, CanvasKit.HEAPF32);
+    var cPtr = copyColorToWasm(color4f);
     if (mode !== undefined) {
       this._drawColor(cPtr, mode);
     } else {
       this._drawColor(cPtr);
     }
-    freeArraysThatAreNotMallocedByUsers(cPtr, color4f);
   }
 
   // points is either an array of [x, y] where x and y are numbers or
@@ -969,8 +967,8 @@
   }
 
   CanvasKit.SkCanvas.prototype.drawShadow = function(path, zPlaneParams, lightPos, lightRadius, ambientColor, spotColor, flags) {
-    var ambiPtr = copy1dArray(ambientColor, CanvasKit.HEAPF32);
-    var spotPtr = copy1dArray(spotColor, CanvasKit.HEAPF32);
+    var ambiPtr = copyColorToWasmNoScratch(ambientColor);
+    var spotPtr = copyColorToWasmNoScratch(spotColor);
     this._drawShadow(path, zPlaneParams, lightPos, lightRadius, ambiPtr, spotPtr, flags);
     freeArraysThatAreNotMallocedByUsers(ambiPtr, ambientColor);
     freeArraysThatAreNotMallocedByUsers(spotPtr, spotColor);
@@ -978,36 +976,32 @@
 
   // getLocalToDevice returns a 4x4 matrix.
   CanvasKit.SkCanvas.prototype.getLocalToDevice = function() {
-    var matrPtr = CanvasKit._malloc(16 * 4); // allocate space for the matrix
     // _getLocalToDevice will copy the values into the pointer.
-    this._getLocalToDevice(matrPtr);
-    return copy4x4MatrixFromWasm(matrPtr);
+    this._getLocalToDevice(_scratch4x4MatrixPtr);
+    return copy4x4MatrixFromWasm(_scratch4x4MatrixPtr);
   }
 
   // findMarkedCTM returns a 4x4 matrix, or null if a matrix was not found at
   // the provided marker.
   CanvasKit.SkCanvas.prototype.findMarkedCTM = function(marker) {
-    var matrPtr = CanvasKit._malloc(16 * 4); // allocate space for the matrix
     // _getLocalToDevice will copy the values into the pointer.
-    var found = this._findMarkedCTM(marker, matrPtr);
+    var found = this._findMarkedCTM(marker, _scratch4x4MatrixPtr);
     if (!found) {
       return null;
     }
-    return copy4x4MatrixFromWasm(matrPtr);
+    return copy4x4MatrixFromWasm(_scratch4x4MatrixPtr);
   }
 
   // getTotalMatrix returns the current matrix as a 3x3 matrix.
   CanvasKit.SkCanvas.prototype.getTotalMatrix = function() {
-    var matrPtr = CanvasKit._malloc(9 * 4); // allocate space for the matrix
     // _getTotalMatrix will copy the values into the pointer.
-    this._getTotalMatrix(matrPtr);
+    this._getTotalMatrix(_scratch3x3MatrixPtr);
     // read them out into an array. TODO(kjlubick): If we change SkMatrix to be
     // typedArrays, then we should return a typed array here too.
     var rv = new Array(9);
     for (var i = 0; i < 9; i++) {
-      rv[i] = CanvasKit.HEAPF32[matrPtr/4 + i]; // divide by 4 to "cast" to float.
+      rv[i] = CanvasKit.HEAPF32[_scratch3x3MatrixPtr/4 + i]; // divide by 4 to "cast" to float.
     }
-    CanvasKit._free(matrPtr);
     return rv;
   }
 
@@ -1072,9 +1066,8 @@
   }
 
   CanvasKit.SkColorFilter.MakeBlend = function(color4f, mode) {
-    var cPtr = copy1dArray(color4f, CanvasKit.HEAPF32);
+    var cPtr = copyColorToWasm(color4f);
     var result = CanvasKit.SkColorFilter._MakeBlend(cPtr, mode);
-    freeArraysThatAreNotMallocedByUsers(cPtr, color4f);
     return result;
   }
 
@@ -1092,24 +1085,19 @@
 
   CanvasKit.SkImageFilter.MakeMatrixTransform = function(matr, filterQuality, input) {
     var matrPtr = copy3x3MatrixToWasm(matr);
-    var imgF = CanvasKit.SkImageFilter._MakeMatrixTransform(matrPtr, filterQuality, input);
-
-    freeArraysThatAreNotMallocedByUsers(matrPtr, matr);
-    return imgF;
+    return CanvasKit.SkImageFilter._MakeMatrixTransform(matrPtr, filterQuality, input);
   }
 
   CanvasKit.SkPaint.prototype.getColor = function() {
-    var cPtr = CanvasKit._malloc(16); // 4 floats, 4 bytes each
-    this._getColor(cPtr);
-    return copyColorFromWasm(cPtr);
+    this._getColor(_scratchColorPtr);
+    return copyColorFromWasm(_scratchColorPtr);
   }
 
   CanvasKit.SkPaint.prototype.setColor = function(color4f, colorSpace) {
     colorSpace = colorSpace || null; // null will be replaced with sRGB in the C++ method.
     // emscripten wouldn't bind undefined to the sk_sp<SkColorSpace> expected here.
-    var cPtr = copy1dArray(color4f, CanvasKit.HEAPF32);
+    var cPtr = copyColorToWasm(color4f);
     this._setColor(cPtr, colorSpace);
-    freeArraysThatAreNotMallocedByUsers(cPtr, color4f);
   }
 
   CanvasKit.SkSurface.prototype.captureFrameAsSkPicture = function(drawFrame) {
@@ -1175,9 +1163,8 @@
 
   CanvasKit.SkShader.Color = function(color4f, colorSpace) {
     colorSpace = colorSpace || null
-    var cPtr = copy1dArray(color4f, CanvasKit.HEAPF32);
+    var cPtr = copyColorToWasm(color4f);
     var result = CanvasKit.SkShader._Color(cPtr, colorSpace);
-    freeArraysThatAreNotMallocedByUsers(cPtr, color4f);
     return result;
   }
 
@@ -1191,7 +1178,6 @@
     var lgs = CanvasKit._MakeLinearGradientShader(start, end, colorPtr, posPtr,
                                                   colors.length, mode, flags, localMatrixPtr, colorSpace);
 
-    freeArraysThatAreNotMallocedByUsers(localMatrixPtr, localMatrix);
     CanvasKit._free(colorPtr);
     freeArraysThatAreNotMallocedByUsers(posPtr, pos);
     return lgs;
@@ -1207,7 +1193,6 @@
     var rgs = CanvasKit._MakeRadialGradientShader(center, radius, colorPtr, posPtr,
                                                   colors.length, mode, flags, localMatrixPtr, colorSpace);
 
-    freeArraysThatAreNotMallocedByUsers(localMatrixPtr, localMatrix);
     CanvasKit._free(colorPtr);
     freeArraysThatAreNotMallocedByUsers(posPtr, pos);
     return rgs;
@@ -1227,7 +1212,6 @@
                                                  startAngle, endAngle, flags,
                                                  localMatrixPtr, colorSpace);
 
-    freeArraysThatAreNotMallocedByUsers(localMatrixPtr, localMatrix);
     CanvasKit._free(colorPtr);
     freeArraysThatAreNotMallocedByUsers(posPtr, pos);
     return sgs;
@@ -1245,7 +1229,6 @@
                           start, startRadius, end, endRadius,
                           colorPtr, posPtr, colors.length, mode, flags, localMatrixPtr, colorSpace);
 
-    freeArraysThatAreNotMallocedByUsers(localMatrixPtr, localMatrix);
     CanvasKit._free(colorPtr);
     freeArraysThatAreNotMallocedByUsers(posPtr, pos);
     return rgs;
@@ -1272,13 +1255,15 @@
 // }
 // Returns the same format
 CanvasKit.computeTonalColors = function(tonalColors) {
-    var cPtrAmbi = copy1dArray(tonalColors['ambient'], CanvasKit.HEAPF32);
-    var cPtrSpot = copy1dArray(tonalColors['spot'], CanvasKit.HEAPF32);
+    var cPtrAmbi = copyColorToWasmNoScratch(tonalColors['ambient']);
+    var cPtrSpot = copyColorToWasmNoScratch(tonalColors['spot']);
     this._computeTonalColors(cPtrAmbi, cPtrSpot);
     var result =  {
       'ambient': copyColorFromWasm(cPtrAmbi),
       'spot': copyColorFromWasm(cPtrSpot),
     }
+    freeArraysThatAreNotMallocedByUsers(cPtrAmbi);
+    freeArraysThatAreNotMallocedByUsers(cPtrSpot);
     return result;
 }