xref: /aosp_15_r20/external/skia/modules/pathkit/tests/effects.spec.js (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker
2*c8dee2aaSAndroid Build Coastguard Workerdescribe('PathKit\'s Path Behavior', function() {
3*c8dee2aaSAndroid Build Coastguard Worker    // see https://fiddle.skia.org/c/@discrete_path
4*c8dee2aaSAndroid Build Coastguard Worker    function drawStar() {
5*c8dee2aaSAndroid Build Coastguard Worker        let path = PathKit.NewPath();
6*c8dee2aaSAndroid Build Coastguard Worker        let R = 115.2, C = 128.0;
7*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(C + R + 22, C);
8*c8dee2aaSAndroid Build Coastguard Worker        for (let i = 1; i < 8; i++) {
9*c8dee2aaSAndroid Build Coastguard Worker            let a = 2.6927937 * i;
10*c8dee2aaSAndroid Build Coastguard Worker            path.lineTo(C + R * Math.cos(a) + 22, C + R * Math.sin(a));
11*c8dee2aaSAndroid Build Coastguard Worker        }
12*c8dee2aaSAndroid Build Coastguard Worker        path.closePath();
13*c8dee2aaSAndroid Build Coastguard Worker        return path;
14*c8dee2aaSAndroid Build Coastguard Worker    }
15*c8dee2aaSAndroid Build Coastguard Worker
16*c8dee2aaSAndroid Build Coastguard Worker    describe('Dash Path Effect', function() {
17*c8dee2aaSAndroid Build Coastguard Worker        it('performs dash in-place with start, stop, phase', function(done) {
18*c8dee2aaSAndroid Build Coastguard Worker            LoadPathKit.then(catchException(done, () => {
19*c8dee2aaSAndroid Build Coastguard Worker                let orig = drawStar();
20*c8dee2aaSAndroid Build Coastguard Worker                let dashed = drawStar();
21*c8dee2aaSAndroid Build Coastguard Worker                let notACopy = dashed.dash(10, 3, 0);
22*c8dee2aaSAndroid Build Coastguard Worker                let phased = drawStar().dash(10, 3, 2);
23*c8dee2aaSAndroid Build Coastguard Worker
24*c8dee2aaSAndroid Build Coastguard Worker                expect(dashed === notACopy).toBe(true);
25*c8dee2aaSAndroid Build Coastguard Worker                expect(dashed.equals(phased)).toBe(false);
26*c8dee2aaSAndroid Build Coastguard Worker                expect(dashed.equals(orig)).toBe(false);
27*c8dee2aaSAndroid Build Coastguard Worker
28*c8dee2aaSAndroid Build Coastguard Worker                reportPath(dashed, 'dashed_no_phase', () => {
29*c8dee2aaSAndroid Build Coastguard Worker                    reportPath(phased, 'dashed_with_phase', done);
30*c8dee2aaSAndroid Build Coastguard Worker                    orig.delete();
31*c8dee2aaSAndroid Build Coastguard Worker                    dashed.delete();
32*c8dee2aaSAndroid Build Coastguard Worker                    phased.delete();
33*c8dee2aaSAndroid Build Coastguard Worker                });
34*c8dee2aaSAndroid Build Coastguard Worker            }));
35*c8dee2aaSAndroid Build Coastguard Worker        });
36*c8dee2aaSAndroid Build Coastguard Worker    });
37*c8dee2aaSAndroid Build Coastguard Worker
38*c8dee2aaSAndroid Build Coastguard Worker    describe('Trim Path Effect', function() {
39*c8dee2aaSAndroid Build Coastguard Worker        it('performs trim in-place with start, stop, phase', function(done) {
40*c8dee2aaSAndroid Build Coastguard Worker            LoadPathKit.then(catchException(done, () => {
41*c8dee2aaSAndroid Build Coastguard Worker                let orig = drawStar();
42*c8dee2aaSAndroid Build Coastguard Worker                let trimmed = drawStar();
43*c8dee2aaSAndroid Build Coastguard Worker                let notACopy = trimmed.trim(0.25, .8);
44*c8dee2aaSAndroid Build Coastguard Worker                let complement = drawStar().trim(.1, .9, true);
45*c8dee2aaSAndroid Build Coastguard Worker
46*c8dee2aaSAndroid Build Coastguard Worker                expect(trimmed === notACopy).toBe(true);
47*c8dee2aaSAndroid Build Coastguard Worker                expect(trimmed.equals(complement)).toBe(false);
48*c8dee2aaSAndroid Build Coastguard Worker                expect(trimmed.equals(orig)).toBe(false);
49*c8dee2aaSAndroid Build Coastguard Worker                expect(complement.equals(orig)).toBe(false);
50*c8dee2aaSAndroid Build Coastguard Worker
51*c8dee2aaSAndroid Build Coastguard Worker                reportPath(trimmed, 'trimmed_non_complement', () => {
52*c8dee2aaSAndroid Build Coastguard Worker                    reportPath(complement, 'trimmed_complement', done);
53*c8dee2aaSAndroid Build Coastguard Worker                    orig.delete();
54*c8dee2aaSAndroid Build Coastguard Worker                    trimmed.delete();
55*c8dee2aaSAndroid Build Coastguard Worker                    complement.delete();
56*c8dee2aaSAndroid Build Coastguard Worker                });
57*c8dee2aaSAndroid Build Coastguard Worker            }));
58*c8dee2aaSAndroid Build Coastguard Worker        });
59*c8dee2aaSAndroid Build Coastguard Worker    });
60*c8dee2aaSAndroid Build Coastguard Worker
61*c8dee2aaSAndroid Build Coastguard Worker    describe('Transform Path Effect', function() {
62*c8dee2aaSAndroid Build Coastguard Worker        it('performs matrix transform in-place', function(done) {
63*c8dee2aaSAndroid Build Coastguard Worker            LoadPathKit.then(catchException(done, () => {
64*c8dee2aaSAndroid Build Coastguard Worker                let orig = drawStar();
65*c8dee2aaSAndroid Build Coastguard Worker                let scaled = drawStar();
66*c8dee2aaSAndroid Build Coastguard Worker                let notACopy = scaled.transform(3, 0, 0,
67*c8dee2aaSAndroid Build Coastguard Worker                                                0, 3, 0,
68*c8dee2aaSAndroid Build Coastguard Worker                                                0, 0, 1);
69*c8dee2aaSAndroid Build Coastguard Worker
70*c8dee2aaSAndroid Build Coastguard Worker                let scaled2 = drawStar().transform([3, 0, 0,
71*c8dee2aaSAndroid Build Coastguard Worker                                                    0, 3, 0,
72*c8dee2aaSAndroid Build Coastguard Worker                                                    0, 0, 1]);
73*c8dee2aaSAndroid Build Coastguard Worker
74*c8dee2aaSAndroid Build Coastguard Worker                expect(scaled === notACopy).toBe(true);
75*c8dee2aaSAndroid Build Coastguard Worker                expect(scaled.equals(scaled2)).toBe(true);
76*c8dee2aaSAndroid Build Coastguard Worker                expect(scaled.equals(orig)).toBe(false);
77*c8dee2aaSAndroid Build Coastguard Worker
78*c8dee2aaSAndroid Build Coastguard Worker                reportPath(scaled, 'transformed_scale', () => {
79*c8dee2aaSAndroid Build Coastguard Worker                    reportPath(scaled2, 'transformed_scale2', done);
80*c8dee2aaSAndroid Build Coastguard Worker                    orig.delete();
81*c8dee2aaSAndroid Build Coastguard Worker                    scaled.delete();
82*c8dee2aaSAndroid Build Coastguard Worker                    scaled2.delete();
83*c8dee2aaSAndroid Build Coastguard Worker                });
84*c8dee2aaSAndroid Build Coastguard Worker            }));
85*c8dee2aaSAndroid Build Coastguard Worker        });
86*c8dee2aaSAndroid Build Coastguard Worker    });
87*c8dee2aaSAndroid Build Coastguard Worker
88*c8dee2aaSAndroid Build Coastguard Worker    describe('Stroke Path Effect', function() {
89*c8dee2aaSAndroid Build Coastguard Worker        it('creates a stroked path in-place', function(done) {
90*c8dee2aaSAndroid Build Coastguard Worker            LoadPathKit.then(catchException(done, () => {
91*c8dee2aaSAndroid Build Coastguard Worker                let orig = drawStar();
92*c8dee2aaSAndroid Build Coastguard Worker                let stroked = drawStar();
93*c8dee2aaSAndroid Build Coastguard Worker                let notACopy = stroked.stroke({
94*c8dee2aaSAndroid Build Coastguard Worker                    width: 15,
95*c8dee2aaSAndroid Build Coastguard Worker                    join: PathKit.StrokeJoin.BEVEL,
96*c8dee2aaSAndroid Build Coastguard Worker                    cap: PathKit.StrokeCap.BUTT,
97*c8dee2aaSAndroid Build Coastguard Worker                    miter_limit: 2,
98*c8dee2aaSAndroid Build Coastguard Worker                });
99*c8dee2aaSAndroid Build Coastguard Worker
100*c8dee2aaSAndroid Build Coastguard Worker                // Don't have to specify all of the fields, defaults will
101*c8dee2aaSAndroid Build Coastguard Worker                // be used instead.
102*c8dee2aaSAndroid Build Coastguard Worker                let rounded = drawStar().stroke({
103*c8dee2aaSAndroid Build Coastguard Worker                    width: 10,
104*c8dee2aaSAndroid Build Coastguard Worker                    join: PathKit.StrokeJoin.ROUND,
105*c8dee2aaSAndroid Build Coastguard Worker                    cap:PathKit.StrokeCap.SQUARE,
106*c8dee2aaSAndroid Build Coastguard Worker                });
107*c8dee2aaSAndroid Build Coastguard Worker
108*c8dee2aaSAndroid Build Coastguard Worker                expect(stroked === notACopy).toBe(true);
109*c8dee2aaSAndroid Build Coastguard Worker                expect(stroked.equals(rounded)).toBe(false);
110*c8dee2aaSAndroid Build Coastguard Worker                expect(stroked.equals(orig)).toBe(false);
111*c8dee2aaSAndroid Build Coastguard Worker
112*c8dee2aaSAndroid Build Coastguard Worker                reportPath(stroked, 'stroke_bevel_butt', () => {
113*c8dee2aaSAndroid Build Coastguard Worker                    reportPath(rounded, 'stroke_round_square', done);
114*c8dee2aaSAndroid Build Coastguard Worker                    orig.delete();
115*c8dee2aaSAndroid Build Coastguard Worker                    stroked.delete();
116*c8dee2aaSAndroid Build Coastguard Worker                    rounded.delete();
117*c8dee2aaSAndroid Build Coastguard Worker                });
118*c8dee2aaSAndroid Build Coastguard Worker            }));
119*c8dee2aaSAndroid Build Coastguard Worker        });
120*c8dee2aaSAndroid Build Coastguard Worker
121*c8dee2aaSAndroid Build Coastguard Worker        it('can use res_scale for more precision', function(done) {
122*c8dee2aaSAndroid Build Coastguard Worker            LoadPathKit.then(catchException(done, () => {
123*c8dee2aaSAndroid Build Coastguard Worker                let canvas = document.createElement('canvas');
124*c8dee2aaSAndroid Build Coastguard Worker                let ctx = canvas.getContext('2d');
125*c8dee2aaSAndroid Build Coastguard Worker                // Set canvas size and make it a bit bigger to zoom in on the lines
126*c8dee2aaSAndroid Build Coastguard Worker                standardizedCanvasSize(ctx);
127*c8dee2aaSAndroid Build Coastguard Worker
128*c8dee2aaSAndroid Build Coastguard Worker                const circle = PathKit.NewPath();
129*c8dee2aaSAndroid Build Coastguard Worker                circle.ellipse(0, 0, 1, 1, 0, 0, Math.PI * 2);
130*c8dee2aaSAndroid Build Coastguard Worker
131*c8dee2aaSAndroid Build Coastguard Worker                let scales = [1, 3, 5,
132*c8dee2aaSAndroid Build Coastguard Worker                              10, 30, 100];
133*c8dee2aaSAndroid Build Coastguard Worker
134*c8dee2aaSAndroid Build Coastguard Worker                // White background
135*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillStyle = 'white';
136*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillRect(0, 0, canvas.width, canvas.height);
137*c8dee2aaSAndroid Build Coastguard Worker
138*c8dee2aaSAndroid Build Coastguard Worker                for (let i = 0; i < scales.length; i++) {
139*c8dee2aaSAndroid Build Coastguard Worker                    ctx.save();
140*c8dee2aaSAndroid Build Coastguard Worker                    const row = Math.floor(i / 3);
141*c8dee2aaSAndroid Build Coastguard Worker                    const col = i % 3;
142*c8dee2aaSAndroid Build Coastguard Worker                    ctx.translate(100 * col + 50, 100 * row + 50);
143*c8dee2aaSAndroid Build Coastguard Worker                    ctx.scale(30, 30);
144*c8dee2aaSAndroid Build Coastguard Worker
145*c8dee2aaSAndroid Build Coastguard Worker                    // Grey circle
146*c8dee2aaSAndroid Build Coastguard Worker                    ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
147*c8dee2aaSAndroid Build Coastguard Worker                    ctx.beginPath();
148*c8dee2aaSAndroid Build Coastguard Worker                    circle.toCanvas(ctx);
149*c8dee2aaSAndroid Build Coastguard Worker                    ctx.fill();
150*c8dee2aaSAndroid Build Coastguard Worker
151*c8dee2aaSAndroid Build Coastguard Worker                    // Pink stroke, with given res_scale option
152*c8dee2aaSAndroid Build Coastguard Worker                    const line = circle.copy().stroke({
153*c8dee2aaSAndroid Build Coastguard Worker                        width: 0.5,
154*c8dee2aaSAndroid Build Coastguard Worker                        res_scale: scales[i],
155*c8dee2aaSAndroid Build Coastguard Worker                    });
156*c8dee2aaSAndroid Build Coastguard Worker                    ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
157*c8dee2aaSAndroid Build Coastguard Worker                    ctx.beginPath();
158*c8dee2aaSAndroid Build Coastguard Worker                    line.toCanvas(ctx);
159*c8dee2aaSAndroid Build Coastguard Worker                    ctx.fill();
160*c8dee2aaSAndroid Build Coastguard Worker
161*c8dee2aaSAndroid Build Coastguard Worker                    line.delete();
162*c8dee2aaSAndroid Build Coastguard Worker                    ctx.restore();
163*c8dee2aaSAndroid Build Coastguard Worker                }
164*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillStyle = 'black';
165*c8dee2aaSAndroid Build Coastguard Worker                ctx.font = '14px serif';
166*c8dee2aaSAndroid Build Coastguard Worker                ctx.fillText('notice for lower res_scale values, the stroked circles ' +
167*c8dee2aaSAndroid Build Coastguard Worker                             '(pink) are not round',
168*c8dee2aaSAndroid Build Coastguard Worker                             10, 200);
169*c8dee2aaSAndroid Build Coastguard Worker
170*c8dee2aaSAndroid Build Coastguard Worker                circle.delete();
171*c8dee2aaSAndroid Build Coastguard Worker                reportCanvas(canvas, 'res_scale').then(() => {
172*c8dee2aaSAndroid Build Coastguard Worker                    done();
173*c8dee2aaSAndroid Build Coastguard Worker                }).catch(reportError(done));
174*c8dee2aaSAndroid Build Coastguard Worker            }));
175*c8dee2aaSAndroid Build Coastguard Worker        });
176*c8dee2aaSAndroid Build Coastguard Worker    });
177*c8dee2aaSAndroid Build Coastguard Worker
178*c8dee2aaSAndroid Build Coastguard Worker});
179