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 {
|
for frame in frames {
|
||||||
match frame {
|
match frame {
|
||||||
WebSurfaceRuntimeFrame::Ready { tab_id, frame, url_change } => {
|
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(()) => {}
|
Ok(()) => {}
|
||||||
Err(message) => {
|
Err(message) => {
|
||||||
self.surface_mut(&tab_id).state =
|
// Only transition to Failed when there is
|
||||||
Some(WebSurfaceState::Failed { message });
|
// nothing on screen yet — once a real frame
|
||||||
result.changed = true;
|
// 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;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.should_hold_initial_frame(&tab_id, &frame, false) {
|
if self.should_hold_initial_frame(&tab_id, &frame, had_ready) {
|
||||||
self.surface_mut(&tab_id).state = Some(WebSurfaceState::Loading {
|
if !had_ready {
|
||||||
requested_url: frame.requested_url.clone(),
|
self.surface_mut(&tab_id).state = Some(WebSurfaceState::Loading {
|
||||||
previous_frame: None,
|
requested_url: frame.requested_url.clone(),
|
||||||
});
|
previous_frame: None,
|
||||||
result.changed = true;
|
});
|
||||||
|
result.changed = true;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(metadata) = WebSurfacePageMetadata::from_frame(&tab_id, &frame) {
|
if let Some(metadata) = WebSurfacePageMetadata::from_frame(&tab_id, &frame) {
|
||||||
@@ -145,6 +158,25 @@ impl WebSurfaceStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
WebSurfaceRuntimeFrame::Failed { tab_id, message } => {
|
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 });
|
self.surface_mut(&tab_id).state = Some(WebSurfaceState::Failed { message });
|
||||||
result.changed = true;
|
result.changed = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user