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