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