tests: Vendor blink perf tests (#38654)

Vendors the [blink perf
tests](https://chromium.googlesource.com/chromium/src/+/HEAD/third_party/blink/perf_tests/).
These perf tests are useful to evaluate the performance of servo. 
The license that governs the perf tests is included in the folder. 
Running benchmark cases automatically is left to future work.

The update.py script is taken from mozjs and slightly adapted, so we can
easily filter
(and patch if this should be necessary in the future.

Testing: This PR just adds the perf_tests, but does not use or modify
them in any way.

---------

Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This commit is contained in:
Jonathan Schwender 2025-08-17 11:54:04 +02:00 committed by GitHub
parent 7621332824
commit ee781b71b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
648 changed files with 359694 additions and 0 deletions

View file

@ -0,0 +1,2 @@
pdr@chromium.org
nrosenthal@chromium.org

View file

@ -0,0 +1,29 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<div id="container"></div>
<script>
// This test measures the lifecycle update performance when adding small
// amounts of text to a large page.
var initialTextCount = 10000;
var initialText = "";
for (var i = 0; i < initialTextCount; i++)
initialText += '<span>a</span>';
measurePaint({
run: function() {
var text = document.createElement('span');
text.innerText = 'abc';
container.appendChild(text);
},
setup: function() {
container.innerHTML = initialText;
},
done: function() {
container.innerHTML = "";
},
});
</script>
</body>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<div id="container" style="columns:10; column-gap:0; width:1px; column-fill:auto; height:100px;">
<div id="child" style="height:1000000px;"></div>
</div>
<script>
// Measure performance of painting a fragmented block with a background
// gradient.
var yellowfirst = false;
measurePaint({
run: function() {
child.style.background = yellowfirst ? "linear-gradient(yellow, hotpink)" : "linear-gradient(hotpink, yellow)";
yellowfirst = !yellowfirst;
},
});
</script>

View file

@ -0,0 +1,89 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<style>
div {
/* To ensure consistent line wrapping behavior about empty spans across
browsers. */
white-space: pre;
}
span {
padding: 1px;
}
.changeColor {
background-color: green;
}
</style>
<script>
// This test measures the lifecycle update performance of changing background
// colors in large trees.
function buildTree(parent, depth, arity, createElementCallback) {
for (var child = 0; child < arity; child++) {
var element = createElementCallback(depth);
parent.appendChild(element);
createElementCallback(element, depth);
if (depth > 1)
buildTree(element, depth - 1, arity, createElementCallback);
}
}
// Build a tall tree that is skinny. A middle layer of
// the tree should have the changeColor class.
buildTree(document.body, 15, 2,
function(depth) {
// Use divs at upper levels to avoid too much layout time.
var element = document.createElement(depth > 9 ? 'div' : 'span');
element.style.backgroundColor = 'green';
if (depth == 5)
element.classList.add('changeColor');
// Insert new lines to break long lines.
if (depth == 12)
element.textContent = '\n';
return element;
}
);
// Build a short tree that is fat. A middle layer of
// the tree should have the changeColor class.
buildTree(document.body, 6, 7,
function(depth) {
// Use divs at upper levels to avoid too much layout time.
var element = document.createElement(depth > 4 ? 'div' : 'span');
element.style.backgroundColor = 'orange';
if (depth == 3)
element.classList.add('changeColor');
// Insert new lines to break long lines.
if (depth == 6)
element.textContent = '\n';
return element;
}
);
var runCount = 0;
var elementsToChange = document.getElementsByClassName('changeColor');
var colors = [
"rgb(128, 18, 237)",
"rgb(191, 1, 191)",
"rgb(237, 18, 128)",
"rgb(255, 64, 64)",
"rgb(237, 127, 18)",
"rgb(191, 191, 1)",
"rgb(128, 237, 18)",
"rgb(64, 255, 64)",
"rgb(18, 237, 127)",
"rgb(1, 191, 191)",
"rgb(18, 128, 237)",
"rgb(64, 64, 255)"
];
measurePaint({
run: function() {
runCount++;
var newColor = colors[runCount % colors.length];
for (var index = 0; index < elementsToChange.length; index++)
elementsToChange[index].style.backgroundColor = newColor;
},
});
</script>
</body>

View file

@ -0,0 +1,30 @@
<!DOCTYPE html>
<style>
#container {
overflow: auto;
width: 600px;
height: 500px;
}
</style>
<div id="container">
<div id="template">
<h1><span>Sample</"span> Title<span><span> <a href=#>link1</a></span><span> <a href=#>link2</a></span></span></h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit</p>
<div><span>Note</span>
<p>Lorem ipsum dolor sit amet, <span>consectetur adipiscing elit</span>, sed do eiusmod tempor <a href=#>incididunt ut labore</a> et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco <span><span>laboris nisi ut aliquip</span> ex ea commodo consequat</span>. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.<p>
</div>
</div>
</div>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<script>
var cloned = template.cloneNode(true);
for (var i = 0; i < 10000; ++i)
container.appendChild(cloned.cloneNode(true));
measurePaint({
run: function() {
container.scrollTop += 20;
},
});
</script>

View file

@ -0,0 +1,72 @@
<!DOCTYPE html>
<title>Contain update layer tree performance</title>
<style>
#wrapper {
position: relative;
}
.cell {
position: absolute;
box-sizing: border-box;
border: solid;
contain: strict;
}
.progressbar {
position: absolute;
left: 0px;
top: 5px;
height: 10px;
}
</style>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<pre id="log"></pre>
<div id="wrapper"></div>
<script>
const CELL_WIDTH = "50";
const CELL_HEIGHT = "25";
const NUM_ROWS = 120;
const NUM_COLUMNS = 120;
const DOM_DEPTH = 10;
function createContent(depth) {
let content = document.createElement("div");
content.appendChild(document.createElement("h1"));
content.appendChild(document.createElement("paragraph"));
if (depth > 0)
content.appendChild(createContent(depth - 1));
return content;
}
function setupTest() {
let wrapper = document.getElementById("wrapper");
for (let i = 0; i < NUM_ROWS; i++) {
for (let j = 0; j < NUM_COLUMNS; j++) {
let cell = document.createElement("div");
if (i == 0 && j == 0)
cell.id = "target";
cell.classList.add("cell");
cell.style.width = CELL_WIDTH + "px";
cell.style.height = CELL_HEIGHT + "px";
cell.style.left = (j * CELL_WIDTH) + "px";
cell.style.top = (i * CELL_HEIGHT) + "px";
cell.style.overflow = "visible";
cell.appendChild(createContent(DOM_DEPTH));
wrapper.appendChild(cell);
}
}
}
function runTest() {
let cell = document.getElementById("target");
// This causes a call to PaintLayer::SetNeedsCompositingInputsUpdate().
cell.style.overflow = cell.style.overflow == "hidden" ? "visible" : "hidden";
}
setupTest();
measurePaint({
run: runTest
});
</script>

View file

@ -0,0 +1,42 @@
<!DOCTYPE html>
<!-- This case is based on the test in crbug.com/692614.
https://www.scirra.com/labs/bugs/containlayoutperf-workaround/ -->
<style>
#container {
border: 1px solid green;
contain: content;
width: 600px;
}
.item {
outline: 1px solid blue;
overflow: hidden;
contain: content;
}
</style>
<div id="container">
</div>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<script>
const LOREM_IPSUM="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
function createListItem() {
let wrap = document.createElement("div");
let item = document.createElement("div");
item.classList.add('item');
item.textContent = LOREM_IPSUM;
wrap.appendChild(item);
container.appendChild(wrap);
};
for (let i = 0; i < 10000; ++i)
createListItem();
var target = container.firstElementChild.firstElementChild;
measurePaint({
run: function() {
target.style.height = (target.offsetHeight - 1) + 'px';
},
});
</script>

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<title>Custom Highlights Painting Baseline</title>
<style>
.example > p > span {
color: blue;
background: yellow;
}
</style>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<pre id="log"></pre>
<script>
const REPETITIONS = 1000;
const LOREM_IPSUM = "Lorem ipsum dolor sit <span>a</span>met, consectetur <span>a</span>dipiscing elit, sed do eiusmod tempor incididunt ut l<span>a</span>bore et dolore m<span>a</span>gn<span>a</span> <span>a</span>liqu<span>a</span>. Ut enim <span>a</span>d minim veni<span>a</span>m, quis nostrud exercit<span>a</span>tion ull<span>a</span>mco l<span>a</span>boris nisi ut <span>a</span>liquip ex e<span>a</span> commodo consequ<span>a</span>t. Duis <span>a</span>ute irure dolor in reprehenderit in volupt<span>a</span>te velit esse cillum dolore eu fugi<span>a</span>t null<span>a</span> p<span>a</span>ri<span>a</span>tur. Excepteur sint occ<span>a</span>ec<span>a</span>t cupid<span>a</span>t<span>a</span>t non proident, sunt in culp<span>a</span> qui offici<span>a</span> deserunt mollit <span>a</span>nim id est l<span>a</span>borum.";
function setupTest() {
for (let i = 0; i < REPETITIONS; i++) {
let p = document.createElement("p");
p.innerHTML = LOREM_IPSUM;
document.body.appendChild(p);
}
}
setupTest();
measurePaint({
description: "Measure time for painting <span> elements to be used as baseline for Custom Highlights (emulates searching 'a' in a large text)",
run: () => document.body.className = "example",
setup: () => document.body.className = "",
});
</script>

View file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<title>Custom Highlights Painting</title>
<style>
::highlight(example) {
color: blue;
background: yellow;
}
.lime ::highlight(example) {
background: lime;
}
</style>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<main></main>
<pre id="log"></pre>
<script>
const LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ".repeat(42);
const highlight = new Highlight;
const main = document.querySelector("main");
main.textContent = LOREM_IPSUM;
for (let i = 0; i < LOREM_IPSUM.length; i += 2) {
const range = new Range;
range.setStart(main.firstChild, i);
range.setEnd(main.firstChild, i + 1);
highlight.add(range);
}
CSS.highlights.set("example", highlight);
measurePaint({
description: "Measure time for painting Custom Highlights (emulates searching 'a' in a large text)",
run: () => document.body.classList.toggle("lime"),
});
</script>

View file

@ -0,0 +1,47 @@
<!DOCTYPE html>
<title>Custom Highlights Painting</title>
<style>
::highlight(example) {
color: blue;
background: yellow;
}
</style>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<pre id="log"></pre>
<script>
// Setting this to larger values can result in "Maximum call stack size exceeded" exceptions, see: https://crbug.com/978832.
const REPETITIONS = 1000;
const LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
let indexesLetterA = [];
for (let i = 0; i < LOREM_IPSUM.length; i++) {
if (LOREM_IPSUM[i] == "a")
indexesLetterA.push(i);
}
let ranges = [];
function setupTest() {
for (let i = 0; i < REPETITIONS; i++) {
let p = document.createElement("p");
p.textContent = LOREM_IPSUM;
document.body.appendChild(p);
indexesLetterA.forEach(index => {
let range = new Range();
range.setStart(p.firstChild, index);
range.setEnd(p.firstChild, index + 1);
ranges.push(range);
});
}
}
setupTest();
measurePaint({
description: "Measure time for painting Custom Highlights (emulates searching 'a' in a large text)",
run: () => CSS.highlights.set("example", new Highlight(...ranges)),
setup: () => CSS.highlights.clear(),
});
</script>

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<div style="position: fixed; width: 10px; height: 10px; background-color: blue"></div>
<table id="table"></table>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<script>
function createRow(i) {
var tr = document.createElement('tr');
tr.innerHTML = '<td>' + i + '</td>' +
'<td style="position: relative"><b><i><u>Test</u></i></b><b><i><u>Test</u></i></b><b><i><u>Test</u></i></b><b><i><u>Test</u></i></b></td>';
table.appendChild(tr);
}
for (var i = 0; i < 20000; ++i)
createRow(i);
var count = 0;
measurePaint({
run: function() {
window.scrollTo(0, 20 * count++);
},
});
</script>

View file

@ -0,0 +1,58 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<style>
table {
border-collapse: collapse;
will-change: transform;
}
table.zero-width-border td {
border: 0px solid blue;
}
table.visible-border td {
border: 1px solid blue;
}
</style>
<script>
function createTable(rows, columns) {
var table = document.createElement("TABLE");
for (var i = 0; i < rows; ++i) {
var tr = document.createElement("TR");
for (var j = 0; j < columns; ++j) {
var td = document.createElement("TD");
tr.appendChild(td);
}
table.appendChild(tr);
}
return table;
}
var table1 = createTable(300, 300);
table1.className = 'zero-width-border';
document.body.appendChild(table1);
var table2 = createTable(300, 300);
table2.className = 'invisible-border';
document.body.appendChild(table2);
var table3 = createTable(300, 300);
table3.className = 'visible-border';
document.body.appendChild(table3);
var count = 0;
var ix = 30;
var iy = 30;
measurePaint({
iterationCount: 30,
run: function() {
var table = [table1, table2, table3][count % 3];
table.childNodes[iy].childNodes[ix].style.backgroundColor = 'teal';
ix++;
iy++;
count++;
},
});
</script>
</body>

View file

@ -0,0 +1,67 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<style>
table {
border: 2px solid green;
border-collapse: collapse;
font-size: 3px;
will-change: transform;
}
td {
border: 1px solid blue;
}
table.text td::before {
content: "ABC";
}
table.background td {
background: green;
}
</style>
<script>
function createTable(rows, columns) {
var table = document.createElement("TABLE");
for (var i = 0; i < rows; ++i) {
var tr = document.createElement("TR");
for (var j = 0; j < columns; ++j) {
var td = document.createElement("TD");
tr.appendChild(td);
}
table.appendChild(tr);
}
return table;
}
var table1 = createTable(100, 100);
document.body.appendChild(table1);
var table2= createTable(150, 150);
table2.className = 'text';
document.body.appendChild(table2);
var table3 = createTable(150, 150);
table3.className = 'background';
document.body.appendChild(table3);
var count = 0;
var ix = 30;
var iy = 30;
measurePaint({
iterationCount: 40,
run: function() {
if (count % 4 == 0) {
table1.style.borderColor = table1.style.borderColor == 'green' ?
'yellow' : 'green';
} else {
var table = [table1, table2, table3][count % 3];
table.childNodes[iy].childNodes[ix].style.borderColor = "red";
ix++;
iy++;
}
count++;
},
});
</script>
</body>

View file

@ -0,0 +1,44 @@
<!doctype html>
<script src="../resources/runner.js"></script>
<script src="../layout/resources/line-layout-perf-test.js"></script>
<script src="resources/paint.js"></script>
<div id="container"></div>
<script>
const kNumberOfWords = 10000 * 30;
const container = document.getElementById('container');
const selection = window.getSelection();
container.textContent = (() => {
const words = [];
for (let i = 0; i < kNumberOfWords; ++i)
words.push(TextGenerator.createWord(i % 12 + 3));
return words.join(' ');
})();
const text = container.firstChild;
var count = 0;
measurePaint({
iterationCount: 50,
warmUpCount: 5,
run: function() {
if (count < 20) {
// Select all.
selection.collapse(container, 0);
if (count % 2)
selection.extend(container, 1);
} else if (count < 35) {
// Modify selection at beginning.
selection.setBaseAndExtent(text, 4000 - count * 10, text, text.length);
} else if (count == 35) {
selection.setBaseAndExtent(text, 1000, text, 4000);
} else {
// Extend selection at end.
selection.modify("extend", "forward", "word");
}
count++;
},
});
</script>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<div id="container" style="columns:10000; column-gap:0; column-fill:auto; height:100px;">
<div style="height:1000000px;"></div>
</div>
<script>
// Measure paint / pre-paint performance of a multicol container with many
// columns.
var wide = false;
measurePaint({
run: function() {
container.style.width = wide ? "600px" : "700px";
wide = !wide;
},
});
</script>

View file

@ -0,0 +1,69 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<style>
.column {
width: 180px;
height: 310px;
border: 1px solid black;
font-size: 1px;
}
.row {
width: 150px;
border: 1px solid cornflowerblue;
}
.row > span {
border: 1px solid rebeccapurple;
}
</style>
<script>
// This test measures the lifecycle update performance of changing paint offset.
// Create a column with many rows of divs and many spans on each row.
function createColumn(parent) {
var rowsPerColumn = 200;
var spansPerRow = 100;
var columnDiv = document.createElement('div');
parent.appendChild(columnDiv);
columnDiv.setAttribute('class', 'column');
for (var row = 0; row < rowsPerColumn; row++) {
var rowDiv = document.createElement('div');
rowDiv.setAttribute('class', 'row');
columnDiv.appendChild(rowDiv);
for (var span = 0; span < spansPerRow; span++) {
var spanElement = document.createElement('span');
rowDiv.appendChild(spanElement);
}
}
return columnDiv;
}
var rowMarginsToChange = createColumn(document.body).querySelectorAll('.row');
var changeRowMargins = function(runCount) {
for (var index = 0; index < rowMarginsToChange.length; index++)
rowMarginsToChange[index].style.marginLeft = (runCount % 10) + 'px';
}
var spanMarginsToChange = createColumn(document.body).querySelectorAll('.row > span');
var changeRowSpanMargins = function(runCount) {
for (var index = 0; index < spanMarginsToChange.length; index += 8)
spanMarginsToChange[index].style.marginLeft = ((runCount + index) % 3) + 'px';
}
var firstRowHeightToChange = createColumn(document.body).querySelector('.row');
var changeFirstRowHeight = function(rowCount) {
firstRowHeightToChange.style.height = (5 + runCount % 5) + 'px';
}
var runCount = 0;
measurePaint({
run: function() {
runCount++;
changeRowMargins(runCount);
changeRowSpanMargins(runCount);
changeFirstRowHeight(runCount);
},
});
</script>
</body>

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<div id="container" style="columns:1000; gap:0; column-fill:auto; height:100px; line-height:20px;">
<span id="relpos" style="position:relative;"></span>
</div>
<script>
// Measure performance of painting a multicol with relatively positioned
// inline with many lines / columns.
for (var i = 0; i < 1000; i++) {
relpos.appendChild(document.createTextNode("i "));
}
var cyan = false;
measurePaint({
run: function() {
relpos.style.background = cyan ? "cyan" : "hotpink";
cyan = !cyan;
},
});
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View file

@ -0,0 +1,12 @@
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
function measurePaint(test) {
test.tracingCategories = 'blink';
test.traceEventsToMeasure = [
'LocalFrameView::RunPrePaintLifecyclePhase',
'LocalFrameView::RunPaintLifecyclePhase'
];
PerfTestRunner.measureFrameTime(test);
}

View file

@ -0,0 +1,91 @@
<!DOCTYPE html>
<title>Spelling error makers painting</title>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<p>To run this test use: <code>content_shell --expose-internals-for-testing</code>.</p>
<p id="warning" style="color: red;"></p>
<pre id="log"></pre>
<div>Word count: <span id="wc">0</span></div>
<main contenteditable></main>
<script>
const LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ";
const INITIAL_WORDS = 3000;
const main = document.querySelector("main");
const wc = document.querySelector("#wc");
function createRange(element, start, end) {
let range = new Range();
range.setStart(element.firstChild, start);
range.setEnd(element.firstChild, end);
return range;
}
function setupTest() {
if (!window.internals)
document.querySelector("#warning").innerHTML = "WARNING: use <code>content_shell --expose-internals-for-testing</code> to run this test more accurately!";
// Use real spell checker as a last resort. content_shell only has intenals,
// while chrome only has real spell checker. Some words in the test input
// might be in the dictionary (e.g. sit, do).
main.spellcheck = !window.internals;
main.focus();
// Type the initial words in bulk. This is much faster than typing it one
// letter at a time with simulateTyping.
const wordsInSentence = LOREM_IPSUM.split(" ").length - 1;
const repeatedSentence = LOREM_IPSUM.repeat(Math.ceil(INITIAL_WORDS / wordsInSentence));
const repeatedWords = repeatedSentence.split(" ");
const input = repeatedWords.slice(0, INITIAL_WORDS).join(" ");
document.execCommand("insertText", false, input);
wc.textContent = INITIAL_WORDS;
// Mark the initial words as spelling errors.
try {
for (let i = 0, wordStart = 0; i < INITIAL_WORDS; i++) {
const wordEnd = wordStart + repeatedWords[i].length;
const range = createRange(main, wordStart, wordEnd);
internals.setMarker(document, range, "spelling");
wordStart = wordEnd + 1; // space (U+0020 or U+00A0)
}
} catch (_) {
/* empty */
}
}
function simulateTyping() {
// Type the input, one letter at a time.
document.execCommand("insertText", false, LOREM_IPSUM[main.textContent.length % LOREM_IPSUM.length]);
// After typing each word, mark that word as a spelling error.
// In content_shell, spaces are U+00A0 (&nbsp;) until they are no longer
// trailing, but in chrome, they can stay as U+00A0 permanently.
// https://w3c.github.io/editing/docs/execCommand/#canonical-space-sequences
// https://w3c.github.io/editing/docs/execCommand/#the-inserttext-command
const newContent = main.textContent;
if (newContent.at(-2) == " " || newContent.at(-2) == "\xA0") {
document.querySelector("#wc").textContent++;
const end = newContent.length - 2;
const words = newContent.slice(0, end);
let start;
for (start = words.length - 1; start >= 0; start--)
if (words[start] == " " || words[start] == "\xA0")
break;
try {
const range = createRange(main, start == -1 ? 0 : start + 1, end);
internals.setMarker(document, range, "spelling");
} catch (_) {
/* empty */
}
}
}
setupTest();
measurePaint({
description: "Measure frame time for typing in contenteditable with many spelling errors",
run: () => void simulateTyping(),
});
</script>

View file

@ -0,0 +1,66 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<style>
span {
border: 1px solid blue;
}
.changeTransform {
position: absolute;
transform: rotate(0);
}
</style>
<script>
// This test measures the lifecycle update performance of changing transforms
// in large trees.
function buildTree(parent, depth, arity, tagNameCallback, createElementCallback) {
for (var child = 0; child < arity; child++) {
var element = document.createElement(tagNameCallback(depth));
parent.appendChild(element);
createElementCallback(element, depth);
if (depth > 1)
buildTree(element, depth - 1, arity, tagNameCallback, createElementCallback);
}
}
// Build a tall tree that is skinny. A middle layer of
// the tree should have the changeTransform class.
buildTree(document.body, 13, 2,
function(depth) {
// Use divs at upper levels to avoid too much layout time.
return depth > 11 ? 'div' : 'span';
},
function(element, depth) {
element.style.borderColor = 'red';
if (depth == 5)
element.setAttribute('class', 'changeTransform');
}
);
// Build a short tree that is fat. A middle layer of
// the tree should have the changeTransform class.
buildTree(document.body, 6, 6,
function(depth) {
// Use divs at upper levels to avoid too much layout time.
return depth > 5 ? 'div' : 'span';
},
function(element, depth) {
element.style.borderColor = 'orange';
if (depth == 3)
element.setAttribute('class', 'changeTransform');
}
);
var runCount = 0;
var elementsToChange = document.getElementsByClassName('changeTransform');
measurePaint({
run: function() {
runCount += 10;
for (var index = 0; index < elementsToChange.length; index++)
elementsToChange[index].style.transform = 'rotate(' + runCount + 'deg)';
},
});
</script>
</body>

View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<title>Wavy decoration painting: one long decoration</title>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<style>
* {
text-decoration-skip: none;
text-decoration-skip-ink: none;
}
main {
text-decoration: red wavy underline;
}
main.blue {
text-decoration: blue wavy underline;
}
</style>
<main>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </main>
<script>
const main = document.querySelector("main");
main.innerHTML = main.innerHTML.repeat(420);
measurePaint({
description: "Measure frame time for painting wavy decorations with one long decoration",
run: () => void document.querySelector("main").classList.toggle("blue"),
});
</script>

View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<title>Wavy decoration painting: many short decorations</title>
<script src="../resources/runner.js"></script>
<script src="resources/paint.js"></script>
<style>
* {
text-decoration-skip: none;
text-decoration-skip-ink: none;
}
main > span {
text-decoration: red wavy underline;
}
main.blue > span {
text-decoration: blue wavy underline;
}
</style>
<main><span>Lorem</span> <span>ipsum</span> <span>dolor</span> <span>sit</span> <span>amet,</span> <span>consectetur</span> <span>adipiscing</span> <span>elit,</span> <span>sed</span> <span>do</span> <span>eiusmod</span> <span>tempor</span> <span>incididunt</span> <span>ut</span> <span>labore</span> <span>et</span> <span>dolore</span> <span>magna</span> <span>aliqua.</span> </main>
<script>
const main = document.querySelector("main");
main.innerHTML = main.innerHTML.repeat(420);
measurePaint({
description: "Measure frame time for painting wavy decorations with many short decorations",
run: () => void document.querySelector("main").classList.toggle("blue"),
});
</script>