xref: /aosp_15_r20/external/skia/modules/pathkit/tests/path2d.spec.js (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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