Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE html>
<html>
<meta charset=utf-8 />
<title>Event Timing: keydown entry dispatched without a repaint.</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/resources/testdriver.js></script>
<script src=/resources/testdriver-actions.js></script>
<script src=/resources/testdriver-vendor.js></script>
<script src=resources/event-timing-test-utils.js></script>
<div id='target' tabindex=0>key target</div>
<script>
// When a key is held on a static page with no pending repaints, keydown
// timing entries must still be dispatched promptly via a posted task
// rather than waiting indefinitely for a paint that may never come.
// Without the fix, entries would only be flushed when some unrelated
// activity (e.g. mouse movement) triggered a repaint, causing durations
// inflated to the total key-hold time.
promise_test(async t => {
const entries = [];
new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
if (entry.name === 'keydown') entries.push(entry);
}
}).observe({type: 'event', durationThreshold: 16});
const target = document.getElementById('target');
target.focus();
// Wait for any focus-related repaint and for the browser to go idle.
// afterNextPaint() resolves from a setTimeout inside a rAF callback, so
// the rendering pipeline may still be scheduled for one or two more
// vsyncs at that point; the extra delay lets painting settle before
// sending the key.
await afterNextPaint();
await new Promise(resolve => t.step_timeout(resolve, 100));
// Block every keydown long enough that each entry exceeds the 16ms
// observation threshold, without involving any DOM changes that would
// schedule a repaint.
target.addEventListener('keydown', () => mainThreadBusy(30));
const keyDownHandled = new Promise(resolve => {
let keyDownCount = 0;
target.addEventListener('keydown', () => {
if (++keyDownCount === 2) {
resolve();
}
}, { capture: true });
});
await new test_driver.Actions()
.keyDown('a')
.keyDown('a')
.send();
await keyDownHandled;
// The entry must be dispatched via a posted task, without requiring a
// repaint. step_wait will fail if no entry arrives within the timeout.
await t.step_wait(() => entries.length === 2,
'keydown timing entry should be dispatched without a repaint');
assert_equals(entries.length, 2, 'two keydown entries');
// Duration should reflect only the processing time (~30ms), not the full
// key-hold duration.
assert_less_than(entries[0].duration, 60,
'duration must not be inflated to the key-hold duration');
assert_less_than(entries[1].duration, 60,
'duration must not be inflated to the key-hold duration');
}, 'keydown timing entry is dispatched without a repaint');
</script>
</html>