warmUpOnCanvas method Null safety

  1. @override
Future<void> warmUpOnCanvas(
  1. Canvas canvas
)
override

Trigger common draw operations on a canvas to warm up GPU shader compilation cache.

Implementation

@override
Future<void> warmUpOnCanvas(ui.Canvas canvas) async {
  const ui.RRect rrect = ui.RRect.fromLTRBXY(20.0, 20.0, 60.0, 60.0, 10.0, 10.0);
  final ui.Path rrectPath = ui.Path()..addRRect(rrect);
  final ui.Path circlePath = ui.Path()..addOval(
    ui.Rect.fromCircle(center: const ui.Offset(40.0, 40.0), radius: 20.0),
  );

  // The following path is based on
  // https://skia.org/user/api/SkCanvas_Reference#SkCanvas_drawPath
  final ui.Path path = ui.Path();
  path.moveTo(20.0, 60.0);
  path.quadraticBezierTo(60.0, 20.0, 60.0, 60.0);
  path.close();
  path.moveTo(60.0, 20.0);
  path.quadraticBezierTo(60.0, 60.0, 20.0, 60.0);

  final ui.Path convexPath = ui.Path();
  convexPath.moveTo(20.0, 30.0);
  convexPath.lineTo(40.0, 20.0);
  convexPath.lineTo(60.0, 30.0);
  convexPath.lineTo(60.0, 60.0);
  convexPath.lineTo(20.0, 60.0);
  convexPath.close();

  // Skia uses different shaders based on the kinds of paths being drawn and
  // the associated paint configurations. According to our experience and
  // tracing, drawing the following paths/paints generates various of
  // shaders that are commonly used.
  final List<ui.Path> paths = <ui.Path>[rrectPath, circlePath, path, convexPath];

  final List<ui.Paint> paints = <ui.Paint>[
    ui.Paint()
      ..isAntiAlias = true
      ..style = ui.PaintingStyle.fill,
    ui.Paint()
      ..isAntiAlias = false
      ..style = ui.PaintingStyle.fill,
    ui.Paint()
      ..isAntiAlias = true
      ..style = ui.PaintingStyle.stroke
      ..strokeWidth = 10,
    ui.Paint()
      ..isAntiAlias = true
      ..style = ui.PaintingStyle.stroke
      ..strokeWidth = 0.1,  // hairline
  ];

  // Warm up path stroke and fill shaders.
  for (int i = 0; i < paths.length; i += 1) {
    canvas.save();
    for (final ui.Paint paint in paints) {
      canvas.drawPath(paths[i], paint);
      canvas.translate(drawCallSpacing, 0.0);
    }
    canvas.restore();
    canvas.translate(0.0, drawCallSpacing);
  }

  // Warm up shadow shaders.
  const ui.Color black = ui.Color(0xFF000000);
  canvas.save();
  canvas.drawShadow(rrectPath, black, 10.0, true);
  canvas.translate(drawCallSpacing, 0.0);
  canvas.drawShadow(rrectPath, black, 10.0, false);
  canvas.restore();

  // Warm up text shaders.
  canvas.translate(0.0, drawCallSpacing);
  final ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(
    ui.ParagraphStyle(textDirection: ui.TextDirection.ltr),
  )..pushStyle(ui.TextStyle(color: black))..addText('_');
  final ui.Paragraph paragraph = paragraphBuilder.build()
    ..layout(const ui.ParagraphConstraints(width: 60.0));
  canvas.drawParagraph(paragraph, const ui.Offset(20.0, 20.0));

  // Draw a rect inside a rrect with a non-trivial intersection. If the
  // intersection is trivial (e.g., equals the rrect clip), Skia will optimize
  // the clip out.
  //
  // Add an integral or fractional translation to trigger Skia's non-AA or AA
  // optimizations (as did before in normal FillRectOp in rrect clip cases).
  for (final double fraction in <double>[0.0, 0.5]) {
    canvas
      ..save()
      ..translate(fraction, fraction)
      ..clipRRect(ui.RRect.fromLTRBR(8, 8, 328, 248, const ui.Radius.circular(16)))
      ..drawRect(const ui.Rect.fromLTRB(10, 10, 320, 240), ui.Paint())
      ..restore();
    canvas.translate(drawCallSpacing, 0.0);
  }
  canvas.translate(0.0, drawCallSpacing);
}