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