update
This commit is contained in:
@@ -147,6 +147,29 @@ impl RenderedFrame {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct WebViewSnapshotPending {
|
||||
has_pending_frame: bool,
|
||||
has_pending_metadata: bool,
|
||||
}
|
||||
|
||||
impl WebViewSnapshotPending {
|
||||
#[must_use]
|
||||
pub fn new(has_pending_frame: bool, has_pending_metadata: bool) -> Self {
|
||||
Self { has_pending_frame, has_pending_metadata }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn has_pending_frame(&self) -> bool {
|
||||
self.has_pending_frame
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn has_pending_metadata(&self) -> bool {
|
||||
self.has_pending_metadata
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct WebViewSnapshot {
|
||||
webview_id: WebViewId,
|
||||
@@ -155,7 +178,7 @@ pub struct WebViewSnapshot {
|
||||
state: WebViewState,
|
||||
url: Option<String>,
|
||||
title: Option<String>,
|
||||
has_pending_frame: bool,
|
||||
pending: WebViewSnapshotPending,
|
||||
}
|
||||
|
||||
impl WebViewSnapshot {
|
||||
@@ -167,9 +190,9 @@ impl WebViewSnapshot {
|
||||
state: WebViewState,
|
||||
url: Option<String>,
|
||||
title: Option<String>,
|
||||
has_pending_frame: bool,
|
||||
pending: WebViewSnapshotPending,
|
||||
) -> Self {
|
||||
Self { webview_id, tab_id, profile_id, state, url, title, has_pending_frame }
|
||||
Self { webview_id, tab_id, profile_id, state, url, title, pending }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@@ -204,7 +227,14 @@ impl WebViewSnapshot {
|
||||
|
||||
#[must_use]
|
||||
pub fn has_pending_frame(&self) -> bool {
|
||||
self.has_pending_frame
|
||||
self.pending.has_pending_frame()
|
||||
}
|
||||
|
||||
/// Returns true when URL, title, or load-state changed since the
|
||||
/// last embedder snapshot observation.
|
||||
#[must_use]
|
||||
pub fn has_pending_metadata(&self) -> bool {
|
||||
self.pending.has_pending_metadata()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ pub use host::{
|
||||
HidpiScaleRequest, KeyboardTextRequest, MouseClickRequest, MouseDragRequest, MouseHoverRequest,
|
||||
NavigationRequest, PageZoomRequest, PermissionDecision, PermissionRequest, RenderedFrame,
|
||||
RenderedFrameSummary, ResizeRequest, ScrollRequest, ServoHost, TouchTapRequest,
|
||||
WebViewSnapshot, WebViewState,
|
||||
WebViewSnapshot, WebViewSnapshotPending, WebViewState,
|
||||
};
|
||||
#[cfg(feature = "servo-engine")]
|
||||
pub use runtime::{RenderingContextKind, ServoSurfaceSize, SoftwareServoHost};
|
||||
|
||||
@@ -45,6 +45,9 @@ pub struct SoftwareServoHost {
|
||||
default_surface_size: ServoSurfaceSize,
|
||||
rendering_context_kind: RenderingContextKind,
|
||||
webviews: HashMap<WebViewId, HostWebView>,
|
||||
// Servo 0.1.0 can still run script tasks after a remote page moves away.
|
||||
// Retain hidden about:blank WebViews until host shutdown releases them together.
|
||||
retired_webviews: Vec<HostWebView>,
|
||||
permissions: PermissionStore,
|
||||
wake_requested: Arc<AtomicBool>,
|
||||
last_rendered_frame: Option<RenderedFrame>,
|
||||
@@ -120,7 +123,27 @@ impl SoftwareServoHost {
|
||||
}
|
||||
|
||||
pub fn close_webview(&mut self, webview_id: &WebViewId) -> bool {
|
||||
self.webviews.remove(webview_id).is_some()
|
||||
let Some(webview) = self.webviews.remove(webview_id) else {
|
||||
return false;
|
||||
};
|
||||
self.retire_webview(webview);
|
||||
true
|
||||
}
|
||||
|
||||
fn retire_webview(&mut self, webview: HostWebView) {
|
||||
webview.webview.hide();
|
||||
if let Ok(blank_url) = Url::parse("about:blank") {
|
||||
webview.webview.load(blank_url);
|
||||
}
|
||||
for _ in 0..32 {
|
||||
self.servo.spin_event_loop();
|
||||
if webview.current_url().as_deref() == Some("about:blank")
|
||||
&& matches!(webview.state(), WebViewState::Complete)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.retired_webviews.push(webview);
|
||||
}
|
||||
|
||||
fn new_started(
|
||||
@@ -143,6 +166,7 @@ impl SoftwareServoHost {
|
||||
default_surface_size: size,
|
||||
rendering_context_kind,
|
||||
webviews: HashMap::new(),
|
||||
retired_webviews: Vec::new(),
|
||||
permissions: Rc::new(RefCell::new(HashMap::new())),
|
||||
wake_requested,
|
||||
last_rendered_frame: None,
|
||||
@@ -190,6 +214,24 @@ impl SoftwareServoHost {
|
||||
self.last_rendered_frame = Some(rendered_frame);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the current snapshot and acknowledges metadata-only
|
||||
/// updates without clearing Servo's frame-ready signal.
|
||||
pub fn snapshot_and_mark_metadata_observed(
|
||||
&self,
|
||||
webview_id: &WebViewId,
|
||||
) -> Result<WebViewSnapshot, ServoHostError> {
|
||||
let webview = self.webview(webview_id)?;
|
||||
let snapshot = webview.snapshot(webview_id);
|
||||
webview.delegate.mark_metadata_observed();
|
||||
Ok(snapshot)
|
||||
}
|
||||
|
||||
fn drain_after_webview_close(&self) {
|
||||
for _ in 0..16 {
|
||||
self.servo.spin_event_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn install_rustls_provider() {
|
||||
@@ -395,6 +437,12 @@ impl ServoHost for SoftwareServoHost {
|
||||
|
||||
impl Drop for SoftwareServoHost {
|
||||
fn drop(&mut self) {
|
||||
let webviews = std::mem::take(&mut self.webviews);
|
||||
for webview in webviews.into_values() {
|
||||
self.retire_webview(webview);
|
||||
}
|
||||
self.retired_webviews.clear();
|
||||
self.drain_after_webview_close();
|
||||
SERVO_RUNTIME_STARTED.store(false, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use servo::{LoadStatus, RenderingContext, WebView, WebViewDelegate};
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
PermissionDecision, WebViewSnapshot, WebViewState,
|
||||
PermissionDecision, WebViewSnapshot, WebViewSnapshotPending, WebViewState,
|
||||
runtime_permissions::{PermissionStore, permission_decision_for_webview},
|
||||
};
|
||||
|
||||
@@ -27,7 +27,10 @@ impl HostWebView {
|
||||
self.state(),
|
||||
self.current_url(),
|
||||
self.current_title(),
|
||||
self.delegate.has_pending_frame(),
|
||||
WebViewSnapshotPending::new(
|
||||
self.delegate.has_pending_frame(),
|
||||
self.delegate.has_pending_metadata(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -62,6 +65,7 @@ pub(super) struct HostWebViewDelegate {
|
||||
url: RefCell<Option<String>>,
|
||||
title: RefCell<Option<String>>,
|
||||
has_pending_frame: Cell<bool>,
|
||||
has_pending_metadata: Cell<bool>,
|
||||
}
|
||||
|
||||
impl HostWebViewDelegate {
|
||||
@@ -73,6 +77,7 @@ impl HostWebViewDelegate {
|
||||
url: RefCell::new(None),
|
||||
title: RefCell::new(None),
|
||||
has_pending_frame: Cell::new(false),
|
||||
has_pending_metadata: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,12 +99,12 @@ impl HostWebViewDelegate {
|
||||
|
||||
fn record_url_change(&self, url: String) {
|
||||
self.url.replace(Some(url));
|
||||
self.has_pending_frame.set(true);
|
||||
self.has_pending_metadata.set(true);
|
||||
}
|
||||
|
||||
fn record_title_change(&self, title: Option<String>) {
|
||||
self.title.replace(title);
|
||||
self.has_pending_frame.set(true);
|
||||
self.has_pending_metadata.set(true);
|
||||
}
|
||||
|
||||
fn record_load_status(&self, status: LoadStatus) {
|
||||
@@ -108,16 +113,24 @@ impl HostWebViewDelegate {
|
||||
LoadStatus::Complete => WebViewState::Complete,
|
||||
};
|
||||
self.set_state(state);
|
||||
self.has_pending_frame.set(true);
|
||||
self.has_pending_metadata.set(true);
|
||||
}
|
||||
|
||||
pub(super) fn has_pending_frame(&self) -> bool {
|
||||
self.has_pending_frame.get()
|
||||
}
|
||||
|
||||
pub(super) fn has_pending_metadata(&self) -> bool {
|
||||
self.has_pending_metadata.get()
|
||||
}
|
||||
|
||||
pub(super) fn mark_frame_presented(&self) {
|
||||
self.has_pending_frame.set(false);
|
||||
}
|
||||
|
||||
pub(super) fn mark_metadata_observed(&self) {
|
||||
self.has_pending_metadata.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
impl WebViewDelegate for HostWebViewDelegate {
|
||||
@@ -172,21 +185,25 @@ mod tests {
|
||||
use super::HostWebViewDelegate;
|
||||
|
||||
#[test]
|
||||
fn metadata_changes_mark_pending_frame() {
|
||||
fn metadata_changes_are_separate_from_pending_frame() {
|
||||
let delegate =
|
||||
HostWebViewDelegate::new(ProfileId::new(), Rc::new(RefCell::new(HashMap::new())));
|
||||
|
||||
assert!(!delegate.has_pending_frame());
|
||||
assert!(!delegate.has_pending_metadata());
|
||||
|
||||
delegate.record_title_change(Some("Example Domain".to_string()));
|
||||
assert_eq!(delegate.title().as_deref(), Some("Example Domain"));
|
||||
assert!(delegate.has_pending_frame());
|
||||
|
||||
delegate.mark_frame_presented();
|
||||
assert!(!delegate.has_pending_frame());
|
||||
assert!(delegate.has_pending_metadata());
|
||||
|
||||
delegate.mark_metadata_observed();
|
||||
assert!(!delegate.has_pending_frame());
|
||||
assert!(!delegate.has_pending_metadata());
|
||||
|
||||
delegate.record_url_change("https://example.com/".to_string());
|
||||
assert_eq!(delegate.url().as_deref(), Some("https://example.com/"));
|
||||
assert!(delegate.has_pending_frame());
|
||||
assert!(!delegate.has_pending_frame());
|
||||
assert!(delegate.has_pending_metadata());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user