LibWeb: Do not scroll cursor into view on programmatic selection changes

We were mimicking Firefox' behavior that whenever a programmatic change
to an <input>'s or <textarea>'s selection happened, the new selection
focus is brought into view by scrolling. Currently we run a layout
update synchronously for that to make sure we have the fragment's
correct dimensions, which caused a significant performance regression in
Speedometer.

Since this is non-standard behavior, let's mimic Chromium instead which
does not scroll at all - only for direct user initiated input such as
typing.

Relevant issues:

* https://github.com/whatwg/html/issues/6217
* https://bugzilla.mozilla.org/show_bug.cgi?id=232405
* https://issues.chromium.org/issues/41081857
This commit is contained in:
Jelle Raaijmakers
2026-02-16 13:51:24 +01:00
committed by Andreas Kling
parent fa04c8db83
commit ded42e649b
Notes: github-actions[bot] 2026-02-17 09:25:08 +00:00
14 changed files with 124 additions and 69 deletions

View File

@@ -0,0 +1,37 @@
<!DOCTYPE html>
<style>
.row {
display: flex;
align-items: center;
padding: 4px;
}
</style>
<input id="inp" />
<div id="app"></div>
<script src="include.js"></script>
<script>
test(() => {
const input = document.querySelector("#inp");
const app = document.querySelector("#app");
for (let i = 0; i < 2000; i++) {
const row = document.createElement("div");
row.className = "row";
row.innerHTML = `<input type="checkbox"><span>${i}</span><button>x</button>`;
app.appendChild(row);
}
input.focus();
input.offsetWidth;
// Performance test: setting input.value must not synchronously trigger a full layout.
const values = ["a", "ab"];
const start = performance.now();
for (let i = 0; i < 2000; i++) {
app.children[i % 2000].style.padding = (4 + (i % 2)) + "px";
input.value = values[i % 2];
}
const elapsed = performance.now() - start;
println(elapsed < 5000 ? "PASS" : `FAIL: took ${elapsed.toFixed(0)}ms`);
});
</script>