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. 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 11 // Add some helpers for matrices. This is ported from SkMatrix.cpp 12 // to save complexity and overhead of going back and forth between 13 // C++ and JS layers. 14 // I would have liked to use something like DOMMatrix, except it 15 // isn't widely supported (would need polyfills) and it doesn't 16 // have a mapPoints() function (which could maybe be tacked on here). 17 // If DOMMatrix catches on, it would be worth re-considering this usage. 18 CanvasKit.SkMatrix = {}; 19 function sdot(a, b, c, d, e, f) { 20 e = e || 0; 21 f = f || 0; 22 return a * b + c * d + e * f; 23 } 24 25 CanvasKit.SkMatrix.identity = function() { 26 return [ 27 1, 0, 0, 28 0, 1, 0, 29 0, 0, 1, 30 ]; 31 }; 32 33 // Return the inverse (if it exists) of this matrix. 34 // Otherwise, return the identity. 35 CanvasKit.SkMatrix.invert = function(m) { 36 var det = m[0]*m[4]*m[8] + m[1]*m[5]*m[6] + m[2]*m[3]*m[7] 37 - m[2]*m[4]*m[6] - m[1]*m[3]*m[8] - m[0]*m[5]*m[7]; 38 if (!det) { 39 SkDebug('Warning, uninvertible matrix'); 40 return CanvasKit.SkMatrix.identity(); 41 } 42 return [ 43 (m[4]*m[8] - m[5]*m[7])/det, (m[2]*m[7] - m[1]*m[8])/det, (m[1]*m[5] - m[2]*m[4])/det, 44 (m[5]*m[6] - m[3]*m[8])/det, (m[0]*m[8] - m[2]*m[6])/det, (m[2]*m[3] - m[0]*m[5])/det, 45 (m[3]*m[7] - m[4]*m[6])/det, (m[1]*m[6] - m[0]*m[7])/det, (m[0]*m[4] - m[1]*m[3])/det, 46 ]; 47 }; 48 49 // Maps the given points according to the passed in matrix. 50 // Results are done in place. 51 // See SkMatrix.h::mapPoints for the docs on the math. 52 CanvasKit.SkMatrix.mapPoints = function(matrix, ptArr) { 53 if (ptArr.length % 2) { 54 throw 'mapPoints requires an even length arr'; 55 } 56 for (var i = 0; i < ptArr.length; i+=2) { 57 var x = ptArr[i], y = ptArr[i+1]; 58 // Gx+Hy+I 59 var denom = matrix[6]*x + matrix[7]*y + matrix[8]; 60 // Ax+By+C 61 var xTrans = matrix[0]*x + matrix[1]*y + matrix[2]; 62 // Dx+Ey+F 63 var yTrans = matrix[3]*x + matrix[4]*y + matrix[5]; 64 ptArr[i] = xTrans/denom; 65 ptArr[i+1] = yTrans/denom; 66 } 67 return ptArr; 68 }; 69 70 CanvasKit.SkMatrix.multiply = function(m1, m2) { 71 var result = [0,0,0, 0,0,0, 0,0,0]; 72 for (var r = 0; r < 3; r++) { 73 for (var c = 0; c < 3; c++) { 74 // m1 and m2 are 1D arrays pretending to be 2D arrays 75 result[3*r + c] = sdot(m1[3*r + 0], m2[3*0 + c], 76 m1[3*r + 1], m2[3*1 + c], 77 m1[3*r + 2], m2[3*2 + c]); 78 } 79 } 80 return result; 81 } 82 83 // Return a matrix representing a rotation by n radians. 84 // px, py optionally say which point the rotation should be around 85 // with the default being (0, 0); 86 CanvasKit.SkMatrix.rotated = function(radians, px, py) { 87 px = px || 0; 88 py = py || 0; 89 var sinV = Math.sin(radians); 90 var cosV = Math.cos(radians); 91 return [ 92 cosV, -sinV, sdot( sinV, py, 1 - cosV, px), 93 sinV, cosV, sdot(-sinV, px, 1 - cosV, py), 94 0, 0, 1, 95 ]; 96 }; 97 98 CanvasKit.SkMatrix.scaled = function(sx, sy, px, py) { 99 px = px || 0; 100 py = py || 0; 101 return [ 102 sx, 0, px - sx * px, 103 0, sy, py - sy * py, 104 0, 0, 1, 105 ]; 106 }; 107 108 CanvasKit.SkMatrix.skewed = function(kx, ky, px, py) { 109 px = px || 0; 110 py = py || 0; 111 return [ 112 1, kx, -kx * px, 113 ky, 1, -ky * py, 114 0, 0, 1, 115 ]; 116 }; 117 118 CanvasKit.SkMatrix.translated = function(dx, dy) { 119 return [ 120 1, 0, dx, 121 0, 1, dy, 122 0, 0, 1, 123 ]; 124 }; 125 126 CanvasKit.SkPath.prototype.addArc = function(oval, startAngle, sweepAngle) { 127 // see arc() for the HTMLCanvas version 128 // note input angles are degrees. 129 this._addArc(oval, startAngle, sweepAngle); 130 return this; 131 }; 132 133 CanvasKit.SkPath.prototype.addPath = function() { 134 // Takes 1, 2, 7, or 10 required args, where the first arg is always the path. 135 // The last arg is optional and chooses between add or extend mode. 136 // The options for the remaining args are: 137 // - an array of 6 or 9 parameters (perspective is optional) 138 // - the 9 parameters of a full matrix or 139 // the 6 non-perspective params of a matrix. 140 var args = Array.prototype.slice.call(arguments); 141 var path = args[0]; 142 var extend = false; 143 if (typeof args[args.length-1] === "boolean") { 144 extend = args.pop(); 145 } 146 if (args.length === 1) { 147 // Add path, unchanged. Use identity matrix 148 this._addPath(path, 1, 0, 0, 149 0, 1, 0, 150 0, 0, 1, 151 extend); 152 } else if (args.length === 2) { 153 // User provided the 9 params of a full matrix as an array. 154 var a = args[1]; 155 this._addPath(path, a[0], a[1], a[2], 156 a[3], a[4], a[5], 157 a[6] || 0, a[7] || 0, a[8] || 1, 158 extend); 159 } else if (args.length === 7 || args.length === 10) { 160 // User provided the 9 params of a (full) matrix directly. 161 // (or just the 6 non perspective ones) 162 // These are in the same order as what Skia expects. 163 var a = args; 164 this._addPath(path, a[1], a[2], a[3], 165 a[4], a[5], a[6], 166 a[7] || 0, a[8] || 0, a[9] || 1, 167 extend); 168 } else { 169 SkDebug('addPath expected to take 1, 2, 7, or 10 required args. Got ' + args.length); 170 return null; 171 } 172 return this; 173 }; 174 175 CanvasKit.SkPath.prototype.addRect = function() { 176 // Takes 1, 2, 4 or 5 args 177 // - SkRect 178 // - SkRect, isCCW 179 // - left, top, right, bottom 180 // - left, top, right, bottom, isCCW 181 if (arguments.length === 1 || arguments.length === 2) { 182 var r = arguments[0]; 183 var ccw = arguments[1] || false; 184 this._addRect(r.fLeft, r.fTop, r.fRight, r.fBottom, ccw); 185 } else if (arguments.length === 4 || arguments.length === 5) { 186 var a = arguments; 187 this._addRect(a[0], a[1], a[2], a[3], a[4] || false); 188 } else { 189 SkDebug('addRect expected to take 1, 2, 4, or 5 args. Got ' + arguments.length); 190 return null; 191 } 192 return this; 193 }; 194 195 CanvasKit.SkPath.prototype.addRoundRect = function() { 196 // Takes 3, 4, 6 or 7 args 197 // - SkRect, radii, ccw 198 // - SkRect, rx, ry, ccw 199 // - left, top, right, bottom, radii, ccw 200 // - left, top, right, bottom, rx, ry, ccw 201 var args = arguments; 202 if (args.length === 3 || args.length === 6) { 203 var radii = args[args.length-2]; 204 } else if (args.length === 6 || args.length === 7){ 205 // duplicate the given (rx, ry) pairs for each corner. 206 var rx = args[args.length-3]; 207 var ry = args[args.length-2]; 208 var radii = [rx, ry, rx, ry, rx, ry, rx, ry]; 209 } else { 210 SkDebug('addRoundRect expected to take 3, 4, 6, or 7 args. Got ' + args.length); 211 return null; 212 } 213 if (radii.length !== 8) { 214 SkDebug('addRoundRect needs 8 radii provided. Got ' + radii.length); 215 return null; 216 } 217 var rptr = copy1dArray(radii, CanvasKit.HEAPF32); 218 if (args.length === 3 || args.length === 4) { 219 var r = args[0]; 220 var ccw = args[args.length - 1]; 221 this._addRoundRect(r.fLeft, r.fTop, r.fRight, r.fBottom, rptr, ccw); 222 } else if (args.length === 6 || args.length === 7) { 223 var a = args; 224 this._addRoundRect(a[0], a[1], a[2], a[3], rptr, ccw); 225 } 226 CanvasKit._free(rptr); 227 return this; 228 }; 229 230 CanvasKit.SkPath.prototype.arc = function(x, y, radius, startAngle, endAngle, ccw) { 231 // emulates the HTMLCanvas behavior. See addArc() for the SkPath version. 232 // Note input angles are radians. 233 var bounds = CanvasKit.LTRBRect(x-radius, y-radius, x+radius, y+radius); 234 var sweep = radiansToDegrees(endAngle - startAngle) - (360 * !!ccw); 235 var temp = new CanvasKit.SkPath(); 236 temp.addArc(bounds, radiansToDegrees(startAngle), sweep); 237 this.addPath(temp, true); 238 temp.delete(); 239 return this; 240 }; 241 242 CanvasKit.SkPath.prototype.arcTo = function() { 243 // takes 4, 5 or 7 args 244 // - 5 x1, y1, x2, y2, radius 245 // - 4 oval (as Rect), startAngle, sweepAngle, forceMoveTo 246 // - 7 x1, y1, x2, y2, startAngle, sweepAngle, forceMoveTo 247 var args = arguments; 248 if (args.length === 5) { 249 this._arcTo(args[0], args[1], args[2], args[3], args[4]); 250 } else if (args.length === 4) { 251 this._arcTo(args[0], args[1], args[2], args[3]); 252 } else if (args.length === 7) { 253 this._arcTo(CanvasKit.LTRBRect(args[0], args[1], args[2], args[3]), 254 args[4], args[5], args[6]); 255 } else { 256 throw 'Invalid args for arcTo. Expected 4, 5, or 7, got '+ args.length; 257 } 258 259 return this; 260 }; 261 262 CanvasKit.SkPath.prototype.close = function() { 263 this._close(); 264 return this; 265 }; 266 267 CanvasKit.SkPath.prototype.conicTo = function(x1, y1, x2, y2, w) { 268 this._conicTo(x1, y1, x2, y2, w); 269 return this; 270 }; 271 272 CanvasKit.SkPath.prototype.cubicTo = function(cp1x, cp1y, cp2x, cp2y, x, y) { 273 this._cubicTo(cp1x, cp1y, cp2x, cp2y, x, y); 274 return this; 275 }; 276 277 CanvasKit.SkPath.prototype.dash = function(on, off, phase) { 278 if (this._dash(on, off, phase)) { 279 return this; 280 } 281 return null; 282 }; 283 284 CanvasKit.SkPath.prototype.lineTo = function(x, y) { 285 this._lineTo(x, y); 286 return this; 287 }; 288 289 CanvasKit.SkPath.prototype.moveTo = function(x, y) { 290 this._moveTo(x, y); 291 return this; 292 }; 293 294 CanvasKit.SkPath.prototype.op = function(otherPath, op) { 295 if (this._op(otherPath, op)) { 296 return this; 297 } 298 return null; 299 }; 300 301 CanvasKit.SkPath.prototype.quadTo = function(cpx, cpy, x, y) { 302 this._quadTo(cpx, cpy, x, y); 303 return this; 304 }; 305 306 CanvasKit.SkPath.prototype.simplify = function() { 307 if (this._simplify()) { 308 return this; 309 } 310 return null; 311 }; 312 313 CanvasKit.SkPath.prototype.stroke = function(opts) { 314 // Fill out any missing values with the default values. 315 /** 316 * See externs.js for this definition 317 * @type {StrokeOpts} 318 */ 319 opts = opts || {}; 320 opts.width = opts.width || 1; 321 opts.miter_limit = opts.miter_limit || 4; 322 opts.cap = opts.cap || CanvasKit.StrokeCap.Butt; 323 opts.join = opts.join || CanvasKit.StrokeJoin.Miter; 324 opts.precision = opts.precision || 1; 325 if (this._stroke(opts)) { 326 return this; 327 } 328 return null; 329 }; 330 331 CanvasKit.SkPath.prototype.transform = function() { 332 // Takes 1 or 9 args 333 if (arguments.length === 1) { 334 // argument 1 should be a 6 or 9 element array. 335 var a = arguments[0]; 336 this._transform(a[0], a[1], a[2], 337 a[3], a[4], a[5], 338 a[6] || 0, a[7] || 0, a[8] || 1); 339 } else if (arguments.length === 6 || arguments.length === 9) { 340 // these arguments are the 6 or 9 members of the matrix 341 var a = arguments; 342 this._transform(a[0], a[1], a[2], 343 a[3], a[4], a[5], 344 a[6] || 0, a[7] || 0, a[8] || 1); 345 } else { 346 throw 'transform expected to take 1 or 9 arguments. Got ' + arguments.length; 347 } 348 return this; 349 }; 350 // isComplement is optional, defaults to false 351 CanvasKit.SkPath.prototype.trim = function(startT, stopT, isComplement) { 352 if (this._trim(startT, stopT, !!isComplement)) { 353 return this; 354 } 355 return null; 356 }; 357 358 // bones should be a 3d array. 359 // Each bone is a 3x2 transformation matrix in column major order: 360 // | scaleX skewX transX | 361 // | skewY scaleY transY | 362 // and bones is an array of those matrices. 363 // Returns a copy of this (SkVertices) with the bones applied. 364 CanvasKit.SkVertices.prototype.applyBones = function(bones) { 365 var bPtr = copy3dArray(bones, CanvasKit.HEAPF32); 366 var vert = this._applyBones(bPtr, bones.length); 367 CanvasKit._free(bPtr); 368 return vert; 369 } 370 371 CanvasKit.SkImage.prototype.encodeToData = function() { 372 if (!arguments.length) { 373 return this._encodeToData(); 374 } 375 376 if (arguments.length === 2) { 377 var a = arguments; 378 return this._encodeToDataWithFormat(a[0], a[1]); 379 } 380 381 throw 'encodeToData expected to take 0 or 2 arguments. Got ' + arguments.length; 382 } 383 384 // str can be either a text string or a ShapedText object 385 CanvasKit.SkCanvas.prototype.drawText = function(str, x, y, paint, font) { 386 if (typeof str === 'string') { 387 // lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten 388 // JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8 389 // Add 1 for null terminator 390 var strLen = lengthBytesUTF8(str) + 1; 391 var strPtr = CanvasKit._malloc(strLen); 392 393 stringToUTF8(str, strPtr, strLen); 394 this._drawSimpleText(strPtr, strLen, x, y, font, paint); 395 } else { 396 this._drawShapedText(str, x, y, paint); 397 } 398 } 399 400 // returns Uint8Array 401 CanvasKit.SkCanvas.prototype.readPixels = function(x, y, w, h, alphaType, 402 colorType, dstRowBytes) { 403 // supply defaults (which are compatible with HTMLCanvas's getImageData) 404 alphaType = alphaType || CanvasKit.AlphaType.Unpremul; 405 colorType = colorType || CanvasKit.ColorType.RGBA_8888; 406 dstRowBytes = dstRowBytes || (4 * w); 407 408 var len = h * dstRowBytes 409 var pptr = CanvasKit._malloc(len); 410 var ok = this._readPixels({ 411 'width': w, 412 'height': h, 413 'colorType': colorType, 414 'alphaType': alphaType, 415 }, pptr, dstRowBytes, x, y); 416 if (!ok) { 417 CanvasKit._free(pptr); 418 return null; 419 } 420 421 // The first typed array is just a view into memory. Because we will 422 // be free-ing that, we call slice to make a persistent copy. 423 var pixels = new Uint8Array(CanvasKit.HEAPU8.buffer, pptr, len).slice(); 424 CanvasKit._free(pptr); 425 return pixels; 426 } 427 428 // pixels is a TypedArray. No matter the input size, it will be treated as 429 // a Uint8Array (essentially, a byte array). 430 CanvasKit.SkCanvas.prototype.writePixels = function(pixels, srcWidth, srcHeight, 431 destX, destY, alphaType, colorType) { 432 if (pixels.byteLength % (srcWidth * srcHeight)) { 433 throw 'pixels length must be a multiple of the srcWidth * srcHeight'; 434 } 435 var bytesPerPixel = pixels.byteLength / (srcWidth * srcHeight); 436 // supply defaults (which are compatible with HTMLCanvas's putImageData) 437 alphaType = alphaType || CanvasKit.AlphaType.Unpremul; 438 colorType = colorType || CanvasKit.ColorType.RGBA_8888; 439 var srcRowBytes = bytesPerPixel * srcWidth; 440 441 var pptr = CanvasKit._malloc(pixels.byteLength); 442 CanvasKit.HEAPU8.set(pixels, pptr); 443 444 var ok = this._writePixels({ 445 'width': srcWidth, 446 'height': srcHeight, 447 'colorType': colorType, 448 'alphaType': alphaType, 449 }, pptr, srcRowBytes, destX, destY); 450 451 CanvasKit._free(pptr); 452 return ok; 453 } 454 455 // fontData should be an arrayBuffer 456 CanvasKit.SkFontMgr.prototype.MakeTypefaceFromData = function(fontData) { 457 var data = new Uint8Array(fontData); 458 459 var fptr = CanvasKit._malloc(data.byteLength); 460 CanvasKit.HEAPU8.set(data, fptr); 461 var font = this._makeTypefaceFromData(fptr, data.byteLength); 462 if (!font) { 463 SkDebug('Could not decode font data'); 464 // We do not need to free the data since the C++ will do that for us 465 // when the font is deleted (or fails to decode); 466 return null; 467 } 468 return font; 469 } 470 471 CanvasKit.SkTextBlob.MakeFromText = function(str, font) { 472 // lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten 473 // JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8 474 // Add 1 for null terminator 475 var strLen = lengthBytesUTF8(str) + 1; 476 var strPtr = CanvasKit._malloc(strLen); 477 // Add 1 for the null terminator. 478 stringToUTF8(str, strPtr, strLen); 479 480 var blob = CanvasKit.SkTextBlob._MakeFromText(strPtr, strLen - 1, font, CanvasKit.TextEncoding.UTF8); 481 if (!blob) { 482 SkDebug('Could not make textblob from string "' + str + '"'); 483 return null; 484 } 485 486 var origDelete = blob.delete.bind(blob); 487 blob.delete = function() { 488 CanvasKit._free(strPtr); 489 origDelete(); 490 } 491 return blob; 492 } 493 494 // Run through the JS files that are added at compile time. 495 if (CanvasKit._extraInitializations) { 496 CanvasKit._extraInitializations.forEach(function(init) { 497 init(); 498 }); 499 } 500 }; // end CanvasKit.onRuntimeInitialized, that is, anything changing prototypes or dynamic. 501 502 CanvasKit.LTRBRect = function(l, t, r, b) { 503 return { 504 fLeft: l, 505 fTop: t, 506 fRight: r, 507 fBottom: b, 508 }; 509 } 510 511 CanvasKit.XYWHRect = function(x, y, w, h) { 512 return { 513 fLeft: x, 514 fTop: y, 515 fRight: x+w, 516 fBottom: y+h, 517 }; 518 } 519 520 CanvasKit.MakePathFromCmds = function(cmds) { 521 var ptrLen = loadCmdsTypedArray(cmds); 522 var path = CanvasKit._MakePathFromCmds(ptrLen[0], ptrLen[1]); 523 CanvasKit._free(ptrLen[0]); 524 return path; 525 } 526 527 CanvasKit.MakeSkDashPathEffect = function(intervals, phase) { 528 if (!phase) { 529 phase = 0; 530 } 531 if (!intervals.length || intervals.length % 2 === 1) { 532 throw 'Intervals array must have even length'; 533 } 534 var ptr = copy1dArray(intervals, CanvasKit.HEAPF32); 535 var dpe = CanvasKit._MakeSkDashPathEffect(ptr, intervals.length, phase); 536 CanvasKit._free(ptr); 537 return dpe; 538 } 539 540 // data is a TypedArray or ArrayBuffer e.g. from fetch().then(resp.arrayBuffer()) 541 CanvasKit.MakeImageFromEncoded = function(data) { 542 data = new Uint8Array(data); 543 544 var iptr = CanvasKit._malloc(data.byteLength); 545 CanvasKit.HEAPU8.set(data, iptr); 546 var img = CanvasKit._decodeImage(iptr, data.byteLength); 547 if (!img) { 548 SkDebug('Could not decode image'); 549 return null; 550 } 551 return img; 552 } 553 554 // imgData is an SkImage, e.g. from MakeImageFromEncoded or SkSurface.makeImageSnapshot 555 CanvasKit.MakeImageShader = function(img, xTileMode, yTileMode, clampUnpremul, localMatrix) { 556 if (!img) { 557 return null; 558 } 559 clampUnpremul = clampUnpremul || false; 560 if (localMatrix) { 561 // Add perspective args if not provided. 562 if (localMatrix.length === 6) { 563 localMatrix.push(0, 0, 1); 564 } 565 return CanvasKit._MakeImageShader(img, xTileMode, yTileMode, clampUnpremul, localMatrix); 566 } else { 567 return CanvasKit._MakeImageShader(img, xTileMode, yTileMode, clampUnpremul); 568 } 569 } 570 571 // pixels is a Uint8Array 572 CanvasKit.MakeImage = function(pixels, width, height, alphaType, colorType) { 573 var bytesPerPixel = pixels.byteLength / (width * height); 574 var info = { 575 'width': width, 576 'height': height, 577 'alphaType': alphaType, 578 'colorType': colorType, 579 }; 580 var pptr = CanvasKit._malloc(pixels.byteLength); 581 CanvasKit.HEAPU8.set(pixels, pptr); 582 // No need to _free iptr, Image takes it with SkData::MakeFromMalloc 583 584 return CanvasKit._MakeImage(info, pptr, pixels.byteLength, width * bytesPerPixel); 585 } 586 587 CanvasKit.MakeLinearGradientShader = function(start, end, colors, pos, mode, localMatrix, flags) { 588 var colorPtr = copy1dArray(colors, CanvasKit.HEAP32); 589 var posPtr = copy1dArray(pos, CanvasKit.HEAPF32); 590 flags = flags || 0; 591 592 if (localMatrix) { 593 // Add perspective args if not provided. 594 if (localMatrix.length === 6) { 595 localMatrix.push(0, 0, 1); 596 } 597 var lgs = CanvasKit._MakeLinearGradientShader(start, end, colorPtr, posPtr, 598 colors.length, mode, flags, localMatrix); 599 } else { 600 var lgs = CanvasKit._MakeLinearGradientShader(start, end, colorPtr, posPtr, 601 colors.length, mode, flags); 602 } 603 604 CanvasKit._free(colorPtr); 605 CanvasKit._free(posPtr); 606 return lgs; 607 } 608 609 CanvasKit.MakeRadialGradientShader = function(center, radius, colors, pos, mode, localMatrix, flags) { 610 var colorPtr = copy1dArray(colors, CanvasKit.HEAP32); 611 var posPtr = copy1dArray(pos, CanvasKit.HEAPF32); 612 flags = flags || 0; 613 614 if (localMatrix) { 615 // Add perspective args if not provided. 616 if (localMatrix.length === 6) { 617 localMatrix.push(0, 0, 1); 618 } 619 var rgs = CanvasKit._MakeRadialGradientShader(center, radius, colorPtr, posPtr, 620 colors.length, mode, flags, localMatrix); 621 } else { 622 var rgs = CanvasKit._MakeRadialGradientShader(center, radius, colorPtr, posPtr, 623 colors.length, mode, flags); 624 } 625 626 CanvasKit._free(colorPtr); 627 CanvasKit._free(posPtr); 628 return rgs; 629 } 630 631 CanvasKit.MakeTwoPointConicalGradientShader = function(start, startRadius, end, endRadius, 632 colors, pos, mode, localMatrix, flags) { 633 var colorPtr = copy1dArray(colors, CanvasKit.HEAP32); 634 var posPtr = copy1dArray(pos, CanvasKit.HEAPF32); 635 flags = flags || 0; 636 637 if (localMatrix) { 638 // Add perspective args if not provided. 639 if (localMatrix.length === 6) { 640 localMatrix.push(0, 0, 1); 641 } 642 var rgs = CanvasKit._MakeTwoPointConicalGradientShader( 643 start, startRadius, end, endRadius, 644 colorPtr, posPtr, colors.length, mode, flags, localMatrix); 645 } else { 646 var rgs = CanvasKit._MakeTwoPointConicalGradientShader( 647 start, startRadius, end, endRadius, 648 colorPtr, posPtr, colors.length, mode, flags); 649 } 650 651 CanvasKit._free(colorPtr); 652 CanvasKit._free(posPtr); 653 return rgs; 654 } 655 656 CanvasKit.MakeSkVertices = function(mode, positions, textureCoordinates, colors, 657 boneIndices, boneWeights, indices, isVolatile) { 658 var positionPtr = copy2dArray(positions, CanvasKit.HEAPF32); 659 var texPtr = copy2dArray(textureCoordinates, CanvasKit.HEAPF32); 660 // Since we write the colors to memory as signed integers (JSColor), we can 661 // read them out on the other side as unsigned ints (SkColor) just fine 662 // - it's effectively casting. 663 var colorPtr = copy1dArray(colors, CanvasKit.HEAP32); 664 665 var boneIdxPtr = copy2dArray(boneIndices, CanvasKit.HEAP32); 666 var boneWtPtr = copy2dArray(boneWeights, CanvasKit.HEAPF32); 667 var idxPtr = copy1dArray(indices, CanvasKit.HEAPU16); 668 669 // Default isVolitile to true if not set 670 isVolatile = isVolatile === undefined ? true : isVolatile; 671 672 var idxCount = (indices && indices.length) || 0; 673 // _MakeVertices will copy all the values in, so we are free to release 674 // the memory after. 675 var vertices = CanvasKit._MakeSkVertices(mode, positions.length, positionPtr, 676 texPtr, colorPtr, boneIdxPtr, boneWtPtr, 677 idxCount, idxPtr, isVolatile); 678 positionPtr && CanvasKit._free(positionPtr); 679 texPtr && CanvasKit._free(texPtr); 680 colorPtr && CanvasKit._free(colorPtr); 681 idxPtr && CanvasKit._free(idxPtr); 682 boneIdxPtr && CanvasKit._free(boneIdxPtr); 683 boneWtPtr && CanvasKit._free(boneWtPtr); 684 return vertices; 685 };