xref: /aosp_15_r20/external/skia/tools/perf-canvaskit-puppeteer/canvas_perf.js (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Workerconst onlytests = [];
2*c8dee2aaSAndroid Build Coastguard Workerconst tests = [];
3*c8dee2aaSAndroid Build Coastguard Worker// In all tests, the canvas is 600 by 600 px.
4*c8dee2aaSAndroid Build Coastguard Worker// tests should NOT call ctx.surface.flush()
5*c8dee2aaSAndroid Build Coastguard Worker// flush is done by benchmark.js
6*c8dee2aaSAndroid Build Coastguard Worker
7*c8dee2aaSAndroid Build Coastguard Workerfunction randomColorTwo(CanvasKit, i, j) {
8*c8dee2aaSAndroid Build Coastguard Worker    c = [1, 1, 1, 1];
9*c8dee2aaSAndroid Build Coastguard Worker    c[i] = Math.random();
10*c8dee2aaSAndroid Build Coastguard Worker    c[j] = Math.random();
11*c8dee2aaSAndroid Build Coastguard Worker    return CanvasKit.Color4f(...c);
12*c8dee2aaSAndroid Build Coastguard Worker}
13*c8dee2aaSAndroid Build Coastguard Worker
14*c8dee2aaSAndroid Build Coastguard Workerfunction randomColor(CanvasKit) {
15*c8dee2aaSAndroid Build Coastguard Worker    return CanvasKit.Color4f(Math.random(), Math.random(), Math.random(), Math.random());
16*c8dee2aaSAndroid Build Coastguard Worker}
17*c8dee2aaSAndroid Build Coastguard Worker
18*c8dee2aaSAndroid Build Coastguard Workerfunction starPath(CanvasKit, X=128, Y=128, R=116) {
19*c8dee2aaSAndroid Build Coastguard Worker    const p = new CanvasKit.Path();
20*c8dee2aaSAndroid Build Coastguard Worker    p.moveTo(X + R, Y);
21*c8dee2aaSAndroid Build Coastguard Worker    for (let i = 1; i < 8; i++) {
22*c8dee2aaSAndroid Build Coastguard Worker      let a = 2.6927937 * i;
23*c8dee2aaSAndroid Build Coastguard Worker      p.lineTo(X + R * Math.cos(a), Y + R * Math.sin(a));
24*c8dee2aaSAndroid Build Coastguard Worker    }
25*c8dee2aaSAndroid Build Coastguard Worker    p.close();
26*c8dee2aaSAndroid Build Coastguard Worker    return p;
27*c8dee2aaSAndroid Build Coastguard Worker}
28*c8dee2aaSAndroid Build Coastguard Worker
29*c8dee2aaSAndroid Build Coastguard Workertests.push({
30*c8dee2aaSAndroid Build Coastguard Worker    description: 'Draw 10K colored rect clips',
31*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
32*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas = ctx.surface.getCanvas();
33*c8dee2aaSAndroid Build Coastguard Worker    },
34*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
35*c8dee2aaSAndroid Build Coastguard Worker        // Draw a lot of colored squares.
36*c8dee2aaSAndroid Build Coastguard Worker        for (let i=0; i<10000; i++) {
37*c8dee2aaSAndroid Build Coastguard Worker            const x = Math.random()*550;
38*c8dee2aaSAndroid Build Coastguard Worker            const y = Math.random()*550;
39*c8dee2aaSAndroid Build Coastguard Worker            ctx.canvas.save();
40*c8dee2aaSAndroid Build Coastguard Worker            ctx.canvas.clipRect(CanvasKit.LTRBRect(x, y, x+50, y+50),
41*c8dee2aaSAndroid Build Coastguard Worker                                CanvasKit.ClipOp.Intersect, false);
42*c8dee2aaSAndroid Build Coastguard Worker            ctx.canvas.drawColor(randomColorTwo(CanvasKit, 0, 1), CanvasKit.BlendMode.SrcOver);
43*c8dee2aaSAndroid Build Coastguard Worker            ctx.canvas.restore();
44*c8dee2aaSAndroid Build Coastguard Worker        }
45*c8dee2aaSAndroid Build Coastguard Worker    },
46*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
47*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'canvas_drawColor',
48*c8dee2aaSAndroid Build Coastguard Worker});
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Workertests.push({
51*c8dee2aaSAndroid Build Coastguard Worker    description: 'Draw 10K colored ellipses',
52*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
53*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas = ctx.surface.getCanvas();
54*c8dee2aaSAndroid Build Coastguard Worker
55*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint = new CanvasKit.Paint();
56*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setAntiAlias(true);
57*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setStyle(CanvasKit.PaintStyle.Fill);
58*c8dee2aaSAndroid Build Coastguard Worker    },
59*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
60*c8dee2aaSAndroid Build Coastguard Worker        for (let i=0; i<10000; i++) {
61*c8dee2aaSAndroid Build Coastguard Worker            const x = Math.random()*550;
62*c8dee2aaSAndroid Build Coastguard Worker            const y = Math.random()*550;
63*c8dee2aaSAndroid Build Coastguard Worker            ctx.paint.setColor(randomColorTwo(CanvasKit, 1, 2));
64*c8dee2aaSAndroid Build Coastguard Worker            ctx.canvas.drawOval(CanvasKit.LTRBRect(x, y, x+50, y+50), ctx.paint);
65*c8dee2aaSAndroid Build Coastguard Worker        }
66*c8dee2aaSAndroid Build Coastguard Worker    },
67*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {
68*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.delete();
69*c8dee2aaSAndroid Build Coastguard Worker    },
70*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'canvas_drawOval',
71*c8dee2aaSAndroid Build Coastguard Worker});
72*c8dee2aaSAndroid Build Coastguard Worker
73*c8dee2aaSAndroid Build Coastguard Workertests.push({
74*c8dee2aaSAndroid Build Coastguard Worker    description: 'Draw 10K colored roundRects',
75*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
76*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas = ctx.surface.getCanvas();
77*c8dee2aaSAndroid Build Coastguard Worker
78*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint = new CanvasKit.Paint();
79*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setAntiAlias(true);
80*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setStyle(CanvasKit.PaintStyle.Fill);
81*c8dee2aaSAndroid Build Coastguard Worker    },
82*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
83*c8dee2aaSAndroid Build Coastguard Worker        for (let i=0; i<10000; i++) {
84*c8dee2aaSAndroid Build Coastguard Worker            const x = Math.random()*550;
85*c8dee2aaSAndroid Build Coastguard Worker            const y = Math.random()*550;
86*c8dee2aaSAndroid Build Coastguard Worker            ctx.paint.setColor(randomColorTwo(CanvasKit, 0, 2));
87*c8dee2aaSAndroid Build Coastguard Worker            const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(x, y, x+50, y+50), 10, 10,);
88*c8dee2aaSAndroid Build Coastguard Worker            ctx.canvas.drawRRect(rr, ctx.paint);
89*c8dee2aaSAndroid Build Coastguard Worker        }
90*c8dee2aaSAndroid Build Coastguard Worker    },
91*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {
92*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.delete();
93*c8dee2aaSAndroid Build Coastguard Worker    },
94*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'canvas_drawRRect',
95*c8dee2aaSAndroid Build Coastguard Worker});
96*c8dee2aaSAndroid Build Coastguard Worker
97*c8dee2aaSAndroid Build Coastguard Workertests.push({
98*c8dee2aaSAndroid Build Coastguard Worker    description: 'Draw 10K colored rects',
99*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
100*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas = ctx.surface.getCanvas();
101*c8dee2aaSAndroid Build Coastguard Worker
102*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint = new CanvasKit.Paint();
103*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setAntiAlias(true);
104*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setStyle(CanvasKit.PaintStyle.Fill);
105*c8dee2aaSAndroid Build Coastguard Worker    },
106*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
107*c8dee2aaSAndroid Build Coastguard Worker        for (let i=0; i<10000; i++) {
108*c8dee2aaSAndroid Build Coastguard Worker            const x = Math.random()*550;
109*c8dee2aaSAndroid Build Coastguard Worker            const y = Math.random()*550;
110*c8dee2aaSAndroid Build Coastguard Worker            ctx.paint.setColor(randomColorTwo(CanvasKit, 1, 2));
111*c8dee2aaSAndroid Build Coastguard Worker            ctx.canvas.drawRect(CanvasKit.LTRBRect(x, y, x+50, y+50), ctx.paint);
112*c8dee2aaSAndroid Build Coastguard Worker        }
113*c8dee2aaSAndroid Build Coastguard Worker    },
114*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {
115*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.delete();
116*c8dee2aaSAndroid Build Coastguard Worker    },
117*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'canvas_drawRect',
118*c8dee2aaSAndroid Build Coastguard Worker});
119*c8dee2aaSAndroid Build Coastguard Worker
120*c8dee2aaSAndroid Build Coastguard Workertests.push({
121*c8dee2aaSAndroid Build Coastguard Worker    description: "Draw 10K colored rects with malloc'd rect",
122*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
123*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas = ctx.surface.getCanvas();
124*c8dee2aaSAndroid Build Coastguard Worker
125*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint = new CanvasKit.Paint();
126*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setAntiAlias(true);
127*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setStyle(CanvasKit.PaintStyle.Fill);
128*c8dee2aaSAndroid Build Coastguard Worker        ctx.rect = CanvasKit.Malloc(Float32Array, 4);
129*c8dee2aaSAndroid Build Coastguard Worker    },
130*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
131*c8dee2aaSAndroid Build Coastguard Worker        for (let i=0; i<10000; i++) {
132*c8dee2aaSAndroid Build Coastguard Worker            ctx.paint.setColor(randomColorTwo(CanvasKit, 1, 2));
133*c8dee2aaSAndroid Build Coastguard Worker            const ta = ctx.rect.toTypedArray();
134*c8dee2aaSAndroid Build Coastguard Worker            ta[0] = Math.random()*550; // x
135*c8dee2aaSAndroid Build Coastguard Worker            ta[1] = Math.random()*550; // y
136*c8dee2aaSAndroid Build Coastguard Worker            ta[2] = ta[0] + 50;
137*c8dee2aaSAndroid Build Coastguard Worker            ta[3] = ta[1] + 50;
138*c8dee2aaSAndroid Build Coastguard Worker            ctx.canvas.drawRect(ta, ctx.paint);
139*c8dee2aaSAndroid Build Coastguard Worker        }
140*c8dee2aaSAndroid Build Coastguard Worker    },
141*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {
142*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.delete();
143*c8dee2aaSAndroid Build Coastguard Worker        CanvasKit.Free(ctx.rect);
144*c8dee2aaSAndroid Build Coastguard Worker    },
145*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'canvas_drawRect_malloc',
146*c8dee2aaSAndroid Build Coastguard Worker});
147*c8dee2aaSAndroid Build Coastguard Worker
148*c8dee2aaSAndroid Build Coastguard Workertests.push({
149*c8dee2aaSAndroid Build Coastguard Worker    description: 'Draw 10K colored rects using 4 float API',
150*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
151*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas = ctx.surface.getCanvas();
152*c8dee2aaSAndroid Build Coastguard Worker
153*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint = new CanvasKit.Paint();
154*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setAntiAlias(true);
155*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setStyle(CanvasKit.PaintStyle.Fill);
156*c8dee2aaSAndroid Build Coastguard Worker    },
157*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
158*c8dee2aaSAndroid Build Coastguard Worker        for (let i=0; i<10000; i++) {
159*c8dee2aaSAndroid Build Coastguard Worker            const x = Math.random()*550;
160*c8dee2aaSAndroid Build Coastguard Worker            const y = Math.random()*550;
161*c8dee2aaSAndroid Build Coastguard Worker            ctx.paint.setColor(randomColorTwo(CanvasKit, 1, 2));
162*c8dee2aaSAndroid Build Coastguard Worker            ctx.canvas.drawRect4f(x, y, x+50, y+50, ctx.paint);
163*c8dee2aaSAndroid Build Coastguard Worker        }
164*c8dee2aaSAndroid Build Coastguard Worker    },
165*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {
166*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.delete();
167*c8dee2aaSAndroid Build Coastguard Worker    },
168*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'canvas_drawRect4f',
169*c8dee2aaSAndroid Build Coastguard Worker});
170*c8dee2aaSAndroid Build Coastguard Worker
171*c8dee2aaSAndroid Build Coastguard Workertests.push({
172*c8dee2aaSAndroid Build Coastguard Worker    description: 'Compute tonal colors',
173*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {},
174*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
175*c8dee2aaSAndroid Build Coastguard Worker        for (let i = 0; i < 10; i++) {
176*c8dee2aaSAndroid Build Coastguard Worker            const input = {
177*c8dee2aaSAndroid Build Coastguard Worker                ambient: randomColor(CanvasKit),
178*c8dee2aaSAndroid Build Coastguard Worker                spot: randomColor(CanvasKit),
179*c8dee2aaSAndroid Build Coastguard Worker            };
180*c8dee2aaSAndroid Build Coastguard Worker            const out = CanvasKit.computeTonalColors(input);
181*c8dee2aaSAndroid Build Coastguard Worker            if (out.spot[2] > 10 || out.ambient[3] > 10) {
182*c8dee2aaSAndroid Build Coastguard Worker                // Something to make sure v8 can't optimize away the return value
183*c8dee2aaSAndroid Build Coastguard Worker                throw 'not possible';
184*c8dee2aaSAndroid Build Coastguard Worker            }
185*c8dee2aaSAndroid Build Coastguard Worker        }
186*c8dee2aaSAndroid Build Coastguard Worker    },
187*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
188*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'computeTonalColors',
189*c8dee2aaSAndroid Build Coastguard Worker});
190*c8dee2aaSAndroid Build Coastguard Worker
191*c8dee2aaSAndroid Build Coastguard Workertests.push({
192*c8dee2aaSAndroid Build Coastguard Worker    description: 'Get and set the color to a paint',
193*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
194*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint = new CanvasKit.Paint();
195*c8dee2aaSAndroid Build Coastguard Worker    },
196*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
197*c8dee2aaSAndroid Build Coastguard Worker        for (let i = 0; i < 10; i++) {
198*c8dee2aaSAndroid Build Coastguard Worker            ctx.paint.setColor(randomColor(CanvasKit));
199*c8dee2aaSAndroid Build Coastguard Worker            const color = ctx.paint.getColor();
200*c8dee2aaSAndroid Build Coastguard Worker            if (color[3] > 4) {
201*c8dee2aaSAndroid Build Coastguard Worker                // Something to make sure v8 can't optimize away the return value
202*c8dee2aaSAndroid Build Coastguard Worker                throw 'not possible';
203*c8dee2aaSAndroid Build Coastguard Worker            }
204*c8dee2aaSAndroid Build Coastguard Worker        }
205*c8dee2aaSAndroid Build Coastguard Worker    },
206*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {
207*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.delete();
208*c8dee2aaSAndroid Build Coastguard Worker    },
209*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'paint_setColor_getColor',
210*c8dee2aaSAndroid Build Coastguard Worker});
211*c8dee2aaSAndroid Build Coastguard Worker
212*c8dee2aaSAndroid Build Coastguard Workertests.push({
213*c8dee2aaSAndroid Build Coastguard Worker    description: 'Set the color to a paint by components',
214*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
215*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint = new CanvasKit.Paint();
216*c8dee2aaSAndroid Build Coastguard Worker    },
217*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
218*c8dee2aaSAndroid Build Coastguard Worker        const r = Math.random();
219*c8dee2aaSAndroid Build Coastguard Worker        const g = Math.random();
220*c8dee2aaSAndroid Build Coastguard Worker        const b = Math.random();
221*c8dee2aaSAndroid Build Coastguard Worker        const a = Math.random();
222*c8dee2aaSAndroid Build Coastguard Worker        for (let i = 0; i < 10000; i++) {
223*c8dee2aaSAndroid Build Coastguard Worker            ctx.paint.setColorComponents(r, g, b, a);
224*c8dee2aaSAndroid Build Coastguard Worker        }
225*c8dee2aaSAndroid Build Coastguard Worker    },
226*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {
227*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.delete();
228*c8dee2aaSAndroid Build Coastguard Worker    },
229*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'paint_setColorComponents',
230*c8dee2aaSAndroid Build Coastguard Worker});
231*c8dee2aaSAndroid Build Coastguard Worker
232*c8dee2aaSAndroid Build Coastguard Workertests.push({
233*c8dee2aaSAndroid Build Coastguard Worker    description: 'Draw a shadow with tonal colors',
234*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
235*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas = ctx.surface.getCanvas();
236*c8dee2aaSAndroid Build Coastguard Worker
237*c8dee2aaSAndroid Build Coastguard Worker        ctx.input = {
238*c8dee2aaSAndroid Build Coastguard Worker            ambient: CanvasKit.Color4f(0.2, 0.1, 0.3, 0.5),
239*c8dee2aaSAndroid Build Coastguard Worker            spot: CanvasKit.Color4f(0.8, 0.8, 0.9, 0.9),
240*c8dee2aaSAndroid Build Coastguard Worker        };
241*c8dee2aaSAndroid Build Coastguard Worker        ctx.lightRadius = 30;
242*c8dee2aaSAndroid Build Coastguard Worker        ctx.flags = 0;
243*c8dee2aaSAndroid Build Coastguard Worker        ctx.lightPos = [250,150,300];
244*c8dee2aaSAndroid Build Coastguard Worker        ctx.zPlaneParams = [0,0,1];
245*c8dee2aaSAndroid Build Coastguard Worker        ctx.path = starPath(CanvasKit);
246*c8dee2aaSAndroid Build Coastguard Worker    },
247*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
248*c8dee2aaSAndroid Build Coastguard Worker        const out = CanvasKit.computeTonalColors(ctx.input);
249*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas.drawShadow(ctx.path, ctx.zPlaneParams, ctx.lightPos, ctx.lightRadius,
250*c8dee2aaSAndroid Build Coastguard Worker                              out.ambient, out.spot, ctx.flags);
251*c8dee2aaSAndroid Build Coastguard Worker    },
252*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
253*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'canvas_drawShadow',
254*c8dee2aaSAndroid Build Coastguard Worker});
255*c8dee2aaSAndroid Build Coastguard Worker
256*c8dee2aaSAndroid Build Coastguard Workertests.push({
257*c8dee2aaSAndroid Build Coastguard Worker    description: 'Draw a gradient with an array of 10K colors',
258*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
259*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas = ctx.surface.getCanvas();
260*c8dee2aaSAndroid Build Coastguard Worker    },
261*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
262*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas.clear(CanvasKit.WHITE);
263*c8dee2aaSAndroid Build Coastguard Worker
264*c8dee2aaSAndroid Build Coastguard Worker        const num = 10000;
265*c8dee2aaSAndroid Build Coastguard Worker        colors = Array(num);
266*c8dee2aaSAndroid Build Coastguard Worker        positions = Array(num);
267*c8dee2aaSAndroid Build Coastguard Worker        // Create an array of colors spaced evenly along the 0..1 range of positions.
268*c8dee2aaSAndroid Build Coastguard Worker        for (let i=0; i<num; i++) {
269*c8dee2aaSAndroid Build Coastguard Worker            colors[i] = randomColorTwo(CanvasKit, 2, 3);
270*c8dee2aaSAndroid Build Coastguard Worker            positions[i] = i/num;
271*c8dee2aaSAndroid Build Coastguard Worker        }
272*c8dee2aaSAndroid Build Coastguard Worker        // make a gradient from those colors
273*c8dee2aaSAndroid Build Coastguard Worker        const shader = CanvasKit.Shader.MakeRadialGradient(
274*c8dee2aaSAndroid Build Coastguard Worker            [300, 300], 50, // center, radius
275*c8dee2aaSAndroid Build Coastguard Worker            colors, positions,
276*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.TileMode.Mirror,
277*c8dee2aaSAndroid Build Coastguard Worker        );
278*c8dee2aaSAndroid Build Coastguard Worker        // Fill the canvas using the gradient shader.
279*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
280*c8dee2aaSAndroid Build Coastguard Worker        paint.setStyle(CanvasKit.PaintStyle.Fill);
281*c8dee2aaSAndroid Build Coastguard Worker        paint.setShader(shader);
282*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas.drawPaint(paint);
283*c8dee2aaSAndroid Build Coastguard Worker
284*c8dee2aaSAndroid Build Coastguard Worker        shader.delete();
285*c8dee2aaSAndroid Build Coastguard Worker        paint.delete();
286*c8dee2aaSAndroid Build Coastguard Worker    },
287*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
288*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'canvas_drawHugeGradient',
289*c8dee2aaSAndroid Build Coastguard Worker});
290*c8dee2aaSAndroid Build Coastguard Worker
291*c8dee2aaSAndroid Build Coastguard Workertests.push({
292*c8dee2aaSAndroid Build Coastguard Worker    description: 'Draw a png image',
293*c8dee2aaSAndroid Build Coastguard Worker    setup: async function(CanvasKit, ctx) {
294*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas = ctx.surface.getCanvas();
295*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint = new CanvasKit.Paint();
296*c8dee2aaSAndroid Build Coastguard Worker        ctx.img = CanvasKit.MakeImageFromEncoded(ctx.files['test_512x512.png']);
297*c8dee2aaSAndroid Build Coastguard Worker        ctx.frame = 0;
298*c8dee2aaSAndroid Build Coastguard Worker    },
299*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
300*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas.clear(CanvasKit.WHITE);
301*c8dee2aaSAndroid Build Coastguard Worker        // Make the image to move so you can see visually that the test is running.
302*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas.drawImage(ctx.img, ctx.frame, ctx.frame, ctx.paint);
303*c8dee2aaSAndroid Build Coastguard Worker        ctx.frame++;
304*c8dee2aaSAndroid Build Coastguard Worker    },
305*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {
306*c8dee2aaSAndroid Build Coastguard Worker        ctx.img.delete();
307*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.delete();
308*c8dee2aaSAndroid Build Coastguard Worker    },
309*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'canvas_drawPngImage',
310*c8dee2aaSAndroid Build Coastguard Worker});
311*c8dee2aaSAndroid Build Coastguard Worker
312*c8dee2aaSAndroid Build Coastguard Worker
313*c8dee2aaSAndroid Build Coastguard Workerfunction htmlImageElementToDataURL(htmlImageElement) {
314*c8dee2aaSAndroid Build Coastguard Worker    const canvas = document.createElement('canvas');
315*c8dee2aaSAndroid Build Coastguard Worker    canvas.height = htmlImageElement.height;
316*c8dee2aaSAndroid Build Coastguard Worker    canvas.width = htmlImageElement.width;
317*c8dee2aaSAndroid Build Coastguard Worker    const ctx = canvas.getContext('2d')
318*c8dee2aaSAndroid Build Coastguard Worker    ctx.drawImage(htmlImageElement, 0, 0);
319*c8dee2aaSAndroid Build Coastguard Worker    return canvas.toDataURL();
320*c8dee2aaSAndroid Build Coastguard Worker}
321*c8dee2aaSAndroid Build Coastguard Worker
322*c8dee2aaSAndroid Build Coastguard Worker// This for loop generates two perf cases for each test image. One uses browser APIs
323*c8dee2aaSAndroid Build Coastguard Worker// to decode an image, and the other uses codecs included in the CanvasKit wasm to decode an
324*c8dee2aaSAndroid Build Coastguard Worker// image. wasm codec Image decoding is faster (50 microseconds vs 20000 microseconds), but
325*c8dee2aaSAndroid Build Coastguard Worker// including codecs in wasm increases the size of the CanvasKit wasm binary.
326*c8dee2aaSAndroid Build Coastguard Workerfor (const testImageFilename of ['test_64x64.png', 'test_512x512.png', 'test_1500x959.jpg']) {
327*c8dee2aaSAndroid Build Coastguard Worker    const htmlImageElement = new Image();
328*c8dee2aaSAndroid Build Coastguard Worker    htmlImageElementLoadPromise = new Promise((resolve) =>
329*c8dee2aaSAndroid Build Coastguard Worker        htmlImageElement.addEventListener('load', resolve));
330*c8dee2aaSAndroid Build Coastguard Worker    // Create a data url of the image so that load and decode time can be measured
331*c8dee2aaSAndroid Build Coastguard Worker    // while ignoring the time of getting the image from disk / the network.
332*c8dee2aaSAndroid Build Coastguard Worker    imageDataURLPromise = htmlImageElementLoadPromise.then(() =>
333*c8dee2aaSAndroid Build Coastguard Worker        htmlImageElementToDataURL(htmlImageElement));
334*c8dee2aaSAndroid Build Coastguard Worker    htmlImageElement.src = `/static/assets/${testImageFilename}`;
335*c8dee2aaSAndroid Build Coastguard Worker
336*c8dee2aaSAndroid Build Coastguard Worker    tests.push({
337*c8dee2aaSAndroid Build Coastguard Worker        description: 'Decode an image using HTMLImageElement and Canvas2D',
338*c8dee2aaSAndroid Build Coastguard Worker        setup: async function(CanvasKit, ctx) {
339*c8dee2aaSAndroid Build Coastguard Worker            ctx.imageDataURL = await imageDataURLPromise;
340*c8dee2aaSAndroid Build Coastguard Worker        },
341*c8dee2aaSAndroid Build Coastguard Worker        test: async function(CanvasKit, ctx) {
342*c8dee2aaSAndroid Build Coastguard Worker            const image = new Image();
343*c8dee2aaSAndroid Build Coastguard Worker            // Testing showed that waiting for the load event is faster than waiting for
344*c8dee2aaSAndroid Build Coastguard Worker            // image.decode().
345*c8dee2aaSAndroid Build Coastguard Worker            // Despite the name, both of them would decode the image, it was loaded in setup.
346*c8dee2aaSAndroid Build Coastguard Worker            // HTMLImageElement.decode() reference:
347*c8dee2aaSAndroid Build Coastguard Worker            // https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decode
348*c8dee2aaSAndroid Build Coastguard Worker            const promise = new Promise((resolve) => image.addEventListener('load', resolve));
349*c8dee2aaSAndroid Build Coastguard Worker            image.src = ctx.imageDataURL;
350*c8dee2aaSAndroid Build Coastguard Worker            await promise;
351*c8dee2aaSAndroid Build Coastguard Worker            const img = await CanvasKit.MakeImageFromCanvasImageSource(image);
352*c8dee2aaSAndroid Build Coastguard Worker            img.delete();
353*c8dee2aaSAndroid Build Coastguard Worker        },
354*c8dee2aaSAndroid Build Coastguard Worker        teardown: function(CanvasKit, ctx) {},
355*c8dee2aaSAndroid Build Coastguard Worker        perfKey: `canvas_${testImageFilename}_HTMLImageElementDecoding`,
356*c8dee2aaSAndroid Build Coastguard Worker    });
357*c8dee2aaSAndroid Build Coastguard Worker
358*c8dee2aaSAndroid Build Coastguard Worker    tests.push({
359*c8dee2aaSAndroid Build Coastguard Worker        description: 'Decode an image using codecs in wasm',
360*c8dee2aaSAndroid Build Coastguard Worker        setup: function(CanvasKit, ctx) {},
361*c8dee2aaSAndroid Build Coastguard Worker        test: function(CanvasKit, ctx) {
362*c8dee2aaSAndroid Build Coastguard Worker            const img = CanvasKit.MakeImageFromEncoded(ctx.files[testImageFilename]);
363*c8dee2aaSAndroid Build Coastguard Worker            img.delete();
364*c8dee2aaSAndroid Build Coastguard Worker        },
365*c8dee2aaSAndroid Build Coastguard Worker        teardown: function(CanvasKit, ctx) {},
366*c8dee2aaSAndroid Build Coastguard Worker        perfKey: '`canvas_${testImageFilename}_wasmImageDecoding`',
367*c8dee2aaSAndroid Build Coastguard Worker    });
368*c8dee2aaSAndroid Build Coastguard Worker}
369*c8dee2aaSAndroid Build Coastguard Worker
370*c8dee2aaSAndroid Build Coastguard Worker// 3x3 matrix ops
371*c8dee2aaSAndroid Build Coastguard Workertests.push({
372*c8dee2aaSAndroid Build Coastguard Worker    description: 'Multiply 3x3 matrices together',
373*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
374*c8dee2aaSAndroid Build Coastguard Worker        ctx.first = CanvasKit.Matrix.rotated(Math.PI/2, 10, 20);
375*c8dee2aaSAndroid Build Coastguard Worker        ctx.second = CanvasKit.Matrix.scaled(1, 2, 3, 4);
376*c8dee2aaSAndroid Build Coastguard Worker    },
377*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
378*c8dee2aaSAndroid Build Coastguard Worker        ctx.result = CanvasKit.Matrix.multiply(ctx.first, ctx.second);
379*c8dee2aaSAndroid Build Coastguard Worker        if (ctx.result.length === 18) {
380*c8dee2aaSAndroid Build Coastguard Worker            throw 'this is here to keep the result from being optimized away';
381*c8dee2aaSAndroid Build Coastguard Worker        }
382*c8dee2aaSAndroid Build Coastguard Worker    },
383*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
384*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'skmatrix_multiply',
385*c8dee2aaSAndroid Build Coastguard Worker});
386*c8dee2aaSAndroid Build Coastguard Worker
387*c8dee2aaSAndroid Build Coastguard Workertests.push({
388*c8dee2aaSAndroid Build Coastguard Worker    description: 'Transform a point using a matrix (mapPoint)',
389*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
390*c8dee2aaSAndroid Build Coastguard Worker        ctx.matr = CanvasKit.Matrix.multiply(
391*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.Matrix.rotated(Math.PI/2, 10, 20),
392*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.Matrix.scaled(1, 2, 3, 4),
393*c8dee2aaSAndroid Build Coastguard Worker        ); // make an arbitrary, but interesting matrix
394*c8dee2aaSAndroid Build Coastguard Worker    },
395*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
396*c8dee2aaSAndroid Build Coastguard Worker        for (let i = 0; i < 30; i++) {
397*c8dee2aaSAndroid Build Coastguard Worker            const pt = CanvasKit.Matrix.mapPoints(ctx.matr, [i, i]);
398*c8dee2aaSAndroid Build Coastguard Worker            if (pt.length === 18) {
399*c8dee2aaSAndroid Build Coastguard Worker                throw 'this is here to keep pt from being optimized away';
400*c8dee2aaSAndroid Build Coastguard Worker            }
401*c8dee2aaSAndroid Build Coastguard Worker        }
402*c8dee2aaSAndroid Build Coastguard Worker    },
403*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
404*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'skmatrix_transformPoint',
405*c8dee2aaSAndroid Build Coastguard Worker});
406*c8dee2aaSAndroid Build Coastguard Worker
407*c8dee2aaSAndroid Build Coastguard Workertests.push({
408*c8dee2aaSAndroid Build Coastguard Worker    description: 'Invert a 3x3 matrix',
409*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
410*c8dee2aaSAndroid Build Coastguard Worker        ctx.matr = CanvasKit.Matrix.multiply(
411*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.Matrix.rotated(Math.PI/2, 10, 20),
412*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.Matrix.scaled(1, 2, 3, 4),
413*c8dee2aaSAndroid Build Coastguard Worker        );
414*c8dee2aaSAndroid Build Coastguard Worker    },
415*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
416*c8dee2aaSAndroid Build Coastguard Worker        ctx.result = CanvasKit.Matrix.invert(ctx.matr);
417*c8dee2aaSAndroid Build Coastguard Worker        if (ctx.result.length === 18) {
418*c8dee2aaSAndroid Build Coastguard Worker            throw 'this is here to keep the result from being optimized away';
419*c8dee2aaSAndroid Build Coastguard Worker        }
420*c8dee2aaSAndroid Build Coastguard Worker    },
421*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
422*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'skmatrix_invert',
423*c8dee2aaSAndroid Build Coastguard Worker});
424*c8dee2aaSAndroid Build Coastguard Worker
425*c8dee2aaSAndroid Build Coastguard Workertests.push({
426*c8dee2aaSAndroid Build Coastguard Worker    description: 'Create a shader from a 3x3 matrix',
427*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
428*c8dee2aaSAndroid Build Coastguard Worker        ctx.matr = CanvasKit.Matrix.multiply(
429*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.Matrix.rotated(Math.PI/2, 10, 20),
430*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.Matrix.scaled(1, 2, 3, 4),
431*c8dee2aaSAndroid Build Coastguard Worker        );
432*c8dee2aaSAndroid Build Coastguard Worker    },
433*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
434*c8dee2aaSAndroid Build Coastguard Worker        const shader = CanvasKit.Shader.MakeSweepGradient(
435*c8dee2aaSAndroid Build Coastguard Worker            100, 100,
436*c8dee2aaSAndroid Build Coastguard Worker            [CanvasKit.GREEN, CanvasKit.BLUE],
437*c8dee2aaSAndroid Build Coastguard Worker            [0.0, 1.0],
438*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.TileMode.Clamp,
439*c8dee2aaSAndroid Build Coastguard Worker            ctx.matr);
440*c8dee2aaSAndroid Build Coastguard Worker        shader.delete();
441*c8dee2aaSAndroid Build Coastguard Worker    },
442*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
443*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'skmatrix_makeShader',
444*c8dee2aaSAndroid Build Coastguard Worker});
445*c8dee2aaSAndroid Build Coastguard Worker
446*c8dee2aaSAndroid Build Coastguard Workertests.push({
447*c8dee2aaSAndroid Build Coastguard Worker    description: 'Concat 3x3 matrix on a canvas',
448*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
449*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas = new CanvasKit.Canvas();
450*c8dee2aaSAndroid Build Coastguard Worker        ctx.matr = CanvasKit.Matrix.multiply(
451*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.Matrix.rotated(Math.PI/2, 10, 20),
452*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.Matrix.scaled(1, 2, 3, 4),
453*c8dee2aaSAndroid Build Coastguard Worker        );
454*c8dee2aaSAndroid Build Coastguard Worker    },
455*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
456*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas.concat(ctx.matr);
457*c8dee2aaSAndroid Build Coastguard Worker    },
458*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {
459*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas.delete();
460*c8dee2aaSAndroid Build Coastguard Worker    },
461*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'skmatrix_concat',
462*c8dee2aaSAndroid Build Coastguard Worker});
463*c8dee2aaSAndroid Build Coastguard Worker
464*c8dee2aaSAndroid Build Coastguard Worker// 4x4 matrix operations
465*c8dee2aaSAndroid Build Coastguard Workertests.push({
466*c8dee2aaSAndroid Build Coastguard Worker    description: 'Multiply 4x4 matrices together',
467*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
468*c8dee2aaSAndroid Build Coastguard Worker        ctx.first = CanvasKit.M44.rotated([10, 20, 30], Math.PI/2);
469*c8dee2aaSAndroid Build Coastguard Worker        ctx.second = CanvasKit.M44.scaled([1, 2, 3]);
470*c8dee2aaSAndroid Build Coastguard Worker    },
471*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
472*c8dee2aaSAndroid Build Coastguard Worker        ctx.result = CanvasKit.M44.multiply(ctx.first, ctx.second);
473*c8dee2aaSAndroid Build Coastguard Worker        if (ctx.result.length === 18) {
474*c8dee2aaSAndroid Build Coastguard Worker            throw 'this is here to keep the result from being optimized away';
475*c8dee2aaSAndroid Build Coastguard Worker        }
476*c8dee2aaSAndroid Build Coastguard Worker    },
477*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
478*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'skm44_multiply',
479*c8dee2aaSAndroid Build Coastguard Worker});
480*c8dee2aaSAndroid Build Coastguard Worker
481*c8dee2aaSAndroid Build Coastguard Workertests.push({
482*c8dee2aaSAndroid Build Coastguard Worker    description: 'Invert a 4x4 matrix',
483*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
484*c8dee2aaSAndroid Build Coastguard Worker        ctx.matr = CanvasKit.M44.multiply(
485*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.M44.rotated([10, 20, 30], Math.PI/2),
486*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.M44.scaled([1, 2, 3]),
487*c8dee2aaSAndroid Build Coastguard Worker        );
488*c8dee2aaSAndroid Build Coastguard Worker    },
489*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
490*c8dee2aaSAndroid Build Coastguard Worker        const result = CanvasKit.M44.invert(ctx.matr);
491*c8dee2aaSAndroid Build Coastguard Worker        if (result.length === 18) {
492*c8dee2aaSAndroid Build Coastguard Worker            throw 'this is here to keep the result from being optimized away';
493*c8dee2aaSAndroid Build Coastguard Worker        }
494*c8dee2aaSAndroid Build Coastguard Worker    },
495*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
496*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'skm44_invert',
497*c8dee2aaSAndroid Build Coastguard Worker});
498*c8dee2aaSAndroid Build Coastguard Worker
499*c8dee2aaSAndroid Build Coastguard Workertests.push({
500*c8dee2aaSAndroid Build Coastguard Worker    description: 'Concat 4x4 matrix on a canvas',
501*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
502*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas = new CanvasKit.Canvas();
503*c8dee2aaSAndroid Build Coastguard Worker        ctx.matr = CanvasKit.M44.multiply(
504*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.M44.rotated([10, 20, 30], Math.PI/2),
505*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.M44.scaled([1, 2, 3]),
506*c8dee2aaSAndroid Build Coastguard Worker        );
507*c8dee2aaSAndroid Build Coastguard Worker    },
508*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
509*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas.concat(ctx.matr);
510*c8dee2aaSAndroid Build Coastguard Worker    },
511*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {
512*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas.delete();
513*c8dee2aaSAndroid Build Coastguard Worker    },
514*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'skm44_concat',
515*c8dee2aaSAndroid Build Coastguard Worker});
516*c8dee2aaSAndroid Build Coastguard Worker
517*c8dee2aaSAndroid Build Coastguard Worker// DOMMatrix operations
518*c8dee2aaSAndroid Build Coastguard Workertests.push({
519*c8dee2aaSAndroid Build Coastguard Worker    description: 'Multiply DOM matrices together',
520*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
521*c8dee2aaSAndroid Build Coastguard Worker        ctx.first = new DOMMatrix().translate(10, 20).rotate(90).translate(-10, -20);
522*c8dee2aaSAndroid Build Coastguard Worker        ctx.second = new DOMMatrix().translate(3, 4).scale(1, 2).translate(-3, -4);
523*c8dee2aaSAndroid Build Coastguard Worker    },
524*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
525*c8dee2aaSAndroid Build Coastguard Worker        const result = ctx.first.multiply(ctx.second);
526*c8dee2aaSAndroid Build Coastguard Worker        if (result.length === 18) {
527*c8dee2aaSAndroid Build Coastguard Worker            throw 'this is here to keep the result from being optimized away';
528*c8dee2aaSAndroid Build Coastguard Worker        }
529*c8dee2aaSAndroid Build Coastguard Worker    },
530*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
531*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'dommatrix_multiply',
532*c8dee2aaSAndroid Build Coastguard Worker});
533*c8dee2aaSAndroid Build Coastguard Worker
534*c8dee2aaSAndroid Build Coastguard Workertests.push({
535*c8dee2aaSAndroid Build Coastguard Worker    description: 'Transform a point using a matrix (transformPoint)',
536*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
537*c8dee2aaSAndroid Build Coastguard Worker        ctx.matr = new DOMMatrix().translate(10, 20).rotate(90).translate(-10, -20)
538*c8dee2aaSAndroid Build Coastguard Worker            .multiply(new DOMMatrix().translate(3, 4).scale(1, 2).translate(-3, -4));
539*c8dee2aaSAndroid Build Coastguard Worker
540*c8dee2aaSAndroid Build Coastguard Worker        ctx.reusablePt = new DOMPoint(0, 0)
541*c8dee2aaSAndroid Build Coastguard Worker    },
542*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
543*c8dee2aaSAndroid Build Coastguard Worker        for (let i = 0; i < 30; i++) {
544*c8dee2aaSAndroid Build Coastguard Worker            ctx.reusablePt.X = i; ctx.reusablePt.Y = i;
545*c8dee2aaSAndroid Build Coastguard Worker            const pt = ctx.matr.transformPoint(ctx.reusablePt);
546*c8dee2aaSAndroid Build Coastguard Worker            if (pt.length === 18) {
547*c8dee2aaSAndroid Build Coastguard Worker                throw 'this is here to keep pt from being optimized away';
548*c8dee2aaSAndroid Build Coastguard Worker            }
549*c8dee2aaSAndroid Build Coastguard Worker        }
550*c8dee2aaSAndroid Build Coastguard Worker    },
551*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
552*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'dommatrix_transformPoint',
553*c8dee2aaSAndroid Build Coastguard Worker});
554*c8dee2aaSAndroid Build Coastguard Worker
555*c8dee2aaSAndroid Build Coastguard Workertests.push({
556*c8dee2aaSAndroid Build Coastguard Worker    description: 'Invert a DOM matrix',
557*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
558*c8dee2aaSAndroid Build Coastguard Worker        ctx.matr = new DOMMatrix().translate(10, 20).rotate(90).translate(-10, -20)
559*c8dee2aaSAndroid Build Coastguard Worker            .multiply(new DOMMatrix().translate(3, 4).scale(1, 2).translate(-3, -4));
560*c8dee2aaSAndroid Build Coastguard Worker    },
561*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
562*c8dee2aaSAndroid Build Coastguard Worker        const inverted = ctx.matr.inverse();
563*c8dee2aaSAndroid Build Coastguard Worker        if (inverted.length === 18) {
564*c8dee2aaSAndroid Build Coastguard Worker            throw 'this is here to keep the result from being optimized away';
565*c8dee2aaSAndroid Build Coastguard Worker        }
566*c8dee2aaSAndroid Build Coastguard Worker    },
567*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
568*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'dommatrix_invert',
569*c8dee2aaSAndroid Build Coastguard Worker});
570*c8dee2aaSAndroid Build Coastguard Worker
571*c8dee2aaSAndroid Build Coastguard Workertests.push({
572*c8dee2aaSAndroid Build Coastguard Worker    description: 'make a shader from a DOMMatrix',
573*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
574*c8dee2aaSAndroid Build Coastguard Worker        ctx.matr = new DOMMatrix().translate(10, 20).rotate(90).translate(-10, -20)
575*c8dee2aaSAndroid Build Coastguard Worker            .multiply(new DOMMatrix().translate(3, 4).scale(1, 2).translate(-3, -4));
576*c8dee2aaSAndroid Build Coastguard Worker    },
577*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
578*c8dee2aaSAndroid Build Coastguard Worker        const shader = CanvasKit.Shader.MakeSweepGradient(
579*c8dee2aaSAndroid Build Coastguard Worker            100, 100,
580*c8dee2aaSAndroid Build Coastguard Worker            [CanvasKit.GREEN, CanvasKit.BLUE],
581*c8dee2aaSAndroid Build Coastguard Worker            [0.0, 1.0],
582*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.TileMode.Clamp,
583*c8dee2aaSAndroid Build Coastguard Worker            ctx.matr);
584*c8dee2aaSAndroid Build Coastguard Worker        shader.delete();
585*c8dee2aaSAndroid Build Coastguard Worker    },
586*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {},
587*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'dommatrix_makeShader',
588*c8dee2aaSAndroid Build Coastguard Worker});
589*c8dee2aaSAndroid Build Coastguard Worker
590*c8dee2aaSAndroid Build Coastguard Worker// Tests the layout and drawing of a paragraph with hundreds of words.
591*c8dee2aaSAndroid Build Coastguard Worker// In the second variant, the colors change every frame
592*c8dee2aaSAndroid Build Coastguard Worker// In the third variant, the font size cycles between three sizes.
593*c8dee2aaSAndroid Build Coastguard Worker// In the fourth variant, the layout width changes.
594*c8dee2aaSAndroid Build Coastguard Worker// in the fifth variant, all of those properties change at the same time.
595*c8dee2aaSAndroid Build Coastguard Workerfor (const variant of ['static', 'color_changing', 'size_changing', 'layout_changing', 'everything']) {
596*c8dee2aaSAndroid Build Coastguard Worker    tests.push({
597*c8dee2aaSAndroid Build Coastguard Worker        description: `Layout and draw a ${variant} paragraph`,
598*c8dee2aaSAndroid Build Coastguard Worker        setup: function(CanvasKit, ctx) {
599*c8dee2aaSAndroid Build Coastguard Worker            ctx.canvas = ctx.surface.getCanvas();
600*c8dee2aaSAndroid Build Coastguard Worker            ctx.fontMgr = CanvasKit.FontMgr.FromData([ctx.files['Roboto-Regular.ttf']]);
601*c8dee2aaSAndroid Build Coastguard Worker            ctx.paraStyle = new CanvasKit.ParagraphStyle({
602*c8dee2aaSAndroid Build Coastguard Worker                textStyle: {
603*c8dee2aaSAndroid Build Coastguard Worker                        color: CanvasKit.WHITE,
604*c8dee2aaSAndroid Build Coastguard Worker                        fontFamilies: ['Roboto'],
605*c8dee2aaSAndroid Build Coastguard Worker                        fontSize: 11,
606*c8dee2aaSAndroid Build Coastguard Worker                    },
607*c8dee2aaSAndroid Build Coastguard Worker                textAlign: CanvasKit.TextAlign.Left,
608*c8dee2aaSAndroid Build Coastguard Worker            });
609*c8dee2aaSAndroid Build Coastguard Worker            ctx.frame = 0;
610*c8dee2aaSAndroid Build Coastguard Worker            ctx.text = "annap sap sa ladipidapidi rapadip sam dim dap dim dap do raka dip da da badip badip badipidipidipadisuten din dab do ".repeat(40);
611*c8dee2aaSAndroid Build Coastguard Worker        },
612*c8dee2aaSAndroid Build Coastguard Worker        test: function(CanvasKit, ctx) {
613*c8dee2aaSAndroid Build Coastguard Worker            ctx.canvas.clear(CanvasKit.BLACK);
614*c8dee2aaSAndroid Build Coastguard Worker            const builder = CanvasKit.ParagraphBuilder.Make(ctx.paraStyle, ctx.fontMgr);
615*c8dee2aaSAndroid Build Coastguard Worker            let pos = 0;
616*c8dee2aaSAndroid Build Coastguard Worker            let color = CanvasKit.WHITE;
617*c8dee2aaSAndroid Build Coastguard Worker            while (pos < ctx.text.length) {
618*c8dee2aaSAndroid Build Coastguard Worker                let size = 11;
619*c8dee2aaSAndroid Build Coastguard Worker                if (variant === 'size_changing' || variant === 'everything') {
620*c8dee2aaSAndroid Build Coastguard Worker                    // the bigger this modulo, the more work it takes to fill the glyph cache
621*c8dee2aaSAndroid Build Coastguard Worker                    size += ctx.frame % 4;
622*c8dee2aaSAndroid Build Coastguard Worker                }
623*c8dee2aaSAndroid Build Coastguard Worker                if (variant === 'color_changing' || variant === 'everything') {
624*c8dee2aaSAndroid Build Coastguard Worker                    color = randomColorTwo(CanvasKit, 0, 1);
625*c8dee2aaSAndroid Build Coastguard Worker                }
626*c8dee2aaSAndroid Build Coastguard Worker                builder.pushStyle(CanvasKit.TextStyle({
627*c8dee2aaSAndroid Build Coastguard Worker                    color: color,
628*c8dee2aaSAndroid Build Coastguard Worker                    fontFamilies: ['Roboto'],
629*c8dee2aaSAndroid Build Coastguard Worker                    fontSize: size,
630*c8dee2aaSAndroid Build Coastguard Worker                    fontStyle: {
631*c8dee2aaSAndroid Build Coastguard Worker                        weight: CanvasKit.FontWeight.Bold,
632*c8dee2aaSAndroid Build Coastguard Worker                    },
633*c8dee2aaSAndroid Build Coastguard Worker                }));
634*c8dee2aaSAndroid Build Coastguard Worker                const len = Math.floor(Math.random()*5+2);
635*c8dee2aaSAndroid Build Coastguard Worker                builder.addText(ctx.text.slice(pos, pos+len));
636*c8dee2aaSAndroid Build Coastguard Worker                builder.pop();
637*c8dee2aaSAndroid Build Coastguard Worker                pos += len;
638*c8dee2aaSAndroid Build Coastguard Worker            }
639*c8dee2aaSAndroid Build Coastguard Worker            const paragraph = builder.build();
640*c8dee2aaSAndroid Build Coastguard Worker            let w = 0;
641*c8dee2aaSAndroid Build Coastguard Worker            const base_width = 520;
642*c8dee2aaSAndroid Build Coastguard Worker            const varying_width_modulo = 70;
643*c8dee2aaSAndroid Build Coastguard Worker            if (variant === 'layout_changing' || variant === 'everything') {
644*c8dee2aaSAndroid Build Coastguard Worker                w = ctx.frame % varying_width_modulo;
645*c8dee2aaSAndroid Build Coastguard Worker            }
646*c8dee2aaSAndroid Build Coastguard Worker            paragraph.layout(base_width + w); // width in pixels to use when wrapping text
647*c8dee2aaSAndroid Build Coastguard Worker            ctx.canvas.drawParagraph(paragraph, 10, 10);
648*c8dee2aaSAndroid Build Coastguard Worker
649*c8dee2aaSAndroid Build Coastguard Worker            ctx.frame++;
650*c8dee2aaSAndroid Build Coastguard Worker            builder.delete();
651*c8dee2aaSAndroid Build Coastguard Worker            paragraph.delete();
652*c8dee2aaSAndroid Build Coastguard Worker        },
653*c8dee2aaSAndroid Build Coastguard Worker        teardown: function(CanvasKit, ctx) {
654*c8dee2aaSAndroid Build Coastguard Worker            ctx.fontMgr.delete();
655*c8dee2aaSAndroid Build Coastguard Worker        },
656*c8dee2aaSAndroid Build Coastguard Worker        perfKey: 'canvas_drawParagraph_'+variant,
657*c8dee2aaSAndroid Build Coastguard Worker    });
658*c8dee2aaSAndroid Build Coastguard Worker}
659*c8dee2aaSAndroid Build Coastguard Worker
660*c8dee2aaSAndroid Build Coastguard Workertests.push({
661*c8dee2aaSAndroid Build Coastguard Worker    description: 'Draw a path with a blur mask',
662*c8dee2aaSAndroid Build Coastguard Worker    setup: function(CanvasKit, ctx) {
663*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas = ctx.surface.getCanvas();
664*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint = new CanvasKit.Paint();
665*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setAntiAlias(true);
666*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setStyle(CanvasKit.PaintStyle.Fill);
667*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setColor(CanvasKit.Color4f(0.1, 0.7, 0.0, 1.0));
668*c8dee2aaSAndroid Build Coastguard Worker        ctx.path = starPath(CanvasKit);
669*c8dee2aaSAndroid Build Coastguard Worker        ctx.frame = 0;
670*c8dee2aaSAndroid Build Coastguard Worker    },
671*c8dee2aaSAndroid Build Coastguard Worker    test: function(CanvasKit, ctx) {
672*c8dee2aaSAndroid Build Coastguard Worker        const sigma = 0.1 + (ctx.frame/10);
673*c8dee2aaSAndroid Build Coastguard Worker        const blurMask = CanvasKit.MaskFilter.MakeBlur(
674*c8dee2aaSAndroid Build Coastguard Worker            CanvasKit.BlurStyle.Normal, sigma, true);
675*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.setMaskFilter(blurMask);
676*c8dee2aaSAndroid Build Coastguard Worker        ctx.canvas.drawPath(ctx.path, ctx.paint);
677*c8dee2aaSAndroid Build Coastguard Worker        blurMask.delete();
678*c8dee2aaSAndroid Build Coastguard Worker        ctx.frame++;
679*c8dee2aaSAndroid Build Coastguard Worker    },
680*c8dee2aaSAndroid Build Coastguard Worker    teardown: function(CanvasKit, ctx) {
681*c8dee2aaSAndroid Build Coastguard Worker        ctx.paint.delete();
682*c8dee2aaSAndroid Build Coastguard Worker        ctx.path.delete();
683*c8dee2aaSAndroid Build Coastguard Worker    },
684*c8dee2aaSAndroid Build Coastguard Worker    perfKey: 'canvas_blur_mask_filter',
685*c8dee2aaSAndroid Build Coastguard Worker});
686*c8dee2aaSAndroid Build Coastguard Worker
687*c8dee2aaSAndroid Build Coastguard Workerfor (const variant of ['ttf', 'woff', 'woff2']) {
688*c8dee2aaSAndroid Build Coastguard Worker    tests.push({
689*c8dee2aaSAndroid Build Coastguard Worker        description: `Get glyphIDs from a ${variant} font`,
690*c8dee2aaSAndroid Build Coastguard Worker        setup: function (CanvasKit, ctx) {
691*c8dee2aaSAndroid Build Coastguard Worker            const robotoData = ctx.files['Roboto-Regular.' + variant];
692*c8dee2aaSAndroid Build Coastguard Worker            ctx.robotoFace = CanvasKit.Typeface.MakeTypefaceFromData(robotoData);
693*c8dee2aaSAndroid Build Coastguard Worker            if (!ctx.robotoFace) {
694*c8dee2aaSAndroid Build Coastguard Worker                throw 'could not load ' + variant;
695*c8dee2aaSAndroid Build Coastguard Worker            }
696*c8dee2aaSAndroid Build Coastguard Worker            ctx.robotoFont = new CanvasKit.Font(ctx.robotoFace, 20);
697*c8dee2aaSAndroid Build Coastguard Worker            ctx.testGlyphID = 1;
698*c8dee2aaSAndroid Build Coastguard Worker        },
699*c8dee2aaSAndroid Build Coastguard Worker        test: function (CanvasKit, ctx) {
700*c8dee2aaSAndroid Build Coastguard Worker            // We get one glyph ID at a time to force cache misses and require Skia to
701*c8dee2aaSAndroid Build Coastguard Worker            // perhaps re-access the font. See skbug.com/12112 for example.
702*c8dee2aaSAndroid Build Coastguard Worker            const output = new Uint16Array(1);
703*c8dee2aaSAndroid Build Coastguard Worker            for (let i = ctx.testGlyphID; i < ctx.testGlyphID+100; i++) {
704*c8dee2aaSAndroid Build Coastguard Worker                ctx.robotoFont.getGlyphIDs(String.fromCodePoint(i), 1, output);
705*c8dee2aaSAndroid Build Coastguard Worker            }
706*c8dee2aaSAndroid Build Coastguard Worker            ctx.testGlyphID += 100;
707*c8dee2aaSAndroid Build Coastguard Worker        },
708*c8dee2aaSAndroid Build Coastguard Worker        teardown: function (CanvasKit, ctx) {
709*c8dee2aaSAndroid Build Coastguard Worker            ctx.robotoFace.delete();
710*c8dee2aaSAndroid Build Coastguard Worker            ctx.robotoFont.delete();
711*c8dee2aaSAndroid Build Coastguard Worker        },
712*c8dee2aaSAndroid Build Coastguard Worker        perfKey: 'font_getGlyphIDs_' + variant,
713*c8dee2aaSAndroid Build Coastguard Worker    });
714*c8dee2aaSAndroid Build Coastguard Worker}
715