Sidebar / window-edge animations emit a new viewport bounds on every
GPUI paint. The previous flow fired `runtime.ensure_tab` synchronously
on every change, which reached down into Servo's surfman backend and
destroyed + reallocated the rendering framebuffer 50+ times per second
— each cycle leaving the NSView with an empty surface until Servo's
next paint completed. The user saw the page strobe blank-then-content
on every gesture, plus a one-time Metal driver warning about an
unloadable texture (the previous framebuffer caught mid-recreate).
Track `viewport_size_changed_at` on `PerTabSurface` and propagate the
debounce on two seams:
- `record_viewport_size` returns `Buffered` for a transition that
arrives inside the 80 ms window of the previous one, so the
synchronous `flush_external_web_surface_tick` from the GPUI paint
callback skips the resize altogether. The very first measurement
and the first transition after a quiet period still return `Applied`
so a single drag step or page-load is not delayed.
- `ensure_surface` skips while the viewport is settling, but only
*after* the initial ensure has installed `last_ensure_key`. The
first ensure must fire even mid-gesture or the page never loads.
- `next_tick_delay` clamps the poll cadence to `ACTIVE_POLL_INTERVAL`
while any visible tab is settling, so the trailing-edge resize
fires within a frame of the gesture stopping instead of waiting
for an 80 ms idle tick.
The synchronous `record + ensure` pattern in
`failed_surface_ensure_waits_for_a_new_key_before_retrying` can't
advance an `Instant`, so it now calls a `#[cfg(test)]`
`clear_viewport_resize_debounce_for_test` to simulate the
trailing edge and exercise the retry-on-new-key business rule in
isolation. Adds `rapid_viewport_changes_buffer_until_gesture_settles`
to lock the new behaviour.