1// Adds any extra JS functions/helpers we want to the PathKit Library. 2// Wrapped in a function to avoid leaking global variables. 3(function(PathKit){ 4 5 // Caching the Float32Arrays can save having to reallocate them 6 // over and over again. 7 var Float32ArrayCache = {}; 8 9 // Takes a 2D array of commands and puts them into the WASM heap 10 // as a 1D array. This allows them to referenced from the C++ code. 11 // Returns a 2 element array, with the first item being essentially a 12 // pointer to the array and the second item being the length of 13 // the new 1D array. 14 // 15 // Example usage: 16 // let cmds = [ 17 // [PathKit.MOVE_VERB, 0, 10], 18 // [PathKit.LINE_VERB, 30, 40], 19 // [PathKit.QUAD_VERB, 20, 50, 45, 60], 20 // ]; 21 // 22 // // The following uses ES6 syntactic sugar "Array Destructuring". 23 // // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Array_destructuring 24 // let [ptr, len] = PathKit.loadCmdsTypedArray(cmds); 25 // let path = PathKit.FromCmds(ptr, len); 26 // 27 // If arguments at index 1... in each cmd row are strings, they will be 28 // parsed as hex, and then converted to floats using SkBits2FloatUnsigned 29 PathKit.loadCmdsTypedArray = function(arr) { 30 var len = 0; 31 for (var r = 0; r < arr.length; r++) { 32 len += arr[r].length; 33 } 34 35 var ta; 36 if (Float32ArrayCache[len]) { 37 ta = Float32ArrayCache[len]; 38 } else { 39 ta = new Float32Array(len); 40 Float32ArrayCache[len] = ta; 41 } 42 // Flatten into a 1d array 43 var i = 0; 44 for (var r = 0; r < arr.length; r++) { 45 for (var c = 0; c < arr[r].length; c++) { 46 var item = arr[r][c]; 47 if (typeof item === 'string') { 48 // Converts hex to an int, which can be passed to SkBits2FloatUnsigned 49 item = PathKit.SkBits2FloatUnsigned(parseInt(item)); 50 } 51 ta[i] = item; 52 i++; 53 } 54 } 55 56 var ptr = PathKit._malloc(ta.length * ta.BYTES_PER_ELEMENT); 57 PathKit.HEAPF32.set(ta, ptr / ta.BYTES_PER_ELEMENT); 58 return [ptr, len]; 59 } 60 61 // Experimentation has shown that using TypedArrays to pass arrays from 62 // JS to C++ is faster than passing the JS Arrays across. 63 // See above for example of cmds. 64 PathKit.FromCmds = function(cmds) { 65 var ptrLen = PathKit.loadCmdsTypedArray(cmds); 66 var path = PathKit._FromCmds(ptrLen[0], ptrLen[1]); 67 // TODO(kjlubick): cache this memory blob somehow. 68 PathKit._free(ptrLen[0]); 69 return path; 70 } 71 72 /** 73 * A common pattern is to call this function in sequence with the same 74 * params. We can just remember the last one to speed things up. 75 * Caching in this way is about a 10-15x speed up. 76 * See externs.js for this definition 77 * @type {CubicMap} 78 */ 79 var cachedMap; 80 var _cpx1, _cpy1, _cpx2, _cpy2; 81 82 PathKit.cubicYFromX = function(cpx1, cpy1, cpx2, cpy2, X) { 83 if (!cachedMap || _cpx1 !== cpx1 || _cpy1 !== cpy1 || 84 _cpx2 !== cpx2 || _cpy2 !== cpy2) { 85 if (cachedMap) { 86 // Delete previous cached map to avoid memory leaks. 87 cachedMap.delete() 88 } 89 cachedMap = new PathKit._SkCubicMap([cpx1, cpy1], [cpx2, cpy2]); 90 _cpx1 = cpx1, _cpy1 = cpy1, _cpx2 = cpx2, _cpy2 = cpy2; 91 } 92 return cachedMap.computeYFromX(X); 93 } 94 95 PathKit.cubicPtFromT = function(cpx1, cpy1, cpx2, cpy2, T) { 96 if (!cachedMap || _cpx1 !== cpx1 || _cpy1 !== cpy1 || 97 _cpx2 !== cpx2 || _cpy2 !== cpy2) { 98 if (cachedMap) { 99 // Delete previous cached map to avoid memory leaks. 100 cachedMap.delete() 101 } 102 cachedMap = new PathKit._SkCubicMap([cpx1, cpy1], [cpx2, cpy2]); 103 _cpx1 = cpx1, _cpy1 = cpy1, _cpx2 = cpx2, _cpy2 = cpy2; 104 } 105 return cachedMap.computePtFromT(T); 106 } 107}(Module)); // When this file is loaded in, the high level object is "Module"; 108 109