blob: dfa7d674ce6d6c553cb2094a96338478d016e8e8 [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:math' as math;
import 'dart:ui';
import 'recorder.dart';
import 'test_data.dart';
/// Draws 9 screens worth of text in a 3x3 grid with only the middle cell
/// appearing on the visible screen:
///
/// +-------------+-------------+-------------+
/// | | | |
/// | invisible | invisible | invisible |
/// | | | |
/// +-----------------------------------------+
/// | | | |
/// | invisible | visible | invisible |
/// | | | |
/// +-----------------------------------------+
/// | | | |
/// | invisible | invisible | invisible |
/// | | | |
/// +-------------+-------------+-------------+
///
/// This reproduces the bug where we render more than visible causing
/// performance issues: https://github.com/flutter/flutter/issues/48516
class BenchTextOutOfPictureBounds extends SceneBuilderRecorder {
BenchTextOutOfPictureBounds() : super(name: benchmarkName) {
const Color red = Color.fromARGB(255, 255, 0, 0);
const Color green = Color.fromARGB(255, 0, 255, 0);
// We don't want paragraph generation and layout to pollute benchmark numbers.
singleLineParagraphs = _generateParagraphs(
paragraphCount: 500,
minWordCountPerParagraph: 2,
maxWordCountPerParagraph: 5,
color: red,
);
multiLineParagraphs = _generateParagraphs(
paragraphCount: 50,
minWordCountPerParagraph: 30,
maxWordCountPerParagraph: 50,
color: green,
);
}
// Use hard-coded seed to make sure the data is stable across benchmark runs.
static final math.Random _random = math.Random(0);
static const String benchmarkName = 'text_out_of_picture_bounds';
List<Paragraph> singleLineParagraphs;
List<Paragraph> multiLineParagraphs;
@override
void onDrawFrame(SceneBuilder sceneBuilder) {
final PictureRecorder pictureRecorder = PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
final Size screenSize = window.physicalSize;
const double padding = 10.0;
// Fills a single cell with random text.
void fillCellWithText(List<Paragraph> textSource) {
canvas.save();
double topOffset = 0;
while (topOffset < screenSize.height) {
final Paragraph paragraph =
textSource[_random.nextInt(textSource.length)];
// Give it enough space to make sure it ends up being a single-line paragraph.
paragraph.layout(ParagraphConstraints(width: screenSize.width / 2));
canvas.drawParagraph(paragraph, Offset.zero);
canvas.translate(0, paragraph.height + padding);
topOffset += paragraph.height + padding;
}
canvas.restore();
}
// Starting with the top-left cell, fill every cell with text.
canvas.translate(-screenSize.width, -screenSize.height);
for (int row = 0; row < 3; row++) {
canvas.save();
for (int col = 0; col < 3; col++) {
canvas.drawRect(
Offset.zero & screenSize,
Paint()
..style = PaintingStyle.stroke
..strokeWidth = 2.0,
);
// Fill single-line text.
fillCellWithText(singleLineParagraphs);
// Fill multi-line text.
canvas.save();
canvas.translate(screenSize.width / 2, 0);
fillCellWithText(multiLineParagraphs);
canvas.restore();
// Shift to next column.
canvas.translate(screenSize.width, 0);
}
// Undo horizontal shift.
canvas.restore();
// Shift to next row.
canvas.translate(0, screenSize.height);
}
final Picture picture = pictureRecorder.endRecording();
sceneBuilder.pushOffset(0.0, 0.0);
sceneBuilder.addPicture(Offset.zero, picture);
sceneBuilder.pop();
}
/// Generates strings and builds pre-laid out paragraphs to be used by the
/// benchmark.
List<Paragraph> _generateParagraphs({
int paragraphCount,
int minWordCountPerParagraph,
int maxWordCountPerParagraph,
Color color,
}) {
final List<Paragraph> strings = <Paragraph>[];
int wordPointer = 0; // points to the next word in lipsum to extract
for (int i = 0; i < paragraphCount; i++) {
final int wordCount = minWordCountPerParagraph +
_random.nextInt(maxWordCountPerParagraph - minWordCountPerParagraph);
final List<String> string = <String>[];
for (int j = 0; j < wordCount; j++) {
string.add(lipsum[wordPointer]);
wordPointer = (wordPointer + 1) % lipsum.length;
}
final ParagraphBuilder builder =
ParagraphBuilder(ParagraphStyle(fontFamily: 'sans-serif'))
..pushStyle(TextStyle(color: color, fontSize: 18.0))
..addText(string.join(' '))
..pop();
final Paragraph paragraph = builder.build();
// Fill half the screen.
paragraph
.layout(ParagraphConstraints(width: window.physicalSize.width / 2));
strings.add(paragraph);
}
return strings;
}
}