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