Skip to content

Commit

Permalink
Ignore presentation time if visibility changed, for Event Timing
Browse files Browse the repository at this point in the history
EventTiming registers for presentation feedback times for events which
are expected to have a visual update.  However, if page visibility
changes, that can affect the time it takes to present the next paint
update.

We were already ignoring the time to next paint portion for UKM
reporting of interactions, but now we also ignore this time for Event
Timing reporting to Web Performance timeline.

Filed a spec issue with EventTiming API to clarify cases where events
will not have a next paint:
w3c/event-timing#123

Also, we will follow-up to see if it is not desirable to measure all the
way until visibility change, as per:
w3c/event-timing#129

Bug: 1312568
Change-Id: Iee0b5eee81fb216a96ecbfcc41ca26601ab6ba1b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3926369
Commit-Queue: Michal Mocny <[email protected]>
Auto-Submit: Michal Mocny <[email protected]>
Reviewed-by: Noam Rosenthal <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1093452}
  • Loading branch information
Michal Mocny authored and chromium-wpt-export-bot committed Jan 17, 2023
1 parent 4e62159 commit ac2138e
Showing 1 changed file with 98 additions and 0 deletions.
98 changes: 98 additions & 0 deletions event-timing/event-click-visibilitychange.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<!DOCTYPE html>
<html>
<meta charset=utf-8 />
<meta name="timeout" content="long">
<title>Event Timing: eventCounts.</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/resources/testdriver.js></script>
<script src=/resources/testdriver-vendor.js></script>
<script src=/resources/testdriver-actions.js></script>
<script src=/page-visibility/resources/window_state_context.js></script>
<script src=resources/event-timing-test-utils.js></script>

<body>
<button id='target'>Click me</button>

<script>
let observedEntries = [];
const map = new Map();
const events = ['pointerdown'];

promise_test(async t => {
assert_implements(window.PerformanceEventTiming, 'Event Timing is not supported.');

const { minimize, restore } = window_state_context(t);
const button = document.getElementById('target');

const callback = (entryList) => { observedEntries = observedEntries.concat(entryList.getEntries().filter(filterAndAddToMap(events, map))); };
const readyToResolve = () => { return observedEntries.length >= 1; };
const observerPromise = createPerformanceObserverPromise(['event'], callback, readyToResolve);

const tapEventPromise = new Promise(resolve => {
button.addEventListener('pointerdown', async (event) => {
document.body.innerText += "Adding content to force rendering";

// await here will yield to event loop, and end event processing time,
// which will allow rendering to continue.
// The visibility change may happen before rendering has a chance
// but it is not guarenteed which will happen first.
await minimize();
const timeAfterVisibilityFalse = performance.now();

await restore();
const timeAfterVisibilityTrue = performance.now();

resolve({ timeAfterVisibilityFalse, timeAfterVisibilityTrue });
});
});

// A buffered visibility-state PerformanceEntry would have made this test
// cleaner, due to the variability of ordering of events, but it is not
// yet available.
const visibilityEventPromise = new Promise(resolve => {
document.addEventListener('visibilitychange', (event) => {
if (document.visibilityState !== 'visible') {
resolve(performance.now());
}
});
});

const timeBeforeTap = performance.now();
await interactAndObserve('tap', button, observerPromise);

// The order that these events fire is non-deterministic, but we can await
// the result of the promise in any order.
const { timeAfterVisibilityFalse, timeAfterVisibilityTrue } = await tapEventPromise;
const timeOfVisibilityFalse = await visibilityEventPromise;

assert_equals(observedEntries.length, 1, "Pointerdown was measured");
const entry = observedEntries[0];

assert_not_equals(timeBeforeTap, undefined);
assert_not_equals(timeAfterVisibilityFalse, undefined);
assert_not_equals(timeAfterVisibilityTrue, undefined);
assert_not_equals(timeOfVisibilityFalse, undefined);

assert_less_than(
entry.processingEnd,
timeOfVisibilityFalse,
"event handler ends before visibility event fires"
);
assert_less_than(
timeOfVisibilityFalse,
timeAfterVisibilityFalse,
"visibility event fires before event handler continues"
);
assert_less_than_equal(
entry.startTime + entry.duration,
timeAfterVisibilityFalse,
"event duration ends before visibility is changed"
);

}, "Event handlers which change visibility should not measure next paint.");

</script>
</body>

</html>

0 comments on commit ac2138e

Please sign in to comment.