mirror of
https://github.com/servo/servo.git
synced 2025-08-11 00:15:32 +01:00
libservo: Rework and clarify the rendering model of the WebView
(#35522)
Make the rendering model of the `WebView` clearer: 1. `WebViewDelegate::notify_new_frame_ready()` indicates that the WebView has become dirty and needs to be repainted. 2. `WebView::paint()` asks Servo to paint the contents of the `WebView` into the `RenderingContext`. 3. `RenderingContext::present()` does a buffer swap if the `RenderingContext` is actually double-buffered. This is documented and all in-tree embedders are updated to work with this new model. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Ngo Iok Ui (Wu Yu Wei) <yuweiwu@pm.me> Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
This commit is contained in:
parent
56840e0a35
commit
e5c9a0365d
10 changed files with 129 additions and 160 deletions
|
@ -58,7 +58,6 @@ pub(crate) enum PumpResult {
|
|||
Shutdown,
|
||||
Continue {
|
||||
need_update: bool,
|
||||
new_servo_frame: bool,
|
||||
need_window_redraw: bool,
|
||||
},
|
||||
}
|
||||
|
@ -195,23 +194,15 @@ impl App {
|
|||
},
|
||||
PumpResult::Continue {
|
||||
need_update: update,
|
||||
new_servo_frame,
|
||||
need_window_redraw,
|
||||
} => {
|
||||
// A new Servo frame is ready, so swap the buffer on our `RenderingContext`. In headed mode
|
||||
// this won't immediately update the widget surface, because we render to an offscreen
|
||||
// `RenderingContext`.
|
||||
if new_servo_frame {
|
||||
state.servo().present();
|
||||
}
|
||||
|
||||
let updated = match (update, &mut self.minibrowser) {
|
||||
(true, Some(minibrowser)) => minibrowser.update_webview_data(state),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
// If in headed mode, request a winit redraw event, so we can paint the minibrowser.
|
||||
if updated || need_window_redraw || new_servo_frame {
|
||||
if updated || need_window_redraw {
|
||||
if let Some(window) = window.winit_window() {
|
||||
window.request_redraw();
|
||||
}
|
||||
|
@ -247,14 +238,7 @@ impl App {
|
|||
state.shutdown();
|
||||
self.state = AppState::ShuttingDown;
|
||||
},
|
||||
PumpResult::Continue {
|
||||
new_servo_frame, ..
|
||||
} => {
|
||||
if new_servo_frame {
|
||||
// In headless mode, we present directly.
|
||||
state.servo().present();
|
||||
}
|
||||
},
|
||||
PumpResult::Continue { .. } => state.repaint_servo_if_necessary(),
|
||||
}
|
||||
|
||||
!matches!(self.state, AppState::ShuttingDown)
|
||||
|
|
|
@ -73,8 +73,9 @@ pub struct RunningAppStateInner {
|
|||
/// Whether or not the application interface needs to be updated.
|
||||
need_update: bool,
|
||||
|
||||
/// Whether or not the application needs to be redrawn.
|
||||
new_servo_frame_ready: bool,
|
||||
/// Whether or not Servo needs to repaint its display. Currently this is global
|
||||
/// because every `WebView` shares a `RenderingContext`.
|
||||
need_repaint: bool,
|
||||
}
|
||||
|
||||
impl Drop for RunningAppState {
|
||||
|
@ -101,7 +102,7 @@ impl RunningAppState {
|
|||
window,
|
||||
gamepad_support: GamepadSupport::maybe_new(),
|
||||
need_update: false,
|
||||
new_servo_frame_ready: false,
|
||||
need_repaint: false,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +125,19 @@ impl RunningAppState {
|
|||
&self.servo
|
||||
}
|
||||
|
||||
pub(crate) fn repaint_servo_if_necessary(&self) {
|
||||
if !self.inner().need_repaint {
|
||||
return;
|
||||
}
|
||||
let Some(webview) = self.focused_webview() else {
|
||||
return;
|
||||
};
|
||||
|
||||
webview.paint();
|
||||
self.inner().window.rendering_context().present();
|
||||
self.inner_mut().need_repaint = false;
|
||||
}
|
||||
|
||||
/// Spins the internal application event loop.
|
||||
///
|
||||
/// - Notifies Servo about incoming gamepad events
|
||||
|
@ -138,15 +152,12 @@ impl RunningAppState {
|
|||
}
|
||||
|
||||
// Delegate handlers may have asked us to present or update compositor contents.
|
||||
let new_servo_frame = std::mem::replace(&mut self.inner_mut().new_servo_frame_ready, false);
|
||||
let need_update = std::mem::replace(&mut self.inner_mut().need_update, false);
|
||||
|
||||
// Currently, egui-file-dialog dialogs need to be constantly redrawn or animations aren't fluid.
|
||||
let need_window_redraw = new_servo_frame || self.has_active_dialog();
|
||||
let need_window_redraw = self.inner().need_repaint || self.has_active_dialog();
|
||||
let need_update = std::mem::replace(&mut self.inner_mut().need_update, false);
|
||||
|
||||
PumpResult::Continue {
|
||||
need_update,
|
||||
new_servo_frame,
|
||||
need_window_redraw,
|
||||
}
|
||||
}
|
||||
|
@ -484,7 +495,7 @@ impl WebViewDelegate for RunningAppState {
|
|||
}
|
||||
|
||||
fn notify_new_frame_ready(&self, _webview: servo::WebView) {
|
||||
self.inner_mut().new_servo_frame_ready = true;
|
||||
self.inner_mut().need_repaint = true;
|
||||
}
|
||||
|
||||
fn play_gamepad_haptic_effect(
|
||||
|
|
|
@ -403,6 +403,8 @@ impl Minibrowser {
|
|||
);
|
||||
}
|
||||
|
||||
state.repaint_servo_if_necessary();
|
||||
|
||||
if let Some(render_to_parent) = rendering_context.render_to_parent_callback() {
|
||||
ui.painter().add(PaintCallback {
|
||||
rect,
|
||||
|
|
|
@ -680,8 +680,8 @@ impl RunningAppState {
|
|||
pub fn present_if_needed(&self) {
|
||||
if self.inner().need_present {
|
||||
self.inner_mut().need_present = false;
|
||||
self.active_webview().paint_immediately();
|
||||
self.servo.present();
|
||||
self.active_webview().paint();
|
||||
self.rendering_context.present();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue