1cb93a386Sopenharmony_cidescribe('Canvas 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('canvas_api_example', (canvas) => { 18cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 19cb93a386Sopenharmony_ci paint.setStrokeWidth(2.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 canvas.drawLine(3, 10, 30, 15, paint); 25cb93a386Sopenharmony_ci const rrect = CanvasKit.RRectXY([5, 35, 45, 80], 15, 10); 26cb93a386Sopenharmony_ci canvas.drawRRect(rrect, paint); 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ci canvas.drawOval(CanvasKit.LTRBRect(5, 35, 45, 80), paint); 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci canvas.drawArc(CanvasKit.LTRBRect(55, 35, 95, 80), 15, 270, true, paint); 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ci const font = new CanvasKit.Font(null, 20); 33cb93a386Sopenharmony_ci canvas.drawText('this is ascii text', 5, 100, paint, font); 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci const blob = CanvasKit.TextBlob.MakeFromText('Unicode chars é É ص', font); 36cb93a386Sopenharmony_ci canvas.drawTextBlob(blob, 5, 130, paint); 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci font.delete(); 39cb93a386Sopenharmony_ci blob.delete(); 40cb93a386Sopenharmony_ci paint.delete(); 41cb93a386Sopenharmony_ci // See canvas2d for more API tests 42cb93a386Sopenharmony_ci }); 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci gm('effect_and_text_example', (canvas) => { 45cb93a386Sopenharmony_ci const path = starPath(CanvasKit); 46cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci const textPaint = new CanvasKit.Paint(); 49cb93a386Sopenharmony_ci textPaint.setColor(CanvasKit.Color(40, 0, 0, 1.0)); 50cb93a386Sopenharmony_ci textPaint.setAntiAlias(true); 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci const textFont = new CanvasKit.Font(null, 30); 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci const dpe = CanvasKit.PathEffect.MakeDash([15, 5, 5, 10], 1); 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci paint.setPathEffect(dpe); 57cb93a386Sopenharmony_ci paint.setStyle(CanvasKit.PaintStyle.Stroke); 58cb93a386Sopenharmony_ci paint.setStrokeWidth(5.0); 59cb93a386Sopenharmony_ci paint.setAntiAlias(true); 60cb93a386Sopenharmony_ci paint.setColor(CanvasKit.Color(66, 129, 164, 1.0)); 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ci canvas.clear(CanvasKit.Color(255, 255, 255, 1.0)); 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci canvas.drawPath(path, paint); 65cb93a386Sopenharmony_ci canvas.drawText('This is text', 10, 280, textPaint, textFont); 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci dpe.delete(); 68cb93a386Sopenharmony_ci path.delete(); 69cb93a386Sopenharmony_ci paint.delete(); 70cb93a386Sopenharmony_ci textFont.delete(); 71cb93a386Sopenharmony_ci textPaint.delete(); 72cb93a386Sopenharmony_ci }); 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci gm('patheffects_canvas', (canvas) => { 75cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 76cb93a386Sopenharmony_ci const path = starPath(CanvasKit, 100, 100, 100); 77cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci const cornerEffect = CanvasKit.PathEffect.MakeCorner(10); 80cb93a386Sopenharmony_ci const discreteEffect = CanvasKit.PathEffect.MakeDiscrete(5, 10, 0); 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ci paint.setPathEffect(cornerEffect); 83cb93a386Sopenharmony_ci paint.setStyle(CanvasKit.PaintStyle.Stroke); 84cb93a386Sopenharmony_ci paint.setStrokeWidth(5.0); 85cb93a386Sopenharmony_ci paint.setAntiAlias(true); 86cb93a386Sopenharmony_ci paint.setColor(CanvasKit.Color(66, 129, 164, 1.0)); 87cb93a386Sopenharmony_ci canvas.drawPath(path, paint); 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci canvas.translate(200, 0); 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ci paint.setPathEffect(discreteEffect); 92cb93a386Sopenharmony_ci canvas.drawPath(path, paint); 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci cornerEffect.delete(); 95cb93a386Sopenharmony_ci path.delete(); 96cb93a386Sopenharmony_ci paint.delete(); 97cb93a386Sopenharmony_ci }); 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci it('returns the depth of the save state stack', () => { 100cb93a386Sopenharmony_ci const canvas = new CanvasKit.Canvas(); 101cb93a386Sopenharmony_ci expect(canvas.getSaveCount()).toEqual(1); 102cb93a386Sopenharmony_ci canvas.save(); 103cb93a386Sopenharmony_ci canvas.save(); 104cb93a386Sopenharmony_ci canvas.restore(); 105cb93a386Sopenharmony_ci canvas.save(); 106cb93a386Sopenharmony_ci canvas.save(); 107cb93a386Sopenharmony_ci expect(canvas.getSaveCount()).toEqual(4); 108cb93a386Sopenharmony_ci // does nothing, by the SkCanvas API 109cb93a386Sopenharmony_ci canvas.restoreToCount(500); 110cb93a386Sopenharmony_ci expect(canvas.getSaveCount()).toEqual(4); 111cb93a386Sopenharmony_ci canvas.restore(); 112cb93a386Sopenharmony_ci expect(canvas.getSaveCount()).toEqual(3); 113cb93a386Sopenharmony_ci canvas.save(); 114cb93a386Sopenharmony_ci canvas.restoreToCount(2); 115cb93a386Sopenharmony_ci expect(canvas.getSaveCount()).toEqual(2); 116cb93a386Sopenharmony_ci }); 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci gm('circle_canvas', (canvas) => { 119cb93a386Sopenharmony_ci const path = starPath(CanvasKit); 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci paint.setStyle(CanvasKit.PaintStyle.Stroke); 124cb93a386Sopenharmony_ci paint.setStrokeWidth(5.0); 125cb93a386Sopenharmony_ci paint.setAntiAlias(true); 126cb93a386Sopenharmony_ci paint.setColor(CanvasKit.CYAN); 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci canvas.drawCircle(30, 50, 15, paint); 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci paint.setStyle(CanvasKit.PaintStyle.Fill); 133cb93a386Sopenharmony_ci paint.setColor(CanvasKit.RED); 134cb93a386Sopenharmony_ci canvas.drawCircle(130, 80, 60, paint); 135cb93a386Sopenharmony_ci canvas.drawCircle(20, 150, 60, paint); 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ci path.delete(); 138cb93a386Sopenharmony_ci paint.delete(); 139cb93a386Sopenharmony_ci }); 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci gm('rrect_canvas', (canvas) => { 142cb93a386Sopenharmony_ci const path = starPath(CanvasKit); 143cb93a386Sopenharmony_ci 144cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci paint.setStyle(CanvasKit.PaintStyle.Stroke); 147cb93a386Sopenharmony_ci paint.setStrokeWidth(3.0); 148cb93a386Sopenharmony_ci paint.setAntiAlias(true); 149cb93a386Sopenharmony_ci paint.setColor(CanvasKit.BLACK); 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci canvas.drawRRect(CanvasKit.RRectXY( 154cb93a386Sopenharmony_ci CanvasKit.LTRBRect(10, 10, 50, 50), 5, 10), paint); 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci canvas.drawRRect(CanvasKit.RRectXY( 157cb93a386Sopenharmony_ci CanvasKit.LTRBRect(60, 10, 110, 50), 10, 5), paint); 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_ci canvas.drawRRect(CanvasKit.RRectXY( 160cb93a386Sopenharmony_ci CanvasKit.LTRBRect(10, 60, 210, 260), 0, 30), paint); 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ci canvas.drawRRect(CanvasKit.RRectXY( 163cb93a386Sopenharmony_ci CanvasKit.LTRBRect(50, 90, 160, 210), 30, 30), paint); 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci path.delete(); 166cb93a386Sopenharmony_ci paint.delete(); 167cb93a386Sopenharmony_ci }); 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci gm('rrect_8corners_canvas', (canvas) => { 170cb93a386Sopenharmony_ci const path = starPath(CanvasKit); 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci paint.setStyle(CanvasKit.PaintStyle.Stroke); 175cb93a386Sopenharmony_ci paint.setStrokeWidth(3.0); 176cb93a386Sopenharmony_ci paint.setAntiAlias(true); 177cb93a386Sopenharmony_ci paint.setColor(CanvasKit.BLACK); 178cb93a386Sopenharmony_ci 179cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci canvas.drawRRect([10, 10, 210, 210, 182cb93a386Sopenharmony_ci // top left corner, going clockwise 183cb93a386Sopenharmony_ci 10, 30, 184cb93a386Sopenharmony_ci 30, 10, 185cb93a386Sopenharmony_ci 50, 75, 186cb93a386Sopenharmony_ci 120, 120, 187cb93a386Sopenharmony_ci ], paint); 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ci path.delete(); 190cb93a386Sopenharmony_ci paint.delete(); 191cb93a386Sopenharmony_ci }); 192cb93a386Sopenharmony_ci 193cb93a386Sopenharmony_ci // As above, except with the array passed in via malloc'd memory. 194cb93a386Sopenharmony_ci gm('rrect_8corners_malloc_canvas', (canvas) => { 195cb93a386Sopenharmony_ci const path = starPath(CanvasKit); 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_ci paint.setStyle(CanvasKit.PaintStyle.Stroke); 200cb93a386Sopenharmony_ci paint.setStrokeWidth(3.0); 201cb93a386Sopenharmony_ci paint.setAntiAlias(true); 202cb93a386Sopenharmony_ci paint.setColor(CanvasKit.BLACK); 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci const rrect = CanvasKit.Malloc(Float32Array, 12); 207cb93a386Sopenharmony_ci rrect.toTypedArray().set([10, 10, 210, 210, 208cb93a386Sopenharmony_ci // top left corner, going clockwise 209cb93a386Sopenharmony_ci 10, 30, 210cb93a386Sopenharmony_ci 30, 10, 211cb93a386Sopenharmony_ci 50, 75, 212cb93a386Sopenharmony_ci 120, 120, 213cb93a386Sopenharmony_ci ]); 214cb93a386Sopenharmony_ci 215cb93a386Sopenharmony_ci canvas.drawRRect(rrect, paint); 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci CanvasKit.Free(rrect); 218cb93a386Sopenharmony_ci path.delete(); 219cb93a386Sopenharmony_ci paint.delete(); 220cb93a386Sopenharmony_ci }); 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci gm('drawDRRect_canvas', (canvas) => { 223cb93a386Sopenharmony_ci const path = starPath(CanvasKit); 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci paint.setStyle(CanvasKit.PaintStyle.Fill); 228cb93a386Sopenharmony_ci paint.setStrokeWidth(3.0); 229cb93a386Sopenharmony_ci paint.setAntiAlias(true); 230cb93a386Sopenharmony_ci paint.setColor(CanvasKit.BLACK); 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci const outer = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 10, 5); 235cb93a386Sopenharmony_ci const inner = CanvasKit.RRectXY(CanvasKit.LTRBRect(50, 90, 160, 210), 30, 30); 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci canvas.drawDRRect(outer, inner, paint); 238cb93a386Sopenharmony_ci 239cb93a386Sopenharmony_ci path.delete(); 240cb93a386Sopenharmony_ci paint.delete(); 241cb93a386Sopenharmony_ci }); 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci gm('colorfilters_canvas', (canvas) => { 244cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 245cb93a386Sopenharmony_ci 246cb93a386Sopenharmony_ci const blue = CanvasKit.ColorFilter.MakeBlend( 247cb93a386Sopenharmony_ci CanvasKit.BLUE, CanvasKit.BlendMode.SrcIn); 248cb93a386Sopenharmony_ci const red = CanvasKit.ColorFilter.MakeBlend( 249cb93a386Sopenharmony_ci CanvasKit.Color(255, 0, 0, 0.8), CanvasKit.BlendMode.SrcOver); 250cb93a386Sopenharmony_ci const lerp = CanvasKit.ColorFilter.MakeLerp(0.6, red, blue); 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci paint.setStyle(CanvasKit.PaintStyle.Fill); 253cb93a386Sopenharmony_ci paint.setAntiAlias(true); 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_ci canvas.clear(CanvasKit.Color(230, 230, 230)); 256cb93a386Sopenharmony_ci 257cb93a386Sopenharmony_ci paint.setColorFilter(blue) 258cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(10, 10, 60, 60), paint); 259cb93a386Sopenharmony_ci paint.setColorFilter(lerp) 260cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(50, 10, 100, 60), paint); 261cb93a386Sopenharmony_ci paint.setColorFilter(red) 262cb93a386Sopenharmony_ci canvas.drawRect4f(90, 10, 140, 60, paint); 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_ci const r = CanvasKit.ColorMatrix.rotated(0, .707, -.707); 265cb93a386Sopenharmony_ci const b = CanvasKit.ColorMatrix.rotated(2, .5, .866); 266cb93a386Sopenharmony_ci const s = CanvasKit.ColorMatrix.scaled(0.9, 1.5, 0.8, 0.8); 267cb93a386Sopenharmony_ci let cm = CanvasKit.ColorMatrix.concat(r, s); 268cb93a386Sopenharmony_ci cm = CanvasKit.ColorMatrix.concat(cm, b); 269cb93a386Sopenharmony_ci CanvasKit.ColorMatrix.postTranslate(cm, 20, 0, -10, 0); 270cb93a386Sopenharmony_ci 271cb93a386Sopenharmony_ci const mat = CanvasKit.ColorFilter.MakeMatrix(cm); 272cb93a386Sopenharmony_ci const final = CanvasKit.ColorFilter.MakeCompose(mat, lerp); 273cb93a386Sopenharmony_ci 274cb93a386Sopenharmony_ci paint.setColorFilter(final) 275cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(10, 70, 140, 120), paint); 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_ci paint.delete(); 278cb93a386Sopenharmony_ci blue.delete(); 279cb93a386Sopenharmony_ci red.delete(); 280cb93a386Sopenharmony_ci lerp.delete(); 281cb93a386Sopenharmony_ci final.delete(); 282cb93a386Sopenharmony_ci }); 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci gm('blendmodes_canvas', (canvas) => { 285cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 286cb93a386Sopenharmony_ci 287cb93a386Sopenharmony_ci const blendModeNames = Object.keys(CanvasKit.BlendMode).filter((key) => key !== 'values'); 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci const PASTEL_MUSTARD_YELLOW = CanvasKit.Color(248, 213, 85, 1.0); 290cb93a386Sopenharmony_ci const PASTEL_SKY_BLUE = CanvasKit.Color(74, 174, 245, 1.0); 291cb93a386Sopenharmony_ci 292cb93a386Sopenharmony_ci const shapePaint = new CanvasKit.Paint(); 293cb93a386Sopenharmony_ci shapePaint.setColor(PASTEL_MUSTARD_YELLOW); 294cb93a386Sopenharmony_ci shapePaint.setAntiAlias(true); 295cb93a386Sopenharmony_ci 296cb93a386Sopenharmony_ci const textPaint = new CanvasKit.Paint(); 297cb93a386Sopenharmony_ci textPaint.setAntiAlias(true); 298cb93a386Sopenharmony_ci 299cb93a386Sopenharmony_ci const textFont = new CanvasKit.Font(null, 10); 300cb93a386Sopenharmony_ci 301cb93a386Sopenharmony_ci let x = 10; 302cb93a386Sopenharmony_ci let y = 20; 303cb93a386Sopenharmony_ci for (const blendModeName of blendModeNames) { 304cb93a386Sopenharmony_ci // Draw a checkerboard for each blend mode. 305cb93a386Sopenharmony_ci // Each checkerboard is labelled with a blendmode's name. 306cb93a386Sopenharmony_ci canvas.drawText(blendModeName, x, y - 5, textPaint, textFont); 307cb93a386Sopenharmony_ci drawCheckerboard(canvas, x, y, x + 80, y + 80); 308cb93a386Sopenharmony_ci 309cb93a386Sopenharmony_ci // A blue square is drawn on to each checkerboard with yellow circle. 310cb93a386Sopenharmony_ci // In each checkerboard the blue square is drawn using a different blendmode. 311cb93a386Sopenharmony_ci const blendMode = CanvasKit.BlendMode[blendModeName]; 312cb93a386Sopenharmony_ci canvas.drawOval(CanvasKit.LTRBRect(x + 5, y + 5, x + 55, y + 55), shapePaint); 313cb93a386Sopenharmony_ci drawRectangle(x + 30, y + 30, x + 70, y + 70, PASTEL_SKY_BLUE, blendMode); 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci x += 90; 316cb93a386Sopenharmony_ci if (x > 500) { 317cb93a386Sopenharmony_ci x = 10; 318cb93a386Sopenharmony_ci y += 110; 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci } 321cb93a386Sopenharmony_ci 322cb93a386Sopenharmony_ci function drawCheckerboard(canvas, x1, y1, x2, y2) { 323cb93a386Sopenharmony_ci const CHECKERBOARD_SQUARE_SIZE = 5; 324cb93a386Sopenharmony_ci const GREY = CanvasKit.Color(220, 220, 220, 0.5); 325cb93a386Sopenharmony_ci // Draw black border and white background for checkerboard 326cb93a386Sopenharmony_ci drawRectangle(x1-1, y1-1, x2+1, y2+1, CanvasKit.BLACK); 327cb93a386Sopenharmony_ci drawRectangle(x1, y1, x2, y2, CanvasKit.WHITE); 328cb93a386Sopenharmony_ci 329cb93a386Sopenharmony_ci // Draw checkerboard squares 330cb93a386Sopenharmony_ci const numberOfColumns = (x2 - x1) / CHECKERBOARD_SQUARE_SIZE; 331cb93a386Sopenharmony_ci const numberOfRows = (y2 - y1) / CHECKERBOARD_SQUARE_SIZE 332cb93a386Sopenharmony_ci 333cb93a386Sopenharmony_ci for (let row = 0; row < numberOfRows; row++) { 334cb93a386Sopenharmony_ci for (let column = 0; column < numberOfColumns; column++) { 335cb93a386Sopenharmony_ci const rowIsEven = row % 2 === 0; 336cb93a386Sopenharmony_ci const columnIsEven = column % 2 === 0; 337cb93a386Sopenharmony_ci 338cb93a386Sopenharmony_ci if ((rowIsEven && !columnIsEven) || (!rowIsEven && columnIsEven)) { 339cb93a386Sopenharmony_ci drawRectangle( 340cb93a386Sopenharmony_ci x1 + CHECKERBOARD_SQUARE_SIZE * row, 341cb93a386Sopenharmony_ci y1 + CHECKERBOARD_SQUARE_SIZE * column, 342cb93a386Sopenharmony_ci Math.min(x1 + CHECKERBOARD_SQUARE_SIZE * row + CHECKERBOARD_SQUARE_SIZE, x2), 343cb93a386Sopenharmony_ci Math.min(y1 + CHECKERBOARD_SQUARE_SIZE * column + CHECKERBOARD_SQUARE_SIZE, y2), 344cb93a386Sopenharmony_ci GREY 345cb93a386Sopenharmony_ci ); 346cb93a386Sopenharmony_ci } 347cb93a386Sopenharmony_ci } 348cb93a386Sopenharmony_ci } 349cb93a386Sopenharmony_ci } 350cb93a386Sopenharmony_ci 351cb93a386Sopenharmony_ci function drawRectangle(x1, y1, x2, y2, color, blendMode=CanvasKit.BlendMode.srcOver) { 352cb93a386Sopenharmony_ci canvas.save(); 353cb93a386Sopenharmony_ci canvas.clipRect(CanvasKit.LTRBRect(x1, y1, x2, y2), CanvasKit.ClipOp.Intersect, true); 354cb93a386Sopenharmony_ci canvas.drawColor(color, blendMode); 355cb93a386Sopenharmony_ci canvas.restore(); 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci }); 358cb93a386Sopenharmony_ci 359cb93a386Sopenharmony_ci gm('colorfilters_malloc_canvas', (canvas) => { 360cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 361cb93a386Sopenharmony_ci 362cb93a386Sopenharmony_ci const src = [ 363cb93a386Sopenharmony_ci 0.8, 0.45, 2, 0, 20, 364cb93a386Sopenharmony_ci 0.53, -0.918, 0.566, 0, 0, 365cb93a386Sopenharmony_ci 0.53, -0.918, -0.566, 0, -10, 366cb93a386Sopenharmony_ci 0, 0, 0, 0.8, 0, 367cb93a386Sopenharmony_ci ] 368cb93a386Sopenharmony_ci const colorObj = new CanvasKit.Malloc(Float32Array, 20); 369cb93a386Sopenharmony_ci const cm = colorObj.toTypedArray(); 370cb93a386Sopenharmony_ci for (i in src) { 371cb93a386Sopenharmony_ci cm[i] = src[i]; 372cb93a386Sopenharmony_ci } 373cb93a386Sopenharmony_ci // MakeMatrix will free the malloc'd array when it is done with it. 374cb93a386Sopenharmony_ci const final = CanvasKit.ColorFilter.MakeMatrix(cm); 375cb93a386Sopenharmony_ci 376cb93a386Sopenharmony_ci paint.setColorFilter(final) 377cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(10, 70, 140, 120), paint); 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci CanvasKit.Free(colorObj); 380cb93a386Sopenharmony_ci paint.delete(); 381cb93a386Sopenharmony_ci final.delete(); 382cb93a386Sopenharmony_ci }); 383cb93a386Sopenharmony_ci 384cb93a386Sopenharmony_ci gm('clips_canvas', (canvas) => { 385cb93a386Sopenharmony_ci const path = starPath(CanvasKit); 386cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 387cb93a386Sopenharmony_ci paint.setColor(CanvasKit.BLUE); 388cb93a386Sopenharmony_ci const rrect = CanvasKit.RRectXY(CanvasKit.LTRBRect(300, 300, 500, 500), 40, 40); 389cb93a386Sopenharmony_ci 390cb93a386Sopenharmony_ci canvas.save(); 391cb93a386Sopenharmony_ci // draw magenta around the outside edge of an rrect. 392cb93a386Sopenharmony_ci canvas.clipRRect(rrect, CanvasKit.ClipOp.Difference, true); 393cb93a386Sopenharmony_ci canvas.drawColorComponents(250/255, 30/255, 240/255, 0.9, CanvasKit.BlendMode.SrcOver); 394cb93a386Sopenharmony_ci canvas.restore(); 395cb93a386Sopenharmony_ci 396cb93a386Sopenharmony_ci // draw grey inside of a star pattern, then the blue star on top 397cb93a386Sopenharmony_ci canvas.clipPath(path, CanvasKit.ClipOp.Intersect, false); 398cb93a386Sopenharmony_ci canvas.drawColorInt(CanvasKit.ColorAsInt(200, 200, 200, 255), CanvasKit.BlendMode.SrcOver); 399cb93a386Sopenharmony_ci canvas.drawPath(path, paint); 400cb93a386Sopenharmony_ci 401cb93a386Sopenharmony_ci path.delete(); 402cb93a386Sopenharmony_ci paint.delete(); 403cb93a386Sopenharmony_ci }); 404cb93a386Sopenharmony_ci 405cb93a386Sopenharmony_ci // inspired by https://fiddle.skia.org/c/feb2a08bb09ede5309678d6a0ab3f981 406cb93a386Sopenharmony_ci gm('savelayer_rect_paint_canvas', (canvas) => { 407cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 408cb93a386Sopenharmony_ci const redPaint = new CanvasKit.Paint(); 409cb93a386Sopenharmony_ci redPaint.setColor(CanvasKit.RED); 410cb93a386Sopenharmony_ci const solidBluePaint = new CanvasKit.Paint(); 411cb93a386Sopenharmony_ci solidBluePaint.setColor(CanvasKit.BLUE); 412cb93a386Sopenharmony_ci 413cb93a386Sopenharmony_ci const thirtyBluePaint = new CanvasKit.Paint(); 414cb93a386Sopenharmony_ci thirtyBluePaint.setColor(CanvasKit.BLUE); 415cb93a386Sopenharmony_ci thirtyBluePaint.setAlphaf(0.3); 416cb93a386Sopenharmony_ci 417cb93a386Sopenharmony_ci const alpha = new CanvasKit.Paint(); 418cb93a386Sopenharmony_ci alpha.setAlphaf(0.3); 419cb93a386Sopenharmony_ci 420cb93a386Sopenharmony_ci // Draw 4 solid red rectangles on the 0th layer. 421cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(10, 10, 60, 60), redPaint); 422cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(150, 10, 200, 60), redPaint); 423cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(10, 70, 60, 120), redPaint); 424cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(150, 70, 200, 120), redPaint); 425cb93a386Sopenharmony_ci 426cb93a386Sopenharmony_ci // Draw 2 blue rectangles that overlap. One is solid, the other 427cb93a386Sopenharmony_ci // is 30% transparent. We should see purple from the right one, 428cb93a386Sopenharmony_ci // the left one overlaps the red because it is opaque. 429cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(30, 10, 80, 60), solidBluePaint); 430cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(170, 10, 220, 60), thirtyBluePaint); 431cb93a386Sopenharmony_ci 432cb93a386Sopenharmony_ci // Save a new layer. When the 1st layer gets merged onto the 433cb93a386Sopenharmony_ci // 0th layer (i.e. when restore() is called), it will use the provided 434cb93a386Sopenharmony_ci // paint to do so. The provided paint is set to have 30% opacity, but 435cb93a386Sopenharmony_ci // it could also have things set like blend modes or image filters. 436cb93a386Sopenharmony_ci // The rectangle is just a hint, so I've set it to be the area that 437cb93a386Sopenharmony_ci // we actually draw in before restore is called. It could also be omitted, 438cb93a386Sopenharmony_ci // see the test below. 439cb93a386Sopenharmony_ci canvas.saveLayer(alpha, CanvasKit.LTRBRect(10, 10, 220, 180)); 440cb93a386Sopenharmony_ci 441cb93a386Sopenharmony_ci // Draw the same blue overlapping rectangles as before. Notice in the 442cb93a386Sopenharmony_ci // final output, we have two different shades of purple instead of the 443cb93a386Sopenharmony_ci // solid blue overwriting the red. This proves the opacity was applied. 444cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(30, 70, 80, 120), solidBluePaint); 445cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(170, 70, 220, 120), thirtyBluePaint); 446cb93a386Sopenharmony_ci 447cb93a386Sopenharmony_ci // We draw two more sets of overlapping red and blue rectangles. Notice 448cb93a386Sopenharmony_ci // the solid blue overwrites the red. This proves that the opacity from 449cb93a386Sopenharmony_ci // the alpha paint isn't available when the drawing happens - it only 450cb93a386Sopenharmony_ci // matters when restore() is called. 451cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(10, 130, 60, 180), redPaint); 452cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(30, 130, 80, 180), solidBluePaint); 453cb93a386Sopenharmony_ci 454cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(150, 130, 200, 180), redPaint); 455cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(170, 130, 220, 180), thirtyBluePaint); 456cb93a386Sopenharmony_ci 457cb93a386Sopenharmony_ci canvas.restore(); 458cb93a386Sopenharmony_ci 459cb93a386Sopenharmony_ci redPaint.delete(); 460cb93a386Sopenharmony_ci solidBluePaint.delete(); 461cb93a386Sopenharmony_ci thirtyBluePaint.delete(); 462cb93a386Sopenharmony_ci alpha.delete(); 463cb93a386Sopenharmony_ci }); 464cb93a386Sopenharmony_ci 465cb93a386Sopenharmony_ci // identical to the test above, except the save layer only has the paint, not 466cb93a386Sopenharmony_ci // the rectangle. 467cb93a386Sopenharmony_ci gm('savelayer_paint_canvas', (canvas) => { 468cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 469cb93a386Sopenharmony_ci const redPaint = new CanvasKit.Paint(); 470cb93a386Sopenharmony_ci redPaint.setColor(CanvasKit.RED); 471cb93a386Sopenharmony_ci const solidBluePaint = new CanvasKit.Paint(); 472cb93a386Sopenharmony_ci solidBluePaint.setColor(CanvasKit.BLUE); 473cb93a386Sopenharmony_ci 474cb93a386Sopenharmony_ci const thirtyBluePaint = new CanvasKit.Paint(); 475cb93a386Sopenharmony_ci thirtyBluePaint.setColor(CanvasKit.BLUE); 476cb93a386Sopenharmony_ci thirtyBluePaint.setAlphaf(0.3); 477cb93a386Sopenharmony_ci 478cb93a386Sopenharmony_ci const alpha = new CanvasKit.Paint(); 479cb93a386Sopenharmony_ci alpha.setAlphaf(0.3); 480cb93a386Sopenharmony_ci 481cb93a386Sopenharmony_ci // Draw 4 solid red rectangles on the 0th layer. 482cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(10, 10, 60, 60), redPaint); 483cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(150, 10, 200, 60), redPaint); 484cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(10, 70, 60, 120), redPaint); 485cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(150, 70, 200, 120), redPaint); 486cb93a386Sopenharmony_ci 487cb93a386Sopenharmony_ci // Draw 2 blue rectangles that overlap. One is solid, the other 488cb93a386Sopenharmony_ci // is 30% transparent. We should see purple from the right one, 489cb93a386Sopenharmony_ci // the left one overlaps the red because it is opaque. 490cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(30, 10, 80, 60), solidBluePaint); 491cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(170, 10, 220, 60), thirtyBluePaint); 492cb93a386Sopenharmony_ci 493cb93a386Sopenharmony_ci // Save a new layer. When the 1st layer gets merged onto the 494cb93a386Sopenharmony_ci // 0th layer (i.e. when restore() is called), it will use the provided 495cb93a386Sopenharmony_ci // paint to do so. The provided paint is set to have 30% opacity, but 496cb93a386Sopenharmony_ci // it could also have things set like blend modes or image filters. 497cb93a386Sopenharmony_ci canvas.saveLayerPaint(alpha); 498cb93a386Sopenharmony_ci 499cb93a386Sopenharmony_ci // Draw the same blue overlapping rectangles as before. Notice in the 500cb93a386Sopenharmony_ci // final output, we have two different shades of purple instead of the 501cb93a386Sopenharmony_ci // solid blue overwriting the red. This proves the opacity was applied. 502cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(30, 70, 80, 120), solidBluePaint); 503cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(170, 70, 220, 120), thirtyBluePaint); 504cb93a386Sopenharmony_ci 505cb93a386Sopenharmony_ci // We draw two more sets of overlapping red and blue rectangles. Notice 506cb93a386Sopenharmony_ci // the solid blue overwrites the red. This proves that the opacity from 507cb93a386Sopenharmony_ci // the alpha paint isn't available when the drawing happens - it only 508cb93a386Sopenharmony_ci // matters when restore() is called. 509cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(10, 130, 60, 180), redPaint); 510cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(30, 130, 80, 180), solidBluePaint); 511cb93a386Sopenharmony_ci 512cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(150, 130, 200, 180), redPaint); 513cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(170, 130, 220, 180), thirtyBluePaint); 514cb93a386Sopenharmony_ci 515cb93a386Sopenharmony_ci canvas.restore(); 516cb93a386Sopenharmony_ci 517cb93a386Sopenharmony_ci redPaint.delete(); 518cb93a386Sopenharmony_ci solidBluePaint.delete(); 519cb93a386Sopenharmony_ci thirtyBluePaint.delete(); 520cb93a386Sopenharmony_ci alpha.delete(); 521cb93a386Sopenharmony_ci }); 522cb93a386Sopenharmony_ci 523cb93a386Sopenharmony_ci gm('savelayerrec_canvas', (canvas) => { 524cb93a386Sopenharmony_ci // Note: fiddle.skia.org quietly draws a white background before doing 525cb93a386Sopenharmony_ci // other things, which is noticed in cases like this where we use saveLayer 526cb93a386Sopenharmony_ci // with the rec struct. 527cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 528cb93a386Sopenharmony_ci canvas.scale(8, 8); 529cb93a386Sopenharmony_ci const redPaint = new CanvasKit.Paint(); 530cb93a386Sopenharmony_ci redPaint.setColor(CanvasKit.RED); 531cb93a386Sopenharmony_ci redPaint.setAntiAlias(true); 532cb93a386Sopenharmony_ci canvas.drawCircle(21, 21, 8, redPaint); 533cb93a386Sopenharmony_ci 534cb93a386Sopenharmony_ci const bluePaint = new CanvasKit.Paint(); 535cb93a386Sopenharmony_ci bluePaint.setColor(CanvasKit.BLUE); 536cb93a386Sopenharmony_ci canvas.drawCircle(31, 21, 8, bluePaint); 537cb93a386Sopenharmony_ci 538cb93a386Sopenharmony_ci const blurIF = CanvasKit.ImageFilter.MakeBlur(8, 0.2, CanvasKit.TileMode.Decal, null); 539cb93a386Sopenharmony_ci 540cb93a386Sopenharmony_ci const count = canvas.saveLayer(null, null, blurIF, 0); 541cb93a386Sopenharmony_ci expect(count).toEqual(1); 542cb93a386Sopenharmony_ci canvas.scale(1/4, 1/4); 543cb93a386Sopenharmony_ci canvas.drawCircle(125, 85, 8, redPaint); 544cb93a386Sopenharmony_ci canvas.restore(); 545cb93a386Sopenharmony_ci 546cb93a386Sopenharmony_ci blurIF.delete(); 547cb93a386Sopenharmony_ci redPaint.delete(); 548cb93a386Sopenharmony_ci bluePaint.delete(); 549cb93a386Sopenharmony_ci }); 550cb93a386Sopenharmony_ci 551cb93a386Sopenharmony_ci gm('drawpoints_canvas', (canvas) => { 552cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 553cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 554cb93a386Sopenharmony_ci paint.setAntiAlias(true); 555cb93a386Sopenharmony_ci paint.setStyle(CanvasKit.PaintStyle.Stroke); 556cb93a386Sopenharmony_ci paint.setStrokeWidth(10); 557cb93a386Sopenharmony_ci paint.setColor(CanvasKit.Color(153, 204, 162, 0.82)); 558cb93a386Sopenharmony_ci 559cb93a386Sopenharmony_ci const points = [32, 16, 48, 48, 16, 32]; 560cb93a386Sopenharmony_ci 561cb93a386Sopenharmony_ci const caps = [CanvasKit.StrokeCap.Round, CanvasKit.StrokeCap.Square, 562cb93a386Sopenharmony_ci CanvasKit.StrokeCap.Butt]; 563cb93a386Sopenharmony_ci const joins = [CanvasKit.StrokeJoin.Round, CanvasKit.StrokeJoin.Miter, 564cb93a386Sopenharmony_ci CanvasKit.StrokeJoin.Bevel]; 565cb93a386Sopenharmony_ci const modes = [CanvasKit.PointMode.Points, CanvasKit.PointMode.Lines, 566cb93a386Sopenharmony_ci CanvasKit.PointMode.Polygon]; 567cb93a386Sopenharmony_ci 568cb93a386Sopenharmony_ci for (let i = 0; i < caps.length; i++) { 569cb93a386Sopenharmony_ci paint.setStrokeCap(caps[i]); 570cb93a386Sopenharmony_ci paint.setStrokeJoin(joins[i]); 571cb93a386Sopenharmony_ci 572cb93a386Sopenharmony_ci for (const m of modes) { 573cb93a386Sopenharmony_ci canvas.drawPoints(m, points, paint); 574cb93a386Sopenharmony_ci canvas.translate(64, 0); 575cb93a386Sopenharmony_ci } 576cb93a386Sopenharmony_ci // Try with the malloc approach. Note that the drawPoints 577cb93a386Sopenharmony_ci // will free the pointer when done. 578cb93a386Sopenharmony_ci const mPointsObj = CanvasKit.Malloc(Float32Array, 3*2); 579cb93a386Sopenharmony_ci const mPoints = mPointsObj.toTypedArray(); 580cb93a386Sopenharmony_ci mPoints.set([32, 16, 48, 48, 16, 32]); 581cb93a386Sopenharmony_ci 582cb93a386Sopenharmony_ci // The obj from Malloc can be passed in instead of the typed array. 583cb93a386Sopenharmony_ci canvas.drawPoints(CanvasKit.PointMode.Polygon, mPointsObj, paint); 584cb93a386Sopenharmony_ci canvas.translate(-192, 64); 585cb93a386Sopenharmony_ci CanvasKit.Free(mPointsObj); 586cb93a386Sopenharmony_ci } 587cb93a386Sopenharmony_ci 588cb93a386Sopenharmony_ci paint.delete(); 589cb93a386Sopenharmony_ci }); 590cb93a386Sopenharmony_ci 591cb93a386Sopenharmony_ci gm('drawPoints in different modes', (canvas) => { 592cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 593cb93a386Sopenharmony_ci // From https://bugs.chromium.org/p/skia/issues/detail?id=11012 594cb93a386Sopenharmony_ci const boxPaint = new CanvasKit.Paint(); 595cb93a386Sopenharmony_ci boxPaint.setStyle(CanvasKit.PaintStyle.Stroke); 596cb93a386Sopenharmony_ci boxPaint.setStrokeWidth(1); 597cb93a386Sopenharmony_ci 598cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 599cb93a386Sopenharmony_ci paint.setStyle(CanvasKit.PaintStyle.Stroke); 600cb93a386Sopenharmony_ci paint.setStrokeWidth(5); 601cb93a386Sopenharmony_ci paint.setStrokeCap(CanvasKit.StrokeCap.Round); 602cb93a386Sopenharmony_ci paint.setColorInt(0xFF0000FF); // Blue 603cb93a386Sopenharmony_ci paint.setAntiAlias(true); 604cb93a386Sopenharmony_ci 605cb93a386Sopenharmony_ci const points = Float32Array.of(40, 40, 80, 40, 120, 80, 160, 80); 606cb93a386Sopenharmony_ci 607cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(35, 35, 165, 85), boxPaint); 608cb93a386Sopenharmony_ci canvas.drawPoints(CanvasKit.PointMode.Points, points, paint); 609cb93a386Sopenharmony_ci 610cb93a386Sopenharmony_ci canvas.translate(0, 50); 611cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(35, 35, 165, 85), boxPaint); 612cb93a386Sopenharmony_ci canvas.drawPoints(CanvasKit.PointMode.Lines, points, paint); 613cb93a386Sopenharmony_ci 614cb93a386Sopenharmony_ci canvas.translate(0, 50); 615cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(35, 35, 165, 85), boxPaint); 616cb93a386Sopenharmony_ci canvas.drawPoints(CanvasKit.PointMode.Polygon, points, paint); 617cb93a386Sopenharmony_ci 618cb93a386Sopenharmony_ci // The control version using drawPath 619cb93a386Sopenharmony_ci canvas.translate(0, 50); 620cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(35, 35, 165, 85), boxPaint); 621cb93a386Sopenharmony_ci const path = new CanvasKit.Path(); 622cb93a386Sopenharmony_ci path.moveTo(40, 40); 623cb93a386Sopenharmony_ci path.lineTo(80, 40); 624cb93a386Sopenharmony_ci path.lineTo(120, 80); 625cb93a386Sopenharmony_ci path.lineTo(160, 80); 626cb93a386Sopenharmony_ci paint.setColorInt(0xFFFF0000); // RED 627cb93a386Sopenharmony_ci canvas.drawPath(path, paint); 628cb93a386Sopenharmony_ci 629cb93a386Sopenharmony_ci paint.delete(); 630cb93a386Sopenharmony_ci path.delete(); 631cb93a386Sopenharmony_ci boxPaint.delete(); 632cb93a386Sopenharmony_ci }); 633cb93a386Sopenharmony_ci 634cb93a386Sopenharmony_ci gm('drawImageNine_canvas', (canvas, fetchedByteBuffers) => { 635cb93a386Sopenharmony_ci const img = CanvasKit.MakeImageFromEncoded(fetchedByteBuffers[0]); 636cb93a386Sopenharmony_ci expect(img).toBeTruthy(); 637cb93a386Sopenharmony_ci 638cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 639cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 640cb93a386Sopenharmony_ci 641cb93a386Sopenharmony_ci canvas.drawImageNine(img, CanvasKit.LTRBiRect(40, 40, 400, 300), 642cb93a386Sopenharmony_ci CanvasKit.LTRBRect(5, 5, 300, 650), CanvasKit.FilterMode.Nearest, paint); 643cb93a386Sopenharmony_ci paint.delete(); 644cb93a386Sopenharmony_ci img.delete(); 645cb93a386Sopenharmony_ci }, '/assets/mandrill_512.png'); 646cb93a386Sopenharmony_ci 647cb93a386Sopenharmony_ci // This should be a nice, clear image. 648cb93a386Sopenharmony_ci gm('makeImageShaderCubic_canvas', (canvas, fetchedByteBuffers) => { 649cb93a386Sopenharmony_ci const img = CanvasKit.MakeImageFromEncoded(fetchedByteBuffers[0]); 650cb93a386Sopenharmony_ci expect(img).toBeTruthy(); 651cb93a386Sopenharmony_ci 652cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 653cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 654cb93a386Sopenharmony_ci const shader = img.makeShaderCubic(CanvasKit.TileMode.Decal, CanvasKit.TileMode.Clamp, 655cb93a386Sopenharmony_ci 1/3 /*B*/, 1/3 /*C*/, 656cb93a386Sopenharmony_ci CanvasKit.Matrix.rotated(0.1)); 657cb93a386Sopenharmony_ci paint.setShader(shader); 658cb93a386Sopenharmony_ci 659cb93a386Sopenharmony_ci canvas.drawPaint(paint); 660cb93a386Sopenharmony_ci paint.delete(); 661cb93a386Sopenharmony_ci shader.delete(); 662cb93a386Sopenharmony_ci img.delete(); 663cb93a386Sopenharmony_ci }, '/assets/mandrill_512.png'); 664cb93a386Sopenharmony_ci 665cb93a386Sopenharmony_ci // This will look more blocky than the version above. 666cb93a386Sopenharmony_ci gm('makeImageShaderOptions_canvas', (canvas, fetchedByteBuffers) => { 667cb93a386Sopenharmony_ci const img = CanvasKit.MakeImageFromEncoded(fetchedByteBuffers[0]); 668cb93a386Sopenharmony_ci expect(img).toBeTruthy(); 669cb93a386Sopenharmony_ci const imgWithMipMap = img.makeCopyWithDefaultMipmaps(); 670cb93a386Sopenharmony_ci 671cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 672cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 673cb93a386Sopenharmony_ci const shader = imgWithMipMap.makeShaderOptions(CanvasKit.TileMode.Decal, 674cb93a386Sopenharmony_ci CanvasKit.TileMode.Clamp, 675cb93a386Sopenharmony_ci CanvasKit.FilterMode.Nearest, 676cb93a386Sopenharmony_ci CanvasKit.MipmapMode.Linear, 677cb93a386Sopenharmony_ci CanvasKit.Matrix.rotated(0.1)); 678cb93a386Sopenharmony_ci paint.setShader(shader); 679cb93a386Sopenharmony_ci 680cb93a386Sopenharmony_ci canvas.drawPaint(paint); 681cb93a386Sopenharmony_ci paint.delete(); 682cb93a386Sopenharmony_ci shader.delete(); 683cb93a386Sopenharmony_ci img.delete(); 684cb93a386Sopenharmony_ci imgWithMipMap.delete(); 685cb93a386Sopenharmony_ci }, '/assets/mandrill_512.png'); 686cb93a386Sopenharmony_ci 687cb93a386Sopenharmony_ci gm('drawvertices_canvas', (canvas) => { 688cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 689cb93a386Sopenharmony_ci paint.setAntiAlias(true); 690cb93a386Sopenharmony_ci 691cb93a386Sopenharmony_ci const points = [0, 0, 250, 0, 100, 100, 0, 250]; 692cb93a386Sopenharmony_ci // 2d float color array 693cb93a386Sopenharmony_ci const colors = [CanvasKit.RED, CanvasKit.BLUE, 694cb93a386Sopenharmony_ci CanvasKit.YELLOW, CanvasKit.CYAN]; 695cb93a386Sopenharmony_ci const vertices = CanvasKit.MakeVertices(CanvasKit.VertexMode.TriangleFan, 696cb93a386Sopenharmony_ci points, null /*textureCoordinates*/, colors, false /*isVolatile*/); 697cb93a386Sopenharmony_ci 698cb93a386Sopenharmony_ci const bounds = vertices.bounds(); 699cb93a386Sopenharmony_ci expect(bounds).toEqual(CanvasKit.LTRBRect(0, 0, 250, 250)); 700cb93a386Sopenharmony_ci 701cb93a386Sopenharmony_ci canvas.drawVertices(vertices, CanvasKit.BlendMode.Src, paint); 702cb93a386Sopenharmony_ci vertices.delete(); 703cb93a386Sopenharmony_ci paint.delete(); 704cb93a386Sopenharmony_ci }); 705cb93a386Sopenharmony_ci 706cb93a386Sopenharmony_ci gm('drawvertices_canvas_flat_floats', (canvas) => { 707cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 708cb93a386Sopenharmony_ci paint.setAntiAlias(true); 709cb93a386Sopenharmony_ci 710cb93a386Sopenharmony_ci const points = [0, 0, 250, 0, 100, 100, 0, 250]; 711cb93a386Sopenharmony_ci // 1d float color array 712cb93a386Sopenharmony_ci const colors = Float32Array.of(...CanvasKit.RED, ...CanvasKit.BLUE, 713cb93a386Sopenharmony_ci ...CanvasKit.YELLOW, ...CanvasKit.CYAN); 714cb93a386Sopenharmony_ci const vertices = CanvasKit.MakeVertices(CanvasKit.VertexMode.TriangleFan, 715cb93a386Sopenharmony_ci points, null /*textureCoordinates*/, colors, false /*isVolatile*/); 716cb93a386Sopenharmony_ci 717cb93a386Sopenharmony_ci const bounds = vertices.bounds(); 718cb93a386Sopenharmony_ci expect(bounds).toEqual(CanvasKit.LTRBRect(0, 0, 250, 250)); 719cb93a386Sopenharmony_ci 720cb93a386Sopenharmony_ci canvas.drawVertices(vertices, CanvasKit.BlendMode.Src, paint); 721cb93a386Sopenharmony_ci vertices.delete(); 722cb93a386Sopenharmony_ci paint.delete(); 723cb93a386Sopenharmony_ci }); 724cb93a386Sopenharmony_ci 725cb93a386Sopenharmony_ci gm('drawvertices_texture_canvas', (canvas, fetchedByteBuffers) => { 726cb93a386Sopenharmony_ci const img = CanvasKit.MakeImageFromEncoded(fetchedByteBuffers[0]); 727cb93a386Sopenharmony_ci 728cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 729cb93a386Sopenharmony_ci paint.setAntiAlias(true); 730cb93a386Sopenharmony_ci 731cb93a386Sopenharmony_ci const points = [ 732cb93a386Sopenharmony_ci 70, 170, 40, 90, 130, 150, 100, 50, 733cb93a386Sopenharmony_ci 225, 150, 225, 60, 310, 180, 330, 100, 734cb93a386Sopenharmony_ci ]; 735cb93a386Sopenharmony_ci const textureCoordinates = [ 736cb93a386Sopenharmony_ci 0, 240, 0, 0, 80, 240, 80, 0, 737cb93a386Sopenharmony_ci 160, 240, 160, 0, 240, 240, 240, 0, 738cb93a386Sopenharmony_ci ]; 739cb93a386Sopenharmony_ci const vertices = CanvasKit.MakeVertices(CanvasKit.VertexMode.TrianglesStrip, 740cb93a386Sopenharmony_ci points, textureCoordinates, null /* colors */, false /*isVolatile*/); 741cb93a386Sopenharmony_ci 742cb93a386Sopenharmony_ci const shader = img.makeShaderCubic(CanvasKit.TileMode.Repeat, CanvasKit.TileMode.Mirror, 743cb93a386Sopenharmony_ci 1/3 /*B*/, 1/3 /*C*/,); 744cb93a386Sopenharmony_ci paint.setShader(shader); 745cb93a386Sopenharmony_ci canvas.drawVertices(vertices, CanvasKit.BlendMode.Src, paint); 746cb93a386Sopenharmony_ci 747cb93a386Sopenharmony_ci shader.delete(); 748cb93a386Sopenharmony_ci vertices.delete(); 749cb93a386Sopenharmony_ci paint.delete(); 750cb93a386Sopenharmony_ci img.delete(); 751cb93a386Sopenharmony_ci }, '/assets/brickwork-texture.jpg'); 752cb93a386Sopenharmony_ci 753cb93a386Sopenharmony_ci it('can change the 3x3 matrix on the canvas and read it back', () => { 754cb93a386Sopenharmony_ci const canvas = new CanvasKit.Canvas(); 755cb93a386Sopenharmony_ci 756cb93a386Sopenharmony_ci let matr = canvas.getTotalMatrix(); 757cb93a386Sopenharmony_ci expect(matr).toEqual(CanvasKit.Matrix.identity()); 758cb93a386Sopenharmony_ci 759cb93a386Sopenharmony_ci // This fills the internal _scratch4x4MatrixPtr with garbage (aka sentinel) values to 760cb93a386Sopenharmony_ci // make sure the 3x3 matrix properly sets these to 0 when it uses the same buffer. 761cb93a386Sopenharmony_ci canvas.save(); 762cb93a386Sopenharmony_ci const garbageMatrix = new Float32Array(16); 763cb93a386Sopenharmony_ci garbageMatrix.fill(-3); 764cb93a386Sopenharmony_ci canvas.concat(garbageMatrix); 765cb93a386Sopenharmony_ci canvas.restore(); 766cb93a386Sopenharmony_ci 767cb93a386Sopenharmony_ci canvas.concat(CanvasKit.Matrix.rotated(Math.PI/4)); 768cb93a386Sopenharmony_ci const d = new DOMMatrix().translate(20, 10); 769cb93a386Sopenharmony_ci canvas.concat(d); 770cb93a386Sopenharmony_ci 771cb93a386Sopenharmony_ci matr = canvas.getTotalMatrix(); 772cb93a386Sopenharmony_ci const expected = CanvasKit.Matrix.multiply( 773cb93a386Sopenharmony_ci CanvasKit.Matrix.rotated(Math.PI/4), 774cb93a386Sopenharmony_ci CanvasKit.Matrix.translated(20, 10) 775cb93a386Sopenharmony_ci ); 776cb93a386Sopenharmony_ci expect3x3MatricesToMatch(expected, matr); 777cb93a386Sopenharmony_ci 778cb93a386Sopenharmony_ci // The 3x3 should be expanded into a 4x4, with 0s in the 3rd row and column. 779cb93a386Sopenharmony_ci matr = canvas.getLocalToDevice(); 780cb93a386Sopenharmony_ci expect4x4MatricesToMatch([ 781cb93a386Sopenharmony_ci 0.707106, -0.707106, 0, 7.071067, 782cb93a386Sopenharmony_ci 0.707106, 0.707106, 0, 21.213203, 783cb93a386Sopenharmony_ci 0 , 0 , 0, 0 , 784cb93a386Sopenharmony_ci 0 , 0 , 0, 1 ], matr); 785cb93a386Sopenharmony_ci }); 786cb93a386Sopenharmony_ci 787cb93a386Sopenharmony_ci it('can accept a 3x2 matrix', () => { 788cb93a386Sopenharmony_ci const canvas = new CanvasKit.Canvas(); 789cb93a386Sopenharmony_ci 790cb93a386Sopenharmony_ci let matr = canvas.getTotalMatrix(); 791cb93a386Sopenharmony_ci expect(matr).toEqual(CanvasKit.Matrix.identity()); 792cb93a386Sopenharmony_ci 793cb93a386Sopenharmony_ci // This fills the internal _scratch4x4MatrixPtr with garbage (aka sentinel) values to 794cb93a386Sopenharmony_ci // make sure the 3x2 matrix properly sets these to 0 when it uses the same buffer. 795cb93a386Sopenharmony_ci canvas.save(); 796cb93a386Sopenharmony_ci const garbageMatrix = new Float32Array(16); 797cb93a386Sopenharmony_ci garbageMatrix.fill(-3); 798cb93a386Sopenharmony_ci canvas.concat(garbageMatrix); 799cb93a386Sopenharmony_ci canvas.restore(); 800cb93a386Sopenharmony_ci 801cb93a386Sopenharmony_ci canvas.concat([1.4, -0.2, 12, 802cb93a386Sopenharmony_ci 0.2, 1.4, 24]); 803cb93a386Sopenharmony_ci 804cb93a386Sopenharmony_ci matr = canvas.getTotalMatrix(); 805cb93a386Sopenharmony_ci const expected = [1.4, -0.2, 12, 806cb93a386Sopenharmony_ci 0.2, 1.4, 24, 807cb93a386Sopenharmony_ci 0, 0, 1]; 808cb93a386Sopenharmony_ci expect3x3MatricesToMatch(expected, matr); 809cb93a386Sopenharmony_ci 810cb93a386Sopenharmony_ci // The 3x2 should be expanded into a 4x4, with 0s in the 3rd row and column 811cb93a386Sopenharmony_ci // and the perspective filled in. 812cb93a386Sopenharmony_ci matr = canvas.getLocalToDevice(); 813cb93a386Sopenharmony_ci expect4x4MatricesToMatch([ 814cb93a386Sopenharmony_ci 1.4, -0.2, 0, 12, 815cb93a386Sopenharmony_ci 0.2, 1.4, 0, 24, 816cb93a386Sopenharmony_ci 0 , 0 , 0, 0, 817cb93a386Sopenharmony_ci 0 , 0 , 0, 1], matr); 818cb93a386Sopenharmony_ci }); 819cb93a386Sopenharmony_ci 820cb93a386Sopenharmony_ci it('can mark a CTM and retrieve it', () => { 821cb93a386Sopenharmony_ci const canvas = new CanvasKit.Canvas(); 822cb93a386Sopenharmony_ci 823cb93a386Sopenharmony_ci canvas.concat(CanvasKit.M44.rotated([0, 1, 0], Math.PI/4)); 824cb93a386Sopenharmony_ci canvas.concat(CanvasKit.M44.rotated([1, 0, 1], Math.PI/8)); 825cb93a386Sopenharmony_ci canvas.markCTM('krispykreme'); 826cb93a386Sopenharmony_ci 827cb93a386Sopenharmony_ci const expected = CanvasKit.M44.multiply( 828cb93a386Sopenharmony_ci CanvasKit.M44.rotated([0, 1, 0], Math.PI/4), 829cb93a386Sopenharmony_ci CanvasKit.M44.rotated([1, 0, 1], Math.PI/8), 830cb93a386Sopenharmony_ci ); 831cb93a386Sopenharmony_ci 832cb93a386Sopenharmony_ci expect4x4MatricesToMatch(expected, canvas.findMarkedCTM('krispykreme')); 833cb93a386Sopenharmony_ci }); 834cb93a386Sopenharmony_ci 835cb93a386Sopenharmony_ci it('returns null for an invalid CTM marker', () => { 836cb93a386Sopenharmony_ci const canvas = new CanvasKit.Canvas(); 837cb93a386Sopenharmony_ci expect(canvas.findMarkedCTM('dunkindonuts')).toBeNull(); 838cb93a386Sopenharmony_ci }); 839cb93a386Sopenharmony_ci 840cb93a386Sopenharmony_ci it('can change the 4x4 matrix on the canvas and read it back', () => { 841cb93a386Sopenharmony_ci const canvas = new CanvasKit.Canvas(); 842cb93a386Sopenharmony_ci 843cb93a386Sopenharmony_ci let matr = canvas.getLocalToDevice(); 844cb93a386Sopenharmony_ci expect(matr).toEqual(CanvasKit.M44.identity()); 845cb93a386Sopenharmony_ci 846cb93a386Sopenharmony_ci canvas.concat(CanvasKit.M44.rotated([0, 1, 0], Math.PI/4)); 847cb93a386Sopenharmony_ci canvas.concat(CanvasKit.M44.rotated([1, 0, 1], Math.PI/8)); 848cb93a386Sopenharmony_ci 849cb93a386Sopenharmony_ci const expected = CanvasKit.M44.multiply( 850cb93a386Sopenharmony_ci CanvasKit.M44.rotated([0, 1, 0], Math.PI/4), 851cb93a386Sopenharmony_ci CanvasKit.M44.rotated([1, 0, 1], Math.PI/8), 852cb93a386Sopenharmony_ci ); 853cb93a386Sopenharmony_ci 854cb93a386Sopenharmony_ci expect4x4MatricesToMatch(expected, canvas.getLocalToDevice()); 855cb93a386Sopenharmony_ci // TODO(kjlubick) add test for DOMMatrix 856cb93a386Sopenharmony_ci // TODO(nifong) add more involved test for camera-related math. 857cb93a386Sopenharmony_ci }); 858cb93a386Sopenharmony_ci 859cb93a386Sopenharmony_ci gm('concat_with4x4_canvas', (canvas) => { 860cb93a386Sopenharmony_ci const path = starPath(CanvasKit, CANVAS_WIDTH/2, CANVAS_HEIGHT/2); 861cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 862cb93a386Sopenharmony_ci paint.setAntiAlias(true); 863cb93a386Sopenharmony_ci canvas.clear(CanvasKit.WHITE); 864cb93a386Sopenharmony_ci 865cb93a386Sopenharmony_ci // Rotate it a bit on all 3 major axis, centered on the screen. 866cb93a386Sopenharmony_ci // To play with rotations, see https://jsfiddle.skia.org/canvaskit/0525300405796aa87c3b84cc0d5748516fca0045d7d6d9c7840710ab771edcd4 867cb93a386Sopenharmony_ci const turn = CanvasKit.M44.multiply( 868cb93a386Sopenharmony_ci CanvasKit.M44.translated([CANVAS_WIDTH/2, 0, 0]), 869cb93a386Sopenharmony_ci CanvasKit.M44.rotated([1, 0, 0], Math.PI/3), 870cb93a386Sopenharmony_ci CanvasKit.M44.rotated([0, 1, 0], Math.PI/4), 871cb93a386Sopenharmony_ci CanvasKit.M44.rotated([0, 0, 1], Math.PI/16), 872cb93a386Sopenharmony_ci CanvasKit.M44.translated([-CANVAS_WIDTH/2, 0, 0]), 873cb93a386Sopenharmony_ci ); 874cb93a386Sopenharmony_ci canvas.concat(turn); 875cb93a386Sopenharmony_ci 876cb93a386Sopenharmony_ci // Draw some stripes to help the eye detect the turn 877cb93a386Sopenharmony_ci const stripeWidth = 10; 878cb93a386Sopenharmony_ci paint.setColor(CanvasKit.BLACK); 879cb93a386Sopenharmony_ci for (let i = 0; i < CANVAS_WIDTH; i += 2*stripeWidth) { 880cb93a386Sopenharmony_ci canvas.drawRect(CanvasKit.LTRBRect(i, 0, i + stripeWidth, CANVAS_HEIGHT), paint); 881cb93a386Sopenharmony_ci } 882cb93a386Sopenharmony_ci 883cb93a386Sopenharmony_ci paint.setColor(CanvasKit.YELLOW); 884cb93a386Sopenharmony_ci canvas.drawPath(path, paint); 885cb93a386Sopenharmony_ci paint.delete(); 886cb93a386Sopenharmony_ci path.delete(); 887cb93a386Sopenharmony_ci }); 888cb93a386Sopenharmony_ci 889cb93a386Sopenharmony_ci gm('particles_canvas', (canvas) => { 890cb93a386Sopenharmony_ci const curveParticles = { 891cb93a386Sopenharmony_ci 'MaxCount': 1000, 892cb93a386Sopenharmony_ci 'Drawable': { 893cb93a386Sopenharmony_ci 'Type': 'SkCircleDrawable', 894cb93a386Sopenharmony_ci 'Radius': 2 895cb93a386Sopenharmony_ci }, 896cb93a386Sopenharmony_ci 'Code': [ 897cb93a386Sopenharmony_ci `void effectSpawn(inout Effect effect) { 898cb93a386Sopenharmony_ci effect.rate = 200; 899cb93a386Sopenharmony_ci effect.color = float4(1, 0, 0, 1); 900cb93a386Sopenharmony_ci } 901cb93a386Sopenharmony_ci void spawn(inout Particle p) { 902cb93a386Sopenharmony_ci p.lifetime = 3 + rand(p.seed); 903cb93a386Sopenharmony_ci p.vel.y = -50; 904cb93a386Sopenharmony_ci } 905cb93a386Sopenharmony_ci 906cb93a386Sopenharmony_ci void update(inout Particle p) { 907cb93a386Sopenharmony_ci float w = mix(15, 3, p.age); 908cb93a386Sopenharmony_ci p.pos.x = sin(radians(p.age * 320)) * mix(25, 10, p.age) + mix(-w, w, rand(p.seed)); 909cb93a386Sopenharmony_ci if (rand(p.seed) < 0.5) { p.pos.x = -p.pos.x; } 910cb93a386Sopenharmony_ci 911cb93a386Sopenharmony_ci p.color.g = (mix(75, 220, p.age) + mix(-30, 30, rand(p.seed))) / 255; 912cb93a386Sopenharmony_ci }` 913cb93a386Sopenharmony_ci ], 914cb93a386Sopenharmony_ci 'Bindings': [] 915cb93a386Sopenharmony_ci }; 916cb93a386Sopenharmony_ci 917cb93a386Sopenharmony_ci const particles = CanvasKit.MakeParticles(JSON.stringify(curveParticles)); 918cb93a386Sopenharmony_ci particles.start(0, true); 919cb93a386Sopenharmony_ci particles.setPosition([0, 0]); 920cb93a386Sopenharmony_ci 921cb93a386Sopenharmony_ci const paint = new CanvasKit.Paint(); 922cb93a386Sopenharmony_ci paint.setAntiAlias(true); 923cb93a386Sopenharmony_ci paint.setColor(CanvasKit.WHITE); 924cb93a386Sopenharmony_ci const font = new CanvasKit.Font(null, 12); 925cb93a386Sopenharmony_ci 926cb93a386Sopenharmony_ci canvas.clear(CanvasKit.BLACK); 927cb93a386Sopenharmony_ci 928cb93a386Sopenharmony_ci // Draw a 5x5 set of different times in the particle system 929cb93a386Sopenharmony_ci // like a filmstrip of motion of particles. 930cb93a386Sopenharmony_ci const LEFT_MARGIN = 90; 931cb93a386Sopenharmony_ci const TOP_MARGIN = 100; 932cb93a386Sopenharmony_ci for (let row = 0; row < 5; row++) { 933cb93a386Sopenharmony_ci for (let column = 0; column < 5; column++) { 934cb93a386Sopenharmony_ci canvas.save(); 935cb93a386Sopenharmony_ci canvas.translate(LEFT_MARGIN + column*100, TOP_MARGIN + row*100); 936cb93a386Sopenharmony_ci 937cb93a386Sopenharmony_ci // Time moves in row-major order in increments of 0.02. 938cb93a386Sopenharmony_ci const particleTime = row/10 + column/50; 939cb93a386Sopenharmony_ci 940cb93a386Sopenharmony_ci canvas.drawText('time ' + particleTime.toFixed(2), -30, 20, paint, font); 941cb93a386Sopenharmony_ci particles.update(particleTime); 942cb93a386Sopenharmony_ci 943cb93a386Sopenharmony_ci particles.draw(canvas); 944cb93a386Sopenharmony_ci canvas.restore(); 945cb93a386Sopenharmony_ci } 946cb93a386Sopenharmony_ci } 947cb93a386Sopenharmony_ci }); 948cb93a386Sopenharmony_ci}); 949cb93a386Sopenharmony_ci 950cb93a386Sopenharmony_ciconst expect3x3MatricesToMatch = (expected, actual) => { 951cb93a386Sopenharmony_ci expect(expected.length).toEqual(9); 952cb93a386Sopenharmony_ci expect(actual.length).toEqual(9); 953cb93a386Sopenharmony_ci for (let i = 0; i < expected.length; i++) { 954cb93a386Sopenharmony_ci expect(expected[i]).toBeCloseTo(actual[i], 5); 955cb93a386Sopenharmony_ci } 956cb93a386Sopenharmony_ci}; 957cb93a386Sopenharmony_ci 958cb93a386Sopenharmony_ciconst expect4x4MatricesToMatch = (expected, actual) => { 959cb93a386Sopenharmony_ci expect(expected.length).toEqual(16); 960cb93a386Sopenharmony_ci expect(actual.length).toEqual(16); 961cb93a386Sopenharmony_ci for (let i = 0; i < expected.length; i++) { 962cb93a386Sopenharmony_ci expect(expected[i]).toBeCloseTo(actual[i], 5); 963cb93a386Sopenharmony_ci } 964cb93a386Sopenharmony_ci}; 965