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