Stop the web surface from strobing on transient errors
Two paths in `WebSurfaceStore::tick` were downgrading a perfectly good Ready frame back to Failed / Loading on every transient hiccup: - `WebSurfaceRuntimeFrame::Failed` overwrote the surface state unconditionally. Combined with the 125 Hz tick (which submits a Poll for every visible tab and any transient ensure / poll error becomes a Failed response), even one parse glitch wiped the rendered page. - The `initial_display_gate_message` and `should_hold_initial_frame` checks for incoming Ready frames hardcoded `has_previous_frame = false`, so a stray empty paint pass after the page had already rendered would knock the surface back to Loading or Failed. Detect whether the surface already has a `Ready(_)` state and: - ignore Failed responses (logging through `tracing` for diagnostics) while a real frame is on screen; - pass that "had ready" signal into the gate / hold checks so they only apply to the very first paint, not later refreshes. The page now stays put even when Servo emits a momentary error; only the first-paint failure path can mark the surface Failed.
This commit is contained in:
@@ -118,21 +118,34 @@ impl WebSurfaceStore {
|
||||
for frame in frames {
|
||||
match frame {
|
||||
WebSurfaceRuntimeFrame::Ready { tab_id, frame, url_change } => {
|
||||
match self.initial_display_gate_message(&tab_id, &frame, false) {
|
||||
let had_ready = matches!(
|
||||
self.surfaces.get(&tab_id).and_then(|surface| surface.state.as_ref()),
|
||||
Some(WebSurfaceState::Ready(_))
|
||||
);
|
||||
match self.initial_display_gate_message(&tab_id, &frame, had_ready) {
|
||||
Ok(()) => {}
|
||||
Err(message) => {
|
||||
// Only transition to Failed when there is
|
||||
// nothing on screen yet — once a real frame
|
||||
// has rendered, transient gate failures
|
||||
// (e.g. a stray empty-paint pass) must not
|
||||
// wipe it out.
|
||||
if !had_ready {
|
||||
self.surface_mut(&tab_id).state =
|
||||
Some(WebSurfaceState::Failed { message });
|
||||
result.changed = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if self.should_hold_initial_frame(&tab_id, &frame, false) {
|
||||
if self.should_hold_initial_frame(&tab_id, &frame, had_ready) {
|
||||
if !had_ready {
|
||||
self.surface_mut(&tab_id).state = Some(WebSurfaceState::Loading {
|
||||
requested_url: frame.requested_url.clone(),
|
||||
previous_frame: None,
|
||||
});
|
||||
result.changed = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if let Some(metadata) = WebSurfacePageMetadata::from_frame(&tab_id, &frame) {
|
||||
@@ -145,6 +158,25 @@ impl WebSurfaceStore {
|
||||
}
|
||||
}
|
||||
WebSurfaceRuntimeFrame::Failed { tab_id, message } => {
|
||||
let had_ready = matches!(
|
||||
self.surfaces.get(&tab_id).and_then(|surface| surface.state.as_ref()),
|
||||
Some(WebSurfaceState::Ready(_))
|
||||
);
|
||||
if had_ready {
|
||||
// Keep the last good frame on screen — the
|
||||
// worker emits Failed for any transient ensure
|
||||
// / poll error (parse glitch, momentary IPC
|
||||
// hiccup) and downgrading every one of them
|
||||
// strobes the page. The error still surfaces
|
||||
// through `tracing` for diagnostics.
|
||||
tracing::warn!(
|
||||
target: "ely::web_surface",
|
||||
tab_id = %tab_id,
|
||||
message = %message,
|
||||
"transient surface error; keeping last frame",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
self.surface_mut(&tab_id).state = Some(WebSurfaceState::Failed { message });
|
||||
result.changed = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user