1*c8dee2aaSAndroid Build Coastguard Workerdescribe('PathKit\'s Path2D API', function() { 2*c8dee2aaSAndroid Build Coastguard Worker it('can do everything in the Path2D API w/o crashing', function(done) { 3*c8dee2aaSAndroid Build Coastguard Worker LoadPathKit.then(catchException(done, () => { 4*c8dee2aaSAndroid Build Coastguard Worker // This is taken from example.html 5*c8dee2aaSAndroid Build Coastguard Worker let path = PathKit.NewPath(); 6*c8dee2aaSAndroid Build Coastguard Worker 7*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(20, 5); 8*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(30, 20); 9*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(40, 10); 10*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(50, 20); 11*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(60, 0); 12*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(20, 5); 13*c8dee2aaSAndroid Build Coastguard Worker 14*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(20, 80); 15*c8dee2aaSAndroid Build Coastguard Worker path.bezierCurveTo(90, 10, 160, 150, 190, 10); 16*c8dee2aaSAndroid Build Coastguard Worker 17*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(36, 148); 18*c8dee2aaSAndroid Build Coastguard Worker path.quadraticCurveTo(66, 188, 120, 136); 19*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(36, 148); 20*c8dee2aaSAndroid Build Coastguard Worker 21*c8dee2aaSAndroid Build Coastguard Worker path.rect(5, 170, 20, 20); 22*c8dee2aaSAndroid Build Coastguard Worker 23*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(150, 180); 24*c8dee2aaSAndroid Build Coastguard Worker path.arcTo(150, 100, 50, 200, 20); 25*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(160, 160); 26*c8dee2aaSAndroid Build Coastguard Worker 27*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(20, 120); 28*c8dee2aaSAndroid Build Coastguard Worker path.arc(20, 120, 18, 0, 1.75 * Math.PI); 29*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(20, 120); 30*c8dee2aaSAndroid Build Coastguard Worker 31*c8dee2aaSAndroid Build Coastguard Worker let secondPath = PathKit.NewPath(); 32*c8dee2aaSAndroid Build Coastguard Worker secondPath.ellipse(130, 25, 30, 10, -1*Math.PI/8, Math.PI/6, 1.5*Math.PI, false); 33*c8dee2aaSAndroid Build Coastguard Worker 34*c8dee2aaSAndroid Build Coastguard Worker path.addPath(secondPath); 35*c8dee2aaSAndroid Build Coastguard Worker 36*c8dee2aaSAndroid Build Coastguard Worker let m = document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGMatrix(); 37*c8dee2aaSAndroid Build Coastguard Worker m.a = 1; m.b = 0; 38*c8dee2aaSAndroid Build Coastguard Worker m.c = 0; m.d = 1; 39*c8dee2aaSAndroid Build Coastguard Worker m.e = 0; m.f = 20.5; 40*c8dee2aaSAndroid Build Coastguard Worker 41*c8dee2aaSAndroid Build Coastguard Worker path.addPath(secondPath, m); 42*c8dee2aaSAndroid Build Coastguard Worker 43*c8dee2aaSAndroid Build Coastguard Worker let canvas = document.createElement('canvas'); 44*c8dee2aaSAndroid Build Coastguard Worker let canvasCtx = canvas.getContext('2d'); 45*c8dee2aaSAndroid Build Coastguard Worker // Set canvas size and make it a bit bigger to zoom in on the lines 46*c8dee2aaSAndroid Build Coastguard Worker standardizedCanvasSize(canvasCtx); 47*c8dee2aaSAndroid Build Coastguard Worker canvasCtx.scale(3.0, 3.0); 48*c8dee2aaSAndroid Build Coastguard Worker canvasCtx.fillStyle = 'blue'; 49*c8dee2aaSAndroid Build Coastguard Worker canvasCtx.stroke(path.toPath2D()); 50*c8dee2aaSAndroid Build Coastguard Worker 51*c8dee2aaSAndroid Build Coastguard Worker let svgPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 52*c8dee2aaSAndroid Build Coastguard Worker svgPath.setAttribute('stroke', 'black'); 53*c8dee2aaSAndroid Build Coastguard Worker svgPath.setAttribute('fill', 'rgba(255,255,255,0.0)'); 54*c8dee2aaSAndroid Build Coastguard Worker svgPath.setAttribute('transform', 'scale(3.0, 3.0)'); 55*c8dee2aaSAndroid Build Coastguard Worker svgPath.setAttribute('d', path.toSVGString()); 56*c8dee2aaSAndroid Build Coastguard Worker 57*c8dee2aaSAndroid Build Coastguard Worker let newSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); 58*c8dee2aaSAndroid Build Coastguard Worker newSVG.appendChild(svgPath); 59*c8dee2aaSAndroid Build Coastguard Worker newSVG.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); 60*c8dee2aaSAndroid Build Coastguard Worker newSVG.setAttribute('width', 600); 61*c8dee2aaSAndroid Build Coastguard Worker newSVG.setAttribute('height', 600); 62*c8dee2aaSAndroid Build Coastguard Worker 63*c8dee2aaSAndroid Build Coastguard Worker path.delete(); 64*c8dee2aaSAndroid Build Coastguard Worker secondPath.delete(); 65*c8dee2aaSAndroid Build Coastguard Worker 66*c8dee2aaSAndroid Build Coastguard Worker reportCanvas(canvas, 'path2D_api_example').then(() => { 67*c8dee2aaSAndroid Build Coastguard Worker reportSVG(newSVG, 'path2D_api_example').then(() => { 68*c8dee2aaSAndroid Build Coastguard Worker done(); 69*c8dee2aaSAndroid Build Coastguard Worker }).catch(reportError(done)); 70*c8dee2aaSAndroid Build Coastguard Worker }).catch(reportError(done)); 71*c8dee2aaSAndroid Build Coastguard Worker })); 72*c8dee2aaSAndroid Build Coastguard Worker }); 73*c8dee2aaSAndroid Build Coastguard Worker 74*c8dee2aaSAndroid Build Coastguard Worker it('can chain by returning the same object', function(done) { 75*c8dee2aaSAndroid Build Coastguard Worker LoadPathKit.then(catchException(done, () => { 76*c8dee2aaSAndroid Build Coastguard Worker let path = PathKit.NewPath(); 77*c8dee2aaSAndroid Build Coastguard Worker 78*c8dee2aaSAndroid Build Coastguard Worker let p1 = path.moveTo(20, 5) 79*c8dee2aaSAndroid Build Coastguard Worker .lineTo(30, 20) 80*c8dee2aaSAndroid Build Coastguard Worker .quadTo(66, 188, 120, 136) 81*c8dee2aaSAndroid Build Coastguard Worker .close(); 82*c8dee2aaSAndroid Build Coastguard Worker 83*c8dee2aaSAndroid Build Coastguard Worker // these should be the same object 84*c8dee2aaSAndroid Build Coastguard Worker expect(path === p1).toBe(true); 85*c8dee2aaSAndroid Build Coastguard Worker p1.delete(); 86*c8dee2aaSAndroid Build Coastguard Worker try { 87*c8dee2aaSAndroid Build Coastguard Worker // This should throw an exception because 88*c8dee2aaSAndroid Build Coastguard Worker // the underlying path was already deleted. 89*c8dee2aaSAndroid Build Coastguard Worker path.delete(); 90*c8dee2aaSAndroid Build Coastguard Worker expect('should not have gotten here').toBe(false); 91*c8dee2aaSAndroid Build Coastguard Worker } catch (e) { 92*c8dee2aaSAndroid Build Coastguard Worker // all is well 93*c8dee2aaSAndroid Build Coastguard Worker } 94*c8dee2aaSAndroid Build Coastguard Worker done(); 95*c8dee2aaSAndroid Build Coastguard Worker })); 96*c8dee2aaSAndroid Build Coastguard Worker }); 97*c8dee2aaSAndroid Build Coastguard Worker 98*c8dee2aaSAndroid Build Coastguard Worker it('does not leak path objects when chaining', function(done) { 99*c8dee2aaSAndroid Build Coastguard Worker LoadPathKit.then(catchException(done, () => { 100*c8dee2aaSAndroid Build Coastguard Worker // By default, we have 16 MB of memory assigned to our PathKit 101*c8dee2aaSAndroid Build Coastguard Worker // library. This can be configured by -S TOTAL_MEMORY=NN 102*c8dee2aaSAndroid Build Coastguard Worker // and defaults to 16MB (we likely don't need to touch this). 103*c8dee2aaSAndroid Build Coastguard Worker // If there's a leak in here, we should OOM pretty quick. 104*c8dee2aaSAndroid Build Coastguard Worker // Testing showed around 50k is enough to see one if we leak a path, 105*c8dee2aaSAndroid Build Coastguard Worker // so run 250k times just to be safe. 106*c8dee2aaSAndroid Build Coastguard Worker for(let i = 0; i < 250000; i++) { 107*c8dee2aaSAndroid Build Coastguard Worker let path = PathKit.NewPath() 108*c8dee2aaSAndroid Build Coastguard Worker .moveTo(20, 5) 109*c8dee2aaSAndroid Build Coastguard Worker .lineTo(30, 20) 110*c8dee2aaSAndroid Build Coastguard Worker .quadTo(66, 188, 120, 136) 111*c8dee2aaSAndroid Build Coastguard Worker .close(); 112*c8dee2aaSAndroid Build Coastguard Worker path.delete(); 113*c8dee2aaSAndroid Build Coastguard Worker } 114*c8dee2aaSAndroid Build Coastguard Worker done(); 115*c8dee2aaSAndroid Build Coastguard Worker })); 116*c8dee2aaSAndroid Build Coastguard Worker }); 117*c8dee2aaSAndroid Build Coastguard Worker 118*c8dee2aaSAndroid Build Coastguard Worker function drawTriangle() { 119*c8dee2aaSAndroid Build Coastguard Worker let path = PathKit.NewPath(); 120*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(0, 0); 121*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(10, 0); 122*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(10, 10); 123*c8dee2aaSAndroid Build Coastguard Worker path.close(); 124*c8dee2aaSAndroid Build Coastguard Worker return path; 125*c8dee2aaSAndroid Build Coastguard Worker } 126*c8dee2aaSAndroid Build Coastguard Worker 127*c8dee2aaSAndroid Build Coastguard Worker it('has multiple overloads of addPath', function(done) { 128*c8dee2aaSAndroid Build Coastguard Worker LoadPathKit.then(catchException(done, () => { 129*c8dee2aaSAndroid Build Coastguard Worker let basePath = PathKit.NewPath(); 130*c8dee2aaSAndroid Build Coastguard Worker let otherPath = drawTriangle(); 131*c8dee2aaSAndroid Build Coastguard Worker // These add path call can be chained. 132*c8dee2aaSAndroid Build Coastguard Worker // add it unchanged 133*c8dee2aaSAndroid Build Coastguard Worker basePath.addPath(otherPath) 134*c8dee2aaSAndroid Build Coastguard Worker // providing the 6 params of an SVG matrix to make it appear 20.5 px down 135*c8dee2aaSAndroid Build Coastguard Worker .addPath(otherPath, 1, 0, 0, 1, 0, 20.5) 136*c8dee2aaSAndroid Build Coastguard Worker // provide the full 9 matrix params to make it appear 30 px to the right 137*c8dee2aaSAndroid Build Coastguard Worker // and be 3 times as big. 138*c8dee2aaSAndroid Build Coastguard Worker .addPath(otherPath, 3, 0, 30, 139*c8dee2aaSAndroid Build Coastguard Worker 0, 3, 0, 140*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 1); 141*c8dee2aaSAndroid Build Coastguard Worker 142*c8dee2aaSAndroid Build Coastguard Worker reportPath(basePath, 'add_path_3x', done); 143*c8dee2aaSAndroid Build Coastguard Worker basePath.delete(); 144*c8dee2aaSAndroid Build Coastguard Worker otherPath.delete(); 145*c8dee2aaSAndroid Build Coastguard Worker })); 146*c8dee2aaSAndroid Build Coastguard Worker }); 147*c8dee2aaSAndroid Build Coastguard Worker 148*c8dee2aaSAndroid Build Coastguard Worker it('approximates arcs (conics) with quads', function(done) { 149*c8dee2aaSAndroid Build Coastguard Worker LoadPathKit.then(catchException(done, () => { 150*c8dee2aaSAndroid Build Coastguard Worker let path = PathKit.NewPath(); 151*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(50, 120); 152*c8dee2aaSAndroid Build Coastguard Worker path.arc(50, 120, 45, 0, 1.75 * Math.PI); 153*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(50, 120); 154*c8dee2aaSAndroid Build Coastguard Worker 155*c8dee2aaSAndroid Build Coastguard Worker let canvas = document.createElement('canvas'); 156*c8dee2aaSAndroid Build Coastguard Worker let canvasCtx = canvas.getContext('2d'); 157*c8dee2aaSAndroid Build Coastguard Worker standardizedCanvasSize(canvasCtx); 158*c8dee2aaSAndroid Build Coastguard Worker // The and.callThrough is important to make it actually 159*c8dee2aaSAndroid Build Coastguard Worker // draw the quadratics 160*c8dee2aaSAndroid Build Coastguard Worker spyOn(canvasCtx, 'quadraticCurveTo').and.callThrough(); 161*c8dee2aaSAndroid Build Coastguard Worker 162*c8dee2aaSAndroid Build Coastguard Worker canvasCtx.beginPath(); 163*c8dee2aaSAndroid Build Coastguard Worker path.toCanvas(canvasCtx); 164*c8dee2aaSAndroid Build Coastguard Worker canvasCtx.stroke(); 165*c8dee2aaSAndroid Build Coastguard Worker // No need to check the whole path, as that's more what the 166*c8dee2aaSAndroid Build Coastguard Worker // gold correctness tests are for (can account for changes we make 167*c8dee2aaSAndroid Build Coastguard Worker // to the approximation algorithms). 168*c8dee2aaSAndroid Build Coastguard Worker expect(canvasCtx.quadraticCurveTo).toHaveBeenCalled(); 169*c8dee2aaSAndroid Build Coastguard Worker path.delete(); 170*c8dee2aaSAndroid Build Coastguard Worker reportCanvas(canvas, 'conics_quads_approx').then(() => { 171*c8dee2aaSAndroid Build Coastguard Worker done(); 172*c8dee2aaSAndroid Build Coastguard Worker }).catch(reportError(done)); 173*c8dee2aaSAndroid Build Coastguard Worker })); 174*c8dee2aaSAndroid Build Coastguard Worker }); 175*c8dee2aaSAndroid Build Coastguard Worker 176*c8dee2aaSAndroid Build Coastguard Worker}); 177