xref: /aosp_15_r20/external/skia/modules/canvaskit/tests/path_test.js (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Workerdescribe('Path Behavior', () => {
2*c8dee2aaSAndroid Build Coastguard Worker    let container;
3*c8dee2aaSAndroid Build Coastguard Worker
4*c8dee2aaSAndroid Build Coastguard Worker    beforeEach(async () => {
5*c8dee2aaSAndroid Build Coastguard Worker        await EverythingLoaded;
6*c8dee2aaSAndroid Build Coastguard Worker        container = document.createElement('div');
7*c8dee2aaSAndroid Build Coastguard Worker        container.innerHTML = `
8*c8dee2aaSAndroid Build Coastguard Worker            <canvas width=600 height=600 id=test></canvas>
9*c8dee2aaSAndroid Build Coastguard Worker            <canvas width=600 height=600 id=report></canvas>`;
10*c8dee2aaSAndroid Build Coastguard Worker        document.body.appendChild(container);
11*c8dee2aaSAndroid Build Coastguard Worker    });
12*c8dee2aaSAndroid Build Coastguard Worker
13*c8dee2aaSAndroid Build Coastguard Worker    afterEach(() => {
14*c8dee2aaSAndroid Build Coastguard Worker        document.body.removeChild(container);
15*c8dee2aaSAndroid Build Coastguard Worker    });
16*c8dee2aaSAndroid Build Coastguard Worker
17*c8dee2aaSAndroid Build Coastguard Worker    gm('path_api_example', (canvas) => {
18*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
19*c8dee2aaSAndroid Build Coastguard Worker        paint.setStrokeWidth(1.0);
20*c8dee2aaSAndroid Build Coastguard Worker        paint.setAntiAlias(true);
21*c8dee2aaSAndroid Build Coastguard Worker        paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
22*c8dee2aaSAndroid Build Coastguard Worker        paint.setStyle(CanvasKit.PaintStyle.Stroke);
23*c8dee2aaSAndroid Build Coastguard Worker
24*c8dee2aaSAndroid Build Coastguard Worker        const path = new CanvasKit.Path();
25*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(20, 5);
26*c8dee2aaSAndroid Build Coastguard Worker        path.lineTo(30, 20);
27*c8dee2aaSAndroid Build Coastguard Worker        path.lineTo(40, 10);
28*c8dee2aaSAndroid Build Coastguard Worker        path.lineTo(50, 20);
29*c8dee2aaSAndroid Build Coastguard Worker        path.lineTo(60, 0);
30*c8dee2aaSAndroid Build Coastguard Worker        path.lineTo(20, 5);
31*c8dee2aaSAndroid Build Coastguard Worker
32*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(20, 80);
33*c8dee2aaSAndroid Build Coastguard Worker        path.cubicTo(90, 10, 160, 150, 190, 10);
34*c8dee2aaSAndroid Build Coastguard Worker
35*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(36, 148);
36*c8dee2aaSAndroid Build Coastguard Worker        path.quadTo(66, 188, 120, 136);
37*c8dee2aaSAndroid Build Coastguard Worker        path.lineTo(36, 148);
38*c8dee2aaSAndroid Build Coastguard Worker
39*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(150, 180);
40*c8dee2aaSAndroid Build Coastguard Worker        path.arcToTangent(150, 100, 50, 200, 20);
41*c8dee2aaSAndroid Build Coastguard Worker        path.lineTo(160, 160);
42*c8dee2aaSAndroid Build Coastguard Worker
43*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(20, 120);
44*c8dee2aaSAndroid Build Coastguard Worker        path.lineTo(20, 120);
45*c8dee2aaSAndroid Build Coastguard Worker
46*c8dee2aaSAndroid Build Coastguard Worker        path.transform([2, 0, 0,
47*c8dee2aaSAndroid Build Coastguard Worker                        0, 2, 0,
48*c8dee2aaSAndroid Build Coastguard Worker                        0, 0, 1 ]);
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(path, paint);
51*c8dee2aaSAndroid Build Coastguard Worker
52*c8dee2aaSAndroid Build Coastguard Worker        const rrect = CanvasKit.RRectXY([100, 10, 140, 62], 10, 4);
53*c8dee2aaSAndroid Build Coastguard Worker
54*c8dee2aaSAndroid Build Coastguard Worker        const rrectPath = new CanvasKit.Path().addRRect(rrect, true);
55*c8dee2aaSAndroid Build Coastguard Worker
56*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(rrectPath, paint);
57*c8dee2aaSAndroid Build Coastguard Worker
58*c8dee2aaSAndroid Build Coastguard Worker        rrectPath.delete();
59*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
60*c8dee2aaSAndroid Build Coastguard Worker        paint.delete();
61*c8dee2aaSAndroid Build Coastguard Worker        // See PathKit for more tests, since they share implementation
62*c8dee2aaSAndroid Build Coastguard Worker    });
63*c8dee2aaSAndroid Build Coastguard Worker
64*c8dee2aaSAndroid Build Coastguard Worker    it('can create a path from an SVG string', () => {
65*c8dee2aaSAndroid Build Coastguard Worker        //.This is a parallelogram from
66*c8dee2aaSAndroid Build Coastguard Worker        // https://upload.wikimedia.org/wikipedia/commons/e/e7/Simple_parallelogram.svg
67*c8dee2aaSAndroid Build Coastguard Worker        const path = CanvasKit.Path.MakeFromSVGString(
68*c8dee2aaSAndroid Build Coastguard Worker          'M 205,5 L 795,5 L 595,295 L 5,295 L 205,5 z');
69*c8dee2aaSAndroid Build Coastguard Worker
70*c8dee2aaSAndroid Build Coastguard Worker        const cmds = path.toCmds();
71*c8dee2aaSAndroid Build Coastguard Worker        expect(cmds).toBeTruthy();
72*c8dee2aaSAndroid Build Coastguard Worker        // 1 move, 4 lines, 1 close
73*c8dee2aaSAndroid Build Coastguard Worker        // each element in cmds is an array, with index 0 being the verb, and the rest being args
74*c8dee2aaSAndroid Build Coastguard Worker        expect(cmds).toEqual(Float32Array.of(
75*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.MOVE_VERB, 205, 5,
76*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 795, 5,
77*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 595, 295,
78*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 5, 295,
79*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 205, 5,
80*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.CLOSE_VERB));
81*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
82*c8dee2aaSAndroid Build Coastguard Worker    });
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker    it('can create a path by combining two other paths', () => {
85*c8dee2aaSAndroid Build Coastguard Worker        // Get the intersection of two overlapping squares and verify that it is the smaller square.
86*c8dee2aaSAndroid Build Coastguard Worker        const pathOne = new CanvasKit.Path();
87*c8dee2aaSAndroid Build Coastguard Worker        pathOne.addRect([10, 10, 20, 20]);
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker        const pathTwo = new CanvasKit.Path();
90*c8dee2aaSAndroid Build Coastguard Worker        pathTwo.addRect([15, 15, 30, 30]);
91*c8dee2aaSAndroid Build Coastguard Worker
92*c8dee2aaSAndroid Build Coastguard Worker        const path = CanvasKit.Path.MakeFromOp(pathOne, pathTwo, CanvasKit.PathOp.Intersect);
93*c8dee2aaSAndroid Build Coastguard Worker        const cmds = path.toCmds();
94*c8dee2aaSAndroid Build Coastguard Worker        expect(cmds).toBeTruthy();
95*c8dee2aaSAndroid Build Coastguard Worker        expect(cmds).toEqual(Float32Array.of(
96*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.MOVE_VERB, 15, 15,
97*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 20, 15,
98*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 20, 20,
99*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 15, 20,
100*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.CLOSE_VERB));
101*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
102*c8dee2aaSAndroid Build Coastguard Worker        pathOne.delete();
103*c8dee2aaSAndroid Build Coastguard Worker        pathTwo.delete();
104*c8dee2aaSAndroid Build Coastguard Worker    });
105*c8dee2aaSAndroid Build Coastguard Worker
106*c8dee2aaSAndroid Build Coastguard Worker    it('can create an SVG string from a path', () => {
107*c8dee2aaSAndroid Build Coastguard Worker        const cmds = [CanvasKit.MOVE_VERB, 205, 5,
108*c8dee2aaSAndroid Build Coastguard Worker                   CanvasKit.LINE_VERB, 795, 5,
109*c8dee2aaSAndroid Build Coastguard Worker                   CanvasKit.LINE_VERB, 595, 295,
110*c8dee2aaSAndroid Build Coastguard Worker                   CanvasKit.LINE_VERB, 5, 295,
111*c8dee2aaSAndroid Build Coastguard Worker                   CanvasKit.LINE_VERB, 205, 5,
112*c8dee2aaSAndroid Build Coastguard Worker                   CanvasKit.CLOSE_VERB];
113*c8dee2aaSAndroid Build Coastguard Worker        const path = CanvasKit.Path.MakeFromCmds(cmds);
114*c8dee2aaSAndroid Build Coastguard Worker
115*c8dee2aaSAndroid Build Coastguard Worker        const svgStr = path.toSVGString();
116*c8dee2aaSAndroid Build Coastguard Worker        // We output it in terse form, which is different than Wikipedia's version
117*c8dee2aaSAndroid Build Coastguard Worker        expect(svgStr).toEqual('M205 5L795 5L595 295L5 295L205 5Z');
118*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
119*c8dee2aaSAndroid Build Coastguard Worker    });
120*c8dee2aaSAndroid Build Coastguard Worker
121*c8dee2aaSAndroid Build Coastguard Worker    it('can create a path with malloced verbs, points, weights', () => {
122*c8dee2aaSAndroid Build Coastguard Worker        const mVerbs = CanvasKit.Malloc(Uint8Array, 6);
123*c8dee2aaSAndroid Build Coastguard Worker        const mPoints = CanvasKit.Malloc(Float32Array, 18);
124*c8dee2aaSAndroid Build Coastguard Worker        const mWeights = CanvasKit.Malloc(Float32Array, 1);
125*c8dee2aaSAndroid Build Coastguard Worker        mVerbs.toTypedArray().set([CanvasKit.MOVE_VERB, CanvasKit.LINE_VERB,
126*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.QUAD_VERB, CanvasKit.CONIC_VERB, CanvasKit.CUBIC_VERB, CanvasKit.CLOSE_VERB
127*c8dee2aaSAndroid Build Coastguard Worker        ]);
128*c8dee2aaSAndroid Build Coastguard Worker
129*c8dee2aaSAndroid Build Coastguard Worker        mPoints.toTypedArray().set([
130*c8dee2aaSAndroid Build Coastguard Worker          1,2, // moveTo
131*c8dee2aaSAndroid Build Coastguard Worker          3,4, // lineTo
132*c8dee2aaSAndroid Build Coastguard Worker          5,6,7,8, // quadTo
133*c8dee2aaSAndroid Build Coastguard Worker          9,10,11,12, // conicTo
134*c8dee2aaSAndroid Build Coastguard Worker          13,14,15,16,17,18, // cubicTo
135*c8dee2aaSAndroid Build Coastguard Worker        ]);
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker        mWeights.toTypedArray().set([117]);
138*c8dee2aaSAndroid Build Coastguard Worker
139*c8dee2aaSAndroid Build Coastguard Worker        let path = CanvasKit.Path.MakeFromVerbsPointsWeights(mVerbs, mPoints, mWeights);
140*c8dee2aaSAndroid Build Coastguard Worker
141*c8dee2aaSAndroid Build Coastguard Worker        let cmds = path.toCmds();
142*c8dee2aaSAndroid Build Coastguard Worker        expect(cmds).toEqual(Float32Array.of(
143*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.MOVE_VERB, 1, 2,
144*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 3, 4,
145*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.QUAD_VERB, 5, 6, 7, 8,
146*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.CONIC_VERB, 9, 10, 11, 12, 117,
147*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.CUBIC_VERB, 13, 14, 15, 16, 17, 18,
148*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.CLOSE_VERB,
149*c8dee2aaSAndroid Build Coastguard Worker        ));
150*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
151*c8dee2aaSAndroid Build Coastguard Worker
152*c8dee2aaSAndroid Build Coastguard Worker        // If given insufficient points, it stops early (but doesn't read out of bounds).
153*c8dee2aaSAndroid Build Coastguard Worker        path = CanvasKit.Path.MakeFromVerbsPointsWeights(mVerbs, mPoints.subarray(0, 10), mWeights);
154*c8dee2aaSAndroid Build Coastguard Worker
155*c8dee2aaSAndroid Build Coastguard Worker        cmds = path.toCmds();
156*c8dee2aaSAndroid Build Coastguard Worker        expect(cmds).toEqual(Float32Array.of(
157*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.MOVE_VERB, 1, 2,
158*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 3, 4,
159*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.QUAD_VERB, 5, 6, 7, 8,
160*c8dee2aaSAndroid Build Coastguard Worker        ));
161*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
162*c8dee2aaSAndroid Build Coastguard Worker        CanvasKit.Free(mVerbs);
163*c8dee2aaSAndroid Build Coastguard Worker        CanvasKit.Free(mPoints);
164*c8dee2aaSAndroid Build Coastguard Worker        CanvasKit.Free(mWeights);
165*c8dee2aaSAndroid Build Coastguard Worker    });
166*c8dee2aaSAndroid Build Coastguard Worker
167*c8dee2aaSAndroid Build Coastguard Worker    it('can create and update a path with verbs and points (no weights)', () => {
168*c8dee2aaSAndroid Build Coastguard Worker        const path = CanvasKit.Path.MakeFromVerbsPointsWeights(
169*c8dee2aaSAndroid Build Coastguard Worker          [CanvasKit.MOVE_VERB, CanvasKit.LINE_VERB],
170*c8dee2aaSAndroid Build Coastguard Worker          [1,2, 3,4]);
171*c8dee2aaSAndroid Build Coastguard Worker        let cmds = path.toCmds();
172*c8dee2aaSAndroid Build Coastguard Worker        expect(cmds).toEqual(Float32Array.of(
173*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.MOVE_VERB, 1, 2,
174*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 3, 4
175*c8dee2aaSAndroid Build Coastguard Worker        ));
176*c8dee2aaSAndroid Build Coastguard Worker
177*c8dee2aaSAndroid Build Coastguard Worker        path.addVerbsPointsWeights(
178*c8dee2aaSAndroid Build Coastguard Worker          [CanvasKit.QUAD_VERB, CanvasKit.CLOSE_VERB],
179*c8dee2aaSAndroid Build Coastguard Worker          [5,6,7,8],
180*c8dee2aaSAndroid Build Coastguard Worker        );
181*c8dee2aaSAndroid Build Coastguard Worker
182*c8dee2aaSAndroid Build Coastguard Worker        cmds = path.toCmds();
183*c8dee2aaSAndroid Build Coastguard Worker        expect(cmds).toEqual(Float32Array.of(
184*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.MOVE_VERB, 1, 2,
185*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 3, 4,
186*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.QUAD_VERB, 5, 6, 7, 8,
187*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.CLOSE_VERB
188*c8dee2aaSAndroid Build Coastguard Worker        ));
189*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
190*c8dee2aaSAndroid Build Coastguard Worker    });
191*c8dee2aaSAndroid Build Coastguard Worker
192*c8dee2aaSAndroid Build Coastguard Worker
193*c8dee2aaSAndroid Build Coastguard Worker    it('can add points to a path in bulk', () => {
194*c8dee2aaSAndroid Build Coastguard Worker        const mVerbs = CanvasKit.Malloc(Uint8Array, 6);
195*c8dee2aaSAndroid Build Coastguard Worker        const mPoints = CanvasKit.Malloc(Float32Array, 18);
196*c8dee2aaSAndroid Build Coastguard Worker        const mWeights = CanvasKit.Malloc(Float32Array, 1);
197*c8dee2aaSAndroid Build Coastguard Worker        mVerbs.toTypedArray().set([CanvasKit.MOVE_VERB, CanvasKit.LINE_VERB,
198*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.QUAD_VERB, CanvasKit.CONIC_VERB, CanvasKit.CUBIC_VERB, CanvasKit.CLOSE_VERB
199*c8dee2aaSAndroid Build Coastguard Worker        ]);
200*c8dee2aaSAndroid Build Coastguard Worker
201*c8dee2aaSAndroid Build Coastguard Worker        mPoints.toTypedArray().set([
202*c8dee2aaSAndroid Build Coastguard Worker            1,2, // moveTo
203*c8dee2aaSAndroid Build Coastguard Worker            3,4, // lineTo
204*c8dee2aaSAndroid Build Coastguard Worker            5,6,7,8, // quadTo
205*c8dee2aaSAndroid Build Coastguard Worker            9,10,11,12, // conicTo
206*c8dee2aaSAndroid Build Coastguard Worker            13,14,15,16,17,18, // cubicTo
207*c8dee2aaSAndroid Build Coastguard Worker        ]);
208*c8dee2aaSAndroid Build Coastguard Worker
209*c8dee2aaSAndroid Build Coastguard Worker        mWeights.toTypedArray().set([117]);
210*c8dee2aaSAndroid Build Coastguard Worker
211*c8dee2aaSAndroid Build Coastguard Worker        const path = new CanvasKit.Path();
212*c8dee2aaSAndroid Build Coastguard Worker        path.lineTo(77, 88);
213*c8dee2aaSAndroid Build Coastguard Worker        path.addVerbsPointsWeights(mVerbs, mPoints, mWeights);
214*c8dee2aaSAndroid Build Coastguard Worker
215*c8dee2aaSAndroid Build Coastguard Worker        let cmds = path.toCmds();
216*c8dee2aaSAndroid Build Coastguard Worker        expect(cmds).toEqual(Float32Array.of(
217*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.MOVE_VERB, 0, 0,
218*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 77, 88,
219*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.MOVE_VERB, 1, 2,
220*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.LINE_VERB, 3, 4,
221*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.QUAD_VERB, 5, 6, 7, 8,
222*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.CONIC_VERB, 9, 10, 11, 12, 117,
223*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.CUBIC_VERB, 13, 14, 15, 16, 17, 18,
224*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.CLOSE_VERB,
225*c8dee2aaSAndroid Build Coastguard Worker        ));
226*c8dee2aaSAndroid Build Coastguard Worker
227*c8dee2aaSAndroid Build Coastguard Worker        path.rewind();
228*c8dee2aaSAndroid Build Coastguard Worker        cmds = path.toCmds();
229*c8dee2aaSAndroid Build Coastguard Worker        expect(cmds).toEqual(new Float32Array(0));
230*c8dee2aaSAndroid Build Coastguard Worker
231*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
232*c8dee2aaSAndroid Build Coastguard Worker        CanvasKit.Free(mVerbs);
233*c8dee2aaSAndroid Build Coastguard Worker        CanvasKit.Free(mPoints);
234*c8dee2aaSAndroid Build Coastguard Worker        CanvasKit.Free(mWeights);
235*c8dee2aaSAndroid Build Coastguard Worker    });
236*c8dee2aaSAndroid Build Coastguard Worker
237*c8dee2aaSAndroid Build Coastguard Worker    it('can retrieve points from a path', () => {
238*c8dee2aaSAndroid Build Coastguard Worker        const path = new CanvasKit.Path();
239*c8dee2aaSAndroid Build Coastguard Worker        path.addRect([10, 15, 20, 25]);
240*c8dee2aaSAndroid Build Coastguard Worker
241*c8dee2aaSAndroid Build Coastguard Worker        let pt = path.getPoint(0);
242*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[0]).toEqual(10);
243*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[1]).toEqual(15);
244*c8dee2aaSAndroid Build Coastguard Worker
245*c8dee2aaSAndroid Build Coastguard Worker        path.getPoint(2, pt);
246*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[0]).toEqual(20);
247*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[1]).toEqual(25);
248*c8dee2aaSAndroid Build Coastguard Worker
249*c8dee2aaSAndroid Build Coastguard Worker        path.getPoint(1000, pt); // off the end returns (0, 0) as per the docs.
250*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[0]).toEqual(0);
251*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[1]).toEqual(0);
252*c8dee2aaSAndroid Build Coastguard Worker
253*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
254*c8dee2aaSAndroid Build Coastguard Worker    });
255*c8dee2aaSAndroid Build Coastguard Worker
256*c8dee2aaSAndroid Build Coastguard Worker    gm('offset_path', (canvas) => {
257*c8dee2aaSAndroid Build Coastguard Worker        const path = starPath(CanvasKit);
258*c8dee2aaSAndroid Build Coastguard Worker
259*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
260*c8dee2aaSAndroid Build Coastguard Worker        paint.setStyle(CanvasKit.PaintStyle.Stroke);
261*c8dee2aaSAndroid Build Coastguard Worker        paint.setStrokeWidth(5.0);
262*c8dee2aaSAndroid Build Coastguard Worker        paint.setAntiAlias(true);
263*c8dee2aaSAndroid Build Coastguard Worker        paint.setColor(CanvasKit.BLACK);
264*c8dee2aaSAndroid Build Coastguard Worker
265*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(path, paint);
266*c8dee2aaSAndroid Build Coastguard Worker        path.offset(80, 40);
267*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(path, paint);
268*c8dee2aaSAndroid Build Coastguard Worker
269*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
270*c8dee2aaSAndroid Build Coastguard Worker        paint.delete();
271*c8dee2aaSAndroid Build Coastguard Worker    });
272*c8dee2aaSAndroid Build Coastguard Worker
273*c8dee2aaSAndroid Build Coastguard Worker    gm('oval_path', (canvas) => {
274*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
275*c8dee2aaSAndroid Build Coastguard Worker
276*c8dee2aaSAndroid Build Coastguard Worker        paint.setStyle(CanvasKit.PaintStyle.Stroke);
277*c8dee2aaSAndroid Build Coastguard Worker        paint.setStrokeWidth(5.0);
278*c8dee2aaSAndroid Build Coastguard Worker        paint.setAntiAlias(true);
279*c8dee2aaSAndroid Build Coastguard Worker        paint.setColor(CanvasKit.BLACK);
280*c8dee2aaSAndroid Build Coastguard Worker
281*c8dee2aaSAndroid Build Coastguard Worker        const path = new CanvasKit.Path();
282*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(5, 5);
283*c8dee2aaSAndroid Build Coastguard Worker        path.lineTo(10, 120);
284*c8dee2aaSAndroid Build Coastguard Worker        path.addOval(CanvasKit.LTRBRect(10, 20, 100, 200), false, 3);
285*c8dee2aaSAndroid Build Coastguard Worker        path.lineTo(300, 300);
286*c8dee2aaSAndroid Build Coastguard Worker
287*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(path, paint);
288*c8dee2aaSAndroid Build Coastguard Worker
289*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
290*c8dee2aaSAndroid Build Coastguard Worker        paint.delete();
291*c8dee2aaSAndroid Build Coastguard Worker    });
292*c8dee2aaSAndroid Build Coastguard Worker
293*c8dee2aaSAndroid Build Coastguard Worker    gm('bounds_path', (canvas) => {
294*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
295*c8dee2aaSAndroid Build Coastguard Worker
296*c8dee2aaSAndroid Build Coastguard Worker        paint.setStyle(CanvasKit.PaintStyle.Stroke);
297*c8dee2aaSAndroid Build Coastguard Worker        paint.setStrokeWidth(5.0);
298*c8dee2aaSAndroid Build Coastguard Worker        paint.setAntiAlias(true);
299*c8dee2aaSAndroid Build Coastguard Worker        paint.setColor(CanvasKit.BLACK);
300*c8dee2aaSAndroid Build Coastguard Worker
301*c8dee2aaSAndroid Build Coastguard Worker        const path = new CanvasKit.Path();
302*c8dee2aaSAndroid Build Coastguard Worker        // Arbitrary points to make an interesting curve.
303*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(97, 225);
304*c8dee2aaSAndroid Build Coastguard Worker        path.cubicTo(20, 400, 404, 75, 243, 271);
305*c8dee2aaSAndroid Build Coastguard Worker
306*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(path, paint);
307*c8dee2aaSAndroid Build Coastguard Worker
308*c8dee2aaSAndroid Build Coastguard Worker        const bounds = new Float32Array(4);
309*c8dee2aaSAndroid Build Coastguard Worker        path.getBounds(bounds);
310*c8dee2aaSAndroid Build Coastguard Worker
311*c8dee2aaSAndroid Build Coastguard Worker        paint.setColor(CanvasKit.BLUE);
312*c8dee2aaSAndroid Build Coastguard Worker        paint.setStrokeWidth(3.0);
313*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawRect(bounds, paint);
314*c8dee2aaSAndroid Build Coastguard Worker
315*c8dee2aaSAndroid Build Coastguard Worker        path.computeTightBounds(bounds);
316*c8dee2aaSAndroid Build Coastguard Worker        paint.setColor(CanvasKit.RED);
317*c8dee2aaSAndroid Build Coastguard Worker        paint.setStrokeWidth(3.0);
318*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawRect(bounds, paint);
319*c8dee2aaSAndroid Build Coastguard Worker
320*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
321*c8dee2aaSAndroid Build Coastguard Worker        paint.delete();
322*c8dee2aaSAndroid Build Coastguard Worker    });
323*c8dee2aaSAndroid Build Coastguard Worker
324*c8dee2aaSAndroid Build Coastguard Worker    gm('arcto_path', (canvas) => {
325*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
326*c8dee2aaSAndroid Build Coastguard Worker
327*c8dee2aaSAndroid Build Coastguard Worker        paint.setStyle(CanvasKit.PaintStyle.Stroke);
328*c8dee2aaSAndroid Build Coastguard Worker        paint.setStrokeWidth(5.0);
329*c8dee2aaSAndroid Build Coastguard Worker        paint.setAntiAlias(true);
330*c8dee2aaSAndroid Build Coastguard Worker        paint.setColor(CanvasKit.BLACK);
331*c8dee2aaSAndroid Build Coastguard Worker
332*c8dee2aaSAndroid Build Coastguard Worker        const path = new CanvasKit.Path();
333*c8dee2aaSAndroid Build Coastguard Worker
334*c8dee2aaSAndroid Build Coastguard Worker        // - x1, y1, x2, y2, radius
335*c8dee2aaSAndroid Build Coastguard Worker        path.arcToTangent(40, 0, 40, 40, 40);
336*c8dee2aaSAndroid Build Coastguard Worker        // - oval (as Rect), startAngle, sweepAngle, forceMoveTo
337*c8dee2aaSAndroid Build Coastguard Worker        path.arcToOval(CanvasKit.LTRBRect(90, 10, 120, 200), 30, 300, true);
338*c8dee2aaSAndroid Build Coastguard Worker        // - rx, ry, xAxisRotate, useSmallArc, isCCW, x, y
339*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(5, 105);
340*c8dee2aaSAndroid Build Coastguard Worker        path.arcToRotated(24, 24, 45, true, false, 82, 156);
341*c8dee2aaSAndroid Build Coastguard Worker
342*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(path, paint);
343*c8dee2aaSAndroid Build Coastguard Worker
344*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
345*c8dee2aaSAndroid Build Coastguard Worker        paint.delete();
346*c8dee2aaSAndroid Build Coastguard Worker    });
347*c8dee2aaSAndroid Build Coastguard Worker
348*c8dee2aaSAndroid Build Coastguard Worker    gm('path_relative', (canvas) => {
349*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
350*c8dee2aaSAndroid Build Coastguard Worker        paint.setStrokeWidth(1.0);
351*c8dee2aaSAndroid Build Coastguard Worker        paint.setAntiAlias(true);
352*c8dee2aaSAndroid Build Coastguard Worker        paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
353*c8dee2aaSAndroid Build Coastguard Worker        paint.setStyle(CanvasKit.PaintStyle.Stroke);
354*c8dee2aaSAndroid Build Coastguard Worker
355*c8dee2aaSAndroid Build Coastguard Worker        const path = new CanvasKit.Path();
356*c8dee2aaSAndroid Build Coastguard Worker        path.rMoveTo(20, 5)
357*c8dee2aaSAndroid Build Coastguard Worker            .rLineTo(10, 15)  // 30, 20
358*c8dee2aaSAndroid Build Coastguard Worker            .rLineTo(10, -5);  // 40, 10
359*c8dee2aaSAndroid Build Coastguard Worker        path.rLineTo(10, 10);  // 50, 20
360*c8dee2aaSAndroid Build Coastguard Worker        path.rLineTo(10, -20); // 60, 0
361*c8dee2aaSAndroid Build Coastguard Worker        path.rLineTo(-40, 5);  // 20, 5
362*c8dee2aaSAndroid Build Coastguard Worker
363*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(20, 80)
364*c8dee2aaSAndroid Build Coastguard Worker            .rCubicTo(70, -70, 140, 70, 170, -70); // 90, 10, 160, 150, 190, 10
365*c8dee2aaSAndroid Build Coastguard Worker
366*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(36, 148)
367*c8dee2aaSAndroid Build Coastguard Worker            .rQuadTo(30, 40, 84, -12) // 66, 188, 120, 136
368*c8dee2aaSAndroid Build Coastguard Worker            .lineTo(36, 148);
369*c8dee2aaSAndroid Build Coastguard Worker
370*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(150, 180)
371*c8dee2aaSAndroid Build Coastguard Worker            .rArcTo(24, 24, 45, true, false, -68, -24); // 82, 156
372*c8dee2aaSAndroid Build Coastguard Worker        path.lineTo(160, 160);
373*c8dee2aaSAndroid Build Coastguard Worker
374*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(path, paint);
375*c8dee2aaSAndroid Build Coastguard Worker
376*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
377*c8dee2aaSAndroid Build Coastguard Worker        paint.delete();
378*c8dee2aaSAndroid Build Coastguard Worker    });
379*c8dee2aaSAndroid Build Coastguard Worker
380*c8dee2aaSAndroid Build Coastguard Worker    it('can measure the contours of a path',  () => {
381*c8dee2aaSAndroid Build Coastguard Worker        const path = new CanvasKit.Path();
382*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(10, 10)
383*c8dee2aaSAndroid Build Coastguard Worker            .lineTo(40, 50); // should be length 50 because of the 3/4/5 triangle rule
384*c8dee2aaSAndroid Build Coastguard Worker
385*c8dee2aaSAndroid Build Coastguard Worker        path.moveTo(80, 0)
386*c8dee2aaSAndroid Build Coastguard Worker            .lineTo(80, 10)
387*c8dee2aaSAndroid Build Coastguard Worker            .lineTo(100, 5)
388*c8dee2aaSAndroid Build Coastguard Worker            .lineTo(80, 0);
389*c8dee2aaSAndroid Build Coastguard Worker
390*c8dee2aaSAndroid Build Coastguard Worker        const meas = new CanvasKit.ContourMeasureIter(path, false, 1);
391*c8dee2aaSAndroid Build Coastguard Worker        let cont = meas.next();
392*c8dee2aaSAndroid Build Coastguard Worker        expect(cont).toBeTruthy();
393*c8dee2aaSAndroid Build Coastguard Worker
394*c8dee2aaSAndroid Build Coastguard Worker        expect(cont.length()).toBeCloseTo(50.0, 3);
395*c8dee2aaSAndroid Build Coastguard Worker        const pt = cont.getPosTan(28.7); // arbitrary point
396*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[0]).toBeCloseTo(27.22, 3); // x
397*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[1]).toBeCloseTo(32.96, 3); // y
398*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[2]).toBeCloseTo(0.6, 3);   // dy
399*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[3]).toBeCloseTo(0.8, 3);   // dy
400*c8dee2aaSAndroid Build Coastguard Worker
401*c8dee2aaSAndroid Build Coastguard Worker        pt.set([-1, -1, -1, -1]); // fill with sentinel values.
402*c8dee2aaSAndroid Build Coastguard Worker        cont.getPosTan(28.7, pt); // arbitrary point again, passing in an array to copy into.
403*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[0]).toBeCloseTo(27.22, 3); // x
404*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[1]).toBeCloseTo(32.96, 3); // y
405*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[2]).toBeCloseTo(0.6, 3);   // dy
406*c8dee2aaSAndroid Build Coastguard Worker        expect(pt[3]).toBeCloseTo(0.8, 3);   // dy
407*c8dee2aaSAndroid Build Coastguard Worker
408*c8dee2aaSAndroid Build Coastguard Worker        const subpath = cont.getSegment(20, 40, true); // make sure this doesn't crash
409*c8dee2aaSAndroid Build Coastguard Worker
410*c8dee2aaSAndroid Build Coastguard Worker        cont.delete();
411*c8dee2aaSAndroid Build Coastguard Worker        cont = meas.next();
412*c8dee2aaSAndroid Build Coastguard Worker        expect(cont).toBeTruthy();
413*c8dee2aaSAndroid Build Coastguard Worker        expect(cont.length()).toBeCloseTo(51.231, 3);
414*c8dee2aaSAndroid Build Coastguard Worker
415*c8dee2aaSAndroid Build Coastguard Worker        cont.delete();
416*c8dee2aaSAndroid Build Coastguard Worker        expect(meas.next()).toBeFalsy();
417*c8dee2aaSAndroid Build Coastguard Worker
418*c8dee2aaSAndroid Build Coastguard Worker        meas.delete();
419*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
420*c8dee2aaSAndroid Build Coastguard Worker    });
421*c8dee2aaSAndroid Build Coastguard Worker
422*c8dee2aaSAndroid Build Coastguard Worker    gm('drawpoly_path', (canvas) => {
423*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
424*c8dee2aaSAndroid Build Coastguard Worker        paint.setStrokeWidth(1.0);
425*c8dee2aaSAndroid Build Coastguard Worker        paint.setAntiAlias(true);
426*c8dee2aaSAndroid Build Coastguard Worker        paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
427*c8dee2aaSAndroid Build Coastguard Worker        paint.setStyle(CanvasKit.PaintStyle.Stroke);
428*c8dee2aaSAndroid Build Coastguard Worker
429*c8dee2aaSAndroid Build Coastguard Worker        const points = [5, 5,  30, 20,  55, 5,  55, 50,  30, 30,  5, 50];
430*c8dee2aaSAndroid Build Coastguard Worker
431*c8dee2aaSAndroid Build Coastguard Worker        const pointsObj = CanvasKit.Malloc(Float32Array, 6 * 2);
432*c8dee2aaSAndroid Build Coastguard Worker        const mPoints = pointsObj.toTypedArray();
433*c8dee2aaSAndroid Build Coastguard Worker        mPoints.set([105, 105, 130, 120, 155, 105, 155, 150, 130, 130, 105, 150]);
434*c8dee2aaSAndroid Build Coastguard Worker
435*c8dee2aaSAndroid Build Coastguard Worker        const path = new CanvasKit.Path();
436*c8dee2aaSAndroid Build Coastguard Worker        path.addPoly(points, true)
437*c8dee2aaSAndroid Build Coastguard Worker            .moveTo(100, 0)
438*c8dee2aaSAndroid Build Coastguard Worker            .addPoly(mPoints, true);
439*c8dee2aaSAndroid Build Coastguard Worker
440*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(path, paint);
441*c8dee2aaSAndroid Build Coastguard Worker        CanvasKit.Free(pointsObj);
442*c8dee2aaSAndroid Build Coastguard Worker
443*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
444*c8dee2aaSAndroid Build Coastguard Worker        paint.delete();
445*c8dee2aaSAndroid Build Coastguard Worker    });
446*c8dee2aaSAndroid Build Coastguard Worker
447*c8dee2aaSAndroid Build Coastguard Worker    // Test trim, adding paths to paths, and a bunch of other path methods.
448*c8dee2aaSAndroid Build Coastguard Worker    gm('trim_path', (canvas) => {
449*c8dee2aaSAndroid Build Coastguard Worker
450*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
451*c8dee2aaSAndroid Build Coastguard Worker        paint.setStrokeWidth(1.0);
452*c8dee2aaSAndroid Build Coastguard Worker        paint.setAntiAlias(true);
453*c8dee2aaSAndroid Build Coastguard Worker        paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
454*c8dee2aaSAndroid Build Coastguard Worker        paint.setStyle(CanvasKit.PaintStyle.Stroke);
455*c8dee2aaSAndroid Build Coastguard Worker
456*c8dee2aaSAndroid Build Coastguard Worker        const arcpath = new CanvasKit.Path();
457*c8dee2aaSAndroid Build Coastguard Worker        arcpath.arc(400, 400, 100, 0, -90, false) // x, y, radius, startAngle, endAngle, ccw
458*c8dee2aaSAndroid Build Coastguard Worker               .dash(3, 1, 0)
459*c8dee2aaSAndroid Build Coastguard Worker               .conicTo(10, 20, 30, 40, 5)
460*c8dee2aaSAndroid Build Coastguard Worker               .rConicTo(60, 70, 80, 90, 5)
461*c8dee2aaSAndroid Build Coastguard Worker               .trim(0.2, 1, false);
462*c8dee2aaSAndroid Build Coastguard Worker
463*c8dee2aaSAndroid Build Coastguard Worker        const path = new CanvasKit.Path();
464*c8dee2aaSAndroid Build Coastguard Worker        path.addArc(CanvasKit.LTRBRect(10, 20, 100, 200), 30, 300)
465*c8dee2aaSAndroid Build Coastguard Worker            .addRect(CanvasKit.LTRBRect(200, 200, 300, 300)) // test single arg, default cw
466*c8dee2aaSAndroid Build Coastguard Worker            .addRect(CanvasKit.LTRBRect(240, 240, 260, 260), true) // test two arg, true means ccw
467*c8dee2aaSAndroid Build Coastguard Worker            .addRect([260, 260, 290, 290], true) // test five arg, true means ccw
468*c8dee2aaSAndroid Build Coastguard Worker            .addRRect([300, 10, 500, 290, // Rect in LTRB order
469*c8dee2aaSAndroid Build Coastguard Worker                       60, 60, 60, 60, 60, 60, 60, 60], // all radii are the same
470*c8dee2aaSAndroid Build Coastguard Worker                       false) // ccw
471*c8dee2aaSAndroid Build Coastguard Worker            .addRRect(CanvasKit.RRectXY([350, 60, 450, 240], 20, 80), true) // Rect, rx, ry, ccw
472*c8dee2aaSAndroid Build Coastguard Worker            .addPath(arcpath)
473*c8dee2aaSAndroid Build Coastguard Worker            .transform(0.54, -0.84,  390.35,
474*c8dee2aaSAndroid Build Coastguard Worker                       0.84,  0.54, -114.53,
475*c8dee2aaSAndroid Build Coastguard Worker                          0,     0,       1);
476*c8dee2aaSAndroid Build Coastguard Worker
477*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(path, paint);
478*c8dee2aaSAndroid Build Coastguard Worker
479*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
480*c8dee2aaSAndroid Build Coastguard Worker        paint.delete();
481*c8dee2aaSAndroid Build Coastguard Worker    });
482*c8dee2aaSAndroid Build Coastguard Worker
483*c8dee2aaSAndroid Build Coastguard Worker    gm('winding_example', (canvas) => {
484*c8dee2aaSAndroid Build Coastguard Worker        // Inspired by https://fiddle.skia.org/c/@Path_FillType_a
485*c8dee2aaSAndroid Build Coastguard Worker        const path = new CanvasKit.Path();
486*c8dee2aaSAndroid Build Coastguard Worker        // Draw overlapping rects on top
487*c8dee2aaSAndroid Build Coastguard Worker        path.addRect(CanvasKit.LTRBRect(10, 10, 30, 30), false);
488*c8dee2aaSAndroid Build Coastguard Worker        path.addRect(CanvasKit.LTRBRect(20, 20, 40, 40), false);
489*c8dee2aaSAndroid Build Coastguard Worker        // Draw overlapping rects on bottom, with different direction lines.
490*c8dee2aaSAndroid Build Coastguard Worker        path.addRect(CanvasKit.LTRBRect(10, 60, 30, 80), false);
491*c8dee2aaSAndroid Build Coastguard Worker        path.addRect(CanvasKit.LTRBRect(20, 70, 40, 90), true);
492*c8dee2aaSAndroid Build Coastguard Worker
493*c8dee2aaSAndroid Build Coastguard Worker        expect(path.getFillType()).toEqual(CanvasKit.FillType.Winding);
494*c8dee2aaSAndroid Build Coastguard Worker
495*c8dee2aaSAndroid Build Coastguard Worker        // Draw the two rectangles on the left side.
496*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
497*c8dee2aaSAndroid Build Coastguard Worker        paint.setStyle(CanvasKit.PaintStyle.Stroke);
498*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(path, paint);
499*c8dee2aaSAndroid Build Coastguard Worker
500*c8dee2aaSAndroid Build Coastguard Worker        const clipRect = CanvasKit.LTRBRect(0, 0, 51, 100);
501*c8dee2aaSAndroid Build Coastguard Worker        paint.setStyle(CanvasKit.PaintStyle.Fill);
502*c8dee2aaSAndroid Build Coastguard Worker
503*c8dee2aaSAndroid Build Coastguard Worker        for (const fillType of [CanvasKit.FillType.Winding, CanvasKit.FillType.EvenOdd]) {
504*c8dee2aaSAndroid Build Coastguard Worker            canvas.translate(51, 0);
505*c8dee2aaSAndroid Build Coastguard Worker            canvas.save();
506*c8dee2aaSAndroid Build Coastguard Worker            canvas.clipRect(clipRect, CanvasKit.ClipOp.Intersect, false);
507*c8dee2aaSAndroid Build Coastguard Worker            path.setFillType(fillType);
508*c8dee2aaSAndroid Build Coastguard Worker            canvas.drawPath(path, paint);
509*c8dee2aaSAndroid Build Coastguard Worker            canvas.restore();
510*c8dee2aaSAndroid Build Coastguard Worker        }
511*c8dee2aaSAndroid Build Coastguard Worker
512*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
513*c8dee2aaSAndroid Build Coastguard Worker        paint.delete();
514*c8dee2aaSAndroid Build Coastguard Worker    });
515*c8dee2aaSAndroid Build Coastguard Worker
516*c8dee2aaSAndroid Build Coastguard Worker    gm('as_winding', (canvas) => {
517*c8dee2aaSAndroid Build Coastguard Worker        const evenOddPath = new CanvasKit.Path();
518*c8dee2aaSAndroid Build Coastguard Worker        // Draw overlapping rects
519*c8dee2aaSAndroid Build Coastguard Worker        evenOddPath.addRect(CanvasKit.LTRBRect(10, 10, 70, 70), false);
520*c8dee2aaSAndroid Build Coastguard Worker        evenOddPath.addRect(CanvasKit.LTRBRect(30, 30, 50, 50), false);
521*c8dee2aaSAndroid Build Coastguard Worker        evenOddPath.setFillType(CanvasKit.FillType.EvenOdd);
522*c8dee2aaSAndroid Build Coastguard Worker
523*c8dee2aaSAndroid Build Coastguard Worker        const evenOddCmds = evenOddPath.toCmds();
524*c8dee2aaSAndroid Build Coastguard Worker        expect(evenOddCmds).toEqual(Float32Array.of(
525*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.MOVE_VERB, 10, 10,
526*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.LINE_VERB, 70, 10,
527*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.LINE_VERB, 70, 70,
528*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.LINE_VERB, 10, 70,
529*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.CLOSE_VERB,
530*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.MOVE_VERB, 30, 30, // This contour is drawn
531*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.LINE_VERB, 50, 30, // clockwise, as specified.
532*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.LINE_VERB, 50, 50,
533*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.LINE_VERB, 30, 50,
534*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.CLOSE_VERB
535*c8dee2aaSAndroid Build Coastguard Worker        ));
536*c8dee2aaSAndroid Build Coastguard Worker
537*c8dee2aaSAndroid Build Coastguard Worker        const windingPath = evenOddPath.makeAsWinding();
538*c8dee2aaSAndroid Build Coastguard Worker
539*c8dee2aaSAndroid Build Coastguard Worker        expect(windingPath.getFillType()).toBe(CanvasKit.FillType.Winding);
540*c8dee2aaSAndroid Build Coastguard Worker        const windingCmds = windingPath.toCmds();
541*c8dee2aaSAndroid Build Coastguard Worker        expect(windingCmds).toEqual(Float32Array.of(
542*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.MOVE_VERB, 10, 10,
543*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.LINE_VERB, 70, 10,
544*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.LINE_VERB, 70, 70,
545*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.LINE_VERB, 10, 70,
546*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.CLOSE_VERB,
547*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.MOVE_VERB, 30, 50, // This contour has been
548*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.LINE_VERB, 50, 50, // re-drawn counter-clockwise
549*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.LINE_VERB, 50, 30, // so that it covers the same
550*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.LINE_VERB, 30, 30, // area, but with the winding fill type.
551*c8dee2aaSAndroid Build Coastguard Worker          CanvasKit.CLOSE_VERB
552*c8dee2aaSAndroid Build Coastguard Worker        ));
553*c8dee2aaSAndroid Build Coastguard Worker
554*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
555*c8dee2aaSAndroid Build Coastguard Worker        paint.setStyle(CanvasKit.PaintStyle.Fill);
556*c8dee2aaSAndroid Build Coastguard Worker        const font = new CanvasKit.Font(CanvasKit.Typeface.GetDefault(), 20);
557*c8dee2aaSAndroid Build Coastguard Worker
558*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawText('Original path (even odd)', 5, 20, paint, font);
559*c8dee2aaSAndroid Build Coastguard Worker        canvas.translate(0, 50);
560*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(evenOddPath, paint);
561*c8dee2aaSAndroid Build Coastguard Worker
562*c8dee2aaSAndroid Build Coastguard Worker        canvas.translate(300, 0);
563*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawPath(windingPath, paint);
564*c8dee2aaSAndroid Build Coastguard Worker
565*c8dee2aaSAndroid Build Coastguard Worker        canvas.translate(0, -50);
566*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawText('makeAsWinding path', 5, 20, paint, font);
567*c8dee2aaSAndroid Build Coastguard Worker
568*c8dee2aaSAndroid Build Coastguard Worker        evenOddPath.delete();
569*c8dee2aaSAndroid Build Coastguard Worker        windingPath.delete();
570*c8dee2aaSAndroid Build Coastguard Worker    });
571*c8dee2aaSAndroid Build Coastguard Worker});
572