Add preference observer API for runtime webxr preference changes (#38649)

Adds a global preference observer that is notified whenever any
preference value is updated. This is used to support runtime
configuration of WebXR automated testing, which is a prerequisite for
running multiple WPT tests in a single browser session.

Testing: Ran `./mach test-wpt /webxr --product=servodriver`
Fixes: #38647

---------

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
Josh Matthews 2025-08-16 04:49:13 -04:00 committed by GitHub
parent fc3feceee5
commit f19b2f6e84
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 63 additions and 6 deletions

View file

@ -34,6 +34,12 @@ fn servo_preferences_derive(input: synstructure::Structure) -> TokenStream {
set_match_cases.extend(quote!(stringify!(#name) => self.#name = value.try_into().unwrap(),))
}
let mut comparisons = quote!();
for field in named_fields.named.iter() {
let name = field.ident.as_ref().unwrap();
comparisons.extend(quote!(if self.#name != other.#name { changes.push((stringify!(#name), self.#name.clone().into(),)) }))
}
let structure_name = &ast.ident;
quote! {
impl #structure_name {
@ -50,6 +56,12 @@ fn servo_preferences_derive(input: synstructure::Structure) -> TokenStream {
_ => { panic!("Unknown preference: {:?}", name); }
}
}
pub fn diff(&self, other: &Self) -> Vec<(&'static str, PrefValue)> {
let mut changes = vec![];
#comparisons
changes
}
}
}
}

View file

@ -11,12 +11,22 @@ pub use crate::pref_util::PrefValue;
static PREFERENCES: RwLock<Preferences> = RwLock::new(Preferences::const_default());
pub trait Observer: Send + Sync {
fn prefs_changed(&self, _changes: Vec<(&'static str, PrefValue)>) {}
}
static OBSERVER: RwLock<Option<Box<dyn Observer>>> = RwLock::new(None);
#[inline]
/// Get the current set of global preferences for Servo.
pub fn get() -> RwLockReadGuard<'static, Preferences> {
PREFERENCES.read().unwrap()
}
pub fn set_observer(observer: Box<dyn Observer>) {
*OBSERVER.write().unwrap() = Some(observer);
}
pub fn set(preferences: Preferences) {
// Map between Stylo preference names and Servo preference names as the This should be
// kept in sync with components/script/dom/bindings/codegen/run.py which generates the
@ -39,7 +49,13 @@ pub fn set(preferences: Preferences) {
preferences.layout_container_queries_enabled,
);
let changed = preferences.diff(&PREFERENCES.read().unwrap());
*PREFERENCES.write().unwrap() = preferences;
if let Some(observer) = OBSERVER.read().unwrap().as_deref() {
observer.prefs_changed(changed);
}
}
/// A convenience macro for accessing a preference value using its static path.