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