1use std::sync::{RwLock, RwLockReadGuard};
6
7use serde::{Deserialize, Serialize};
8use servo_config_macro::ServoPreferences;
9
10pub use crate::pref_util::PrefValue;
11
12static PREFERENCES: RwLock<Preferences> = RwLock::new(Preferences::const_default());
13
14pub trait Observer: Send + Sync {
15 fn prefs_changed(&self, _changes: &[(&'static str, PrefValue)]) {}
16}
17
18static OBSERVERS: RwLock<Vec<Box<dyn Observer>>> = RwLock::new(Vec::new());
19
20#[inline]
21pub fn get() -> RwLockReadGuard<'static, Preferences> {
23 PREFERENCES.read().unwrap()
24}
25
26pub fn add_observer(observer: Box<dyn Observer>) {
27 OBSERVERS.write().unwrap().push(observer);
28}
29
30pub fn set(preferences: Preferences) {
31 stylo_config::set_bool("layout.unimplemented", preferences.layout_unimplemented);
35 stylo_config::set_i32("layout.threads", preferences.layout_threads as i32);
36 stylo_config::set_bool("layout.flexbox.enabled", preferences.layout_flexbox_enabled);
37 stylo_config::set_bool("layout.columns.enabled", preferences.layout_columns_enabled);
38 stylo_config::set_bool("layout.grid.enabled", preferences.layout_grid_enabled);
39 stylo_config::set_bool(
40 "layout.css.transition-behavior.enabled",
41 preferences.layout_css_transition_behavior_enabled,
42 );
43 stylo_config::set_bool(
44 "layout.writing-mode.enabled",
45 preferences.layout_writing_mode_enabled,
46 );
47 stylo_config::set_bool(
48 "layout.container-queries.enabled",
49 preferences.layout_container_queries_enabled,
50 );
51 stylo_config::set_bool(
52 "layout.variable_fonts.enabled",
53 preferences.layout_variable_fonts_enabled,
54 );
55
56 let changed = preferences.diff(&PREFERENCES.read().unwrap());
57
58 *PREFERENCES.write().unwrap() = preferences;
59
60 for observer in &*OBSERVERS.read().unwrap() {
61 observer.prefs_changed(&changed);
62 }
63}
64
65#[macro_export]
68macro_rules! pref {
69 ($name: ident) => {
70 $crate::prefs::get().$name.clone()
71 };
72}
73
74#[derive(Clone, Deserialize, Serialize, ServoPreferences)]
75pub struct Preferences {
76 pub fonts_default: String,
77 pub fonts_serif: String,
78 pub fonts_sans_serif: String,
79 pub fonts_monospace: String,
80 pub fonts_default_size: i64,
81 pub fonts_default_monospace_size: i64,
82 pub css_animations_testing_enabled: bool,
83 pub devtools_server_enabled: bool,
85 pub devtools_server_port: i64,
88 pub dom_webgpu_enabled: bool,
89 pub dom_webgpu_wgpu_backend: String,
91 pub dom_abort_controller_enabled: bool,
92 pub dom_adoptedstylesheet_enabled: bool,
93 pub dom_async_clipboard_enabled: bool,
94 pub dom_bluetooth_enabled: bool,
95 pub dom_bluetooth_testing_enabled: bool,
96 pub dom_allow_scripts_to_close_windows: bool,
97 pub dom_canvas_capture_enabled: bool,
98 pub dom_canvas_text_enabled: bool,
99 pub dom_canvas_backend: String,
106 pub dom_clipboardevent_enabled: bool,
107 pub dom_composition_event_enabled: bool,
108 pub dom_cookiestore_enabled: bool,
109 pub dom_credential_management_enabled: bool,
110 pub dom_crypto_subtle_enabled: bool,
111 pub dom_customelements_enabled: bool,
112 pub dom_document_dblclick_timeout: i64,
113 pub dom_document_dblclick_dist: i64,
114 pub dom_fontface_enabled: bool,
115 pub dom_fullscreen_test: bool,
116 pub dom_gamepad_enabled: bool,
117 pub dom_geolocation_enabled: bool,
118 pub dom_indexeddb_enabled: bool,
119 pub dom_intersection_observer_enabled: bool,
120 pub dom_microdata_testing_enabled: bool,
121 pub dom_mouse_event_which_enabled: bool,
122 pub dom_mutation_observer_enabled: bool,
123 pub dom_navigator_sendbeacon_enabled: bool,
124 pub dom_notification_enabled: bool,
125 pub dom_offscreen_canvas_enabled: bool,
126 pub dom_permissions_enabled: bool,
127 pub dom_permissions_testing_allowed_in_nonsecure_contexts: bool,
128 pub dom_resize_observer_enabled: bool,
129 pub dom_script_asynch: bool,
130 pub dom_serviceworker_enabled: bool,
131 pub dom_serviceworker_timeout_seconds: i64,
132 pub dom_servo_helpers_enabled: bool,
133 pub dom_servoparser_async_html_tokenizer_enabled: bool,
134 pub dom_testable_crash_enabled: bool,
135 pub dom_testbinding_enabled: bool,
136 pub dom_testbinding_prefcontrolled_enabled: bool,
137 pub dom_testbinding_prefcontrolled2_enabled: bool,
138 pub dom_testbinding_preference_value_falsy: bool,
139 pub dom_testbinding_preference_value_quote_string_test: String,
140 pub dom_testbinding_preference_value_space_string_test: String,
141 pub dom_testbinding_preference_value_string_empty: String,
142 pub dom_testbinding_preference_value_string_test: String,
143 pub dom_testbinding_preference_value_truthy: bool,
144 pub dom_testing_element_activation_enabled: bool,
145 pub dom_testing_html_input_element_select_files_enabled: bool,
146 pub dom_testperf_enabled: bool,
147 pub dom_testutils_enabled: bool,
149 pub dom_xpath_enabled: bool,
150 pub dom_webgl2_enabled: bool,
152 pub dom_webrtc_enabled: bool,
153 pub dom_webrtc_transceiver_enabled: bool,
154 pub dom_webvtt_enabled: bool,
155 pub dom_webxr_enabled: bool,
156 pub dom_webxr_test: bool,
157 pub dom_webxr_first_person_observer_view: bool,
158 pub dom_webxr_glwindow_enabled: bool,
159 pub dom_webxr_glwindow_left_right: bool,
160 pub dom_webxr_glwindow_red_cyan: bool,
161 pub dom_webxr_glwindow_spherical: bool,
162 pub dom_webxr_glwindow_cubemap: bool,
163 pub dom_webxr_hands_enabled: bool,
164 pub dom_webxr_layers_enabled: bool,
165 pub dom_webxr_openxr_enabled: bool,
166 pub dom_webxr_sessionavailable: bool,
167 pub dom_webxr_unsafe_assume_user_intent: bool,
168 pub dom_worklet_enabled: bool,
169 pub dom_worklet_blockingsleep: bool,
170 pub dom_worklet_testing_enabled: bool,
171 pub dom_worklet_timeout_ms: i64,
172 pub gfx_precache_shaders: bool,
176 pub gfx_text_antialiasing_enabled: bool,
178 pub gfx_subpixel_text_antialiasing_enabled: bool,
180 pub gfx_texture_swizzling_enabled: bool,
181 pub image_key_batch_size: i64,
183 pub inspector_show_servo_internal_shadow_roots: bool,
185 pub js_asmjs_enabled: bool,
186 pub js_asyncstack: bool,
187 pub js_baseline_interpreter_enabled: bool,
188 pub js_disable_jit: bool,
190 pub js_baseline_jit_enabled: bool,
191 pub js_baseline_jit_unsafe_eager_compilation_enabled: bool,
192 pub js_discard_system_source: bool,
193 pub js_dump_stack_on_debuggee_would_run: bool,
194 pub js_ion_enabled: bool,
195 pub js_ion_offthread_compilation_enabled: bool,
196 pub js_ion_unsafe_eager_compilation_enabled: bool,
197 pub js_mem_gc_allocation_threshold_mb: i64,
198 pub js_mem_gc_allocation_threshold_factor: i64,
199 pub js_mem_gc_allocation_threshold_avoid_interrupt_factor: i64,
200 pub js_mem_gc_compacting_enabled: bool,
201 pub js_mem_gc_decommit_threshold_mb: i64,
202 pub js_mem_gc_dynamic_heap_growth_enabled: bool,
203 pub js_mem_gc_dynamic_mark_slice_enabled: bool,
204 pub js_mem_gc_empty_chunk_count_min: i64,
205 pub js_mem_gc_high_frequency_heap_growth_max: i64,
206 pub js_mem_gc_high_frequency_heap_growth_min: i64,
207 pub js_mem_gc_high_frequency_high_limit_mb: i64,
208 pub js_mem_gc_high_frequency_low_limit_mb: i64,
209 pub js_mem_gc_high_frequency_time_limit_ms: i64,
210 pub js_mem_gc_incremental_enabled: bool,
211 pub js_mem_gc_incremental_slice_ms: i64,
212 pub js_mem_gc_low_frequency_heap_growth: i64,
213 pub js_mem_gc_per_zone_enabled: bool,
214 pub js_mem_gc_zeal_frequency: i64,
215 pub js_mem_gc_zeal_level: i64,
216 pub js_mem_max: i64,
217 pub js_native_regex_enabled: bool,
218 pub js_offthread_compilation_enabled: bool,
219 pub js_shared_memory: bool,
220 pub js_throw_on_asmjs_validation_failure: bool,
221 pub js_throw_on_debuggee_would_run: bool,
222 pub js_timers_minimum_duration: i64,
223 pub js_wasm_baseline_enabled: bool,
224 pub js_wasm_enabled: bool,
225 pub js_wasm_ion_enabled: bool,
226 pub js_werror_enabled: bool,
227 pub layout_animations_test_enabled: bool,
228 pub layout_columns_enabled: bool,
229 pub layout_grid_enabled: bool,
230 pub layout_container_queries_enabled: bool,
231 pub layout_css_transition_behavior_enabled: bool,
232 pub layout_flexbox_enabled: bool,
233 pub layout_threads: i64,
234 pub layout_unimplemented: bool,
235 pub layout_variable_fonts_enabled: bool,
236 pub layout_writing_mode_enabled: bool,
237 pub media_glvideo_enabled: bool,
239 pub media_testing_enabled: bool,
241 pub network_enforce_tls_enabled: bool,
242 pub network_enforce_tls_localhost: bool,
243 pub network_enforce_tls_onion: bool,
244 pub network_http_cache_disabled: bool,
245 pub network_local_directory_listing_enabled: bool,
246 pub network_mime_sniff: bool,
247 pub session_history_max_length: i64,
248 pub shell_background_color_rgba: [f64; 4],
250 pub webgl_testing_context_creation_error: bool,
251 pub threadpools_fallback_worker_num: i64,
254 pub threadpools_image_cache_workers_max: i64,
256 pub threadpools_indexeddb_workers_max: i64,
258 pub threadpools_webstorage_workers_max: i64,
260 pub threadpools_async_runtime_workers_max: i64,
262 pub threadpools_resource_workers_max: i64,
264 pub threadpools_webrender_workers_max: i64,
266 pub user_agent: String,
269 pub viewport_meta_enabled: bool,
271 pub log_filter: String,
272}
273
274impl Preferences {
275 const fn const_default() -> Self {
276 Self {
277 css_animations_testing_enabled: false,
278 devtools_server_enabled: false,
279 devtools_server_port: 0,
280 dom_abort_controller_enabled: false,
281 dom_adoptedstylesheet_enabled: false,
282 dom_allow_scripts_to_close_windows: false,
283 dom_async_clipboard_enabled: false,
284 dom_bluetooth_enabled: false,
285 dom_bluetooth_testing_enabled: false,
286 dom_canvas_capture_enabled: false,
287 dom_canvas_text_enabled: true,
288 dom_canvas_backend: String::new(),
289 dom_clipboardevent_enabled: true,
290 dom_composition_event_enabled: false,
291 dom_cookiestore_enabled: false,
292 dom_credential_management_enabled: false,
293 dom_crypto_subtle_enabled: true,
294 dom_customelements_enabled: true,
295 dom_document_dblclick_dist: 1,
296 dom_document_dblclick_timeout: 300,
297 dom_fontface_enabled: false,
298 dom_fullscreen_test: false,
299 dom_gamepad_enabled: true,
300 dom_geolocation_enabled: false,
301 dom_indexeddb_enabled: false,
302 dom_intersection_observer_enabled: false,
303 dom_microdata_testing_enabled: false,
304 dom_mouse_event_which_enabled: false,
305 dom_mutation_observer_enabled: true,
306 dom_navigator_sendbeacon_enabled: false,
307 dom_notification_enabled: false,
308 dom_offscreen_canvas_enabled: false,
309 dom_permissions_enabled: false,
310 dom_permissions_testing_allowed_in_nonsecure_contexts: false,
311 dom_resize_observer_enabled: false,
312 dom_script_asynch: true,
313 dom_serviceworker_enabled: false,
314 dom_serviceworker_timeout_seconds: 60,
315 dom_servo_helpers_enabled: false,
316 dom_servoparser_async_html_tokenizer_enabled: false,
317 dom_testable_crash_enabled: false,
318 dom_testbinding_enabled: false,
319 dom_testbinding_prefcontrolled2_enabled: false,
320 dom_testbinding_prefcontrolled_enabled: false,
321 dom_testbinding_preference_value_falsy: false,
322 dom_testbinding_preference_value_quote_string_test: String::new(),
323 dom_testbinding_preference_value_space_string_test: String::new(),
324 dom_testbinding_preference_value_string_empty: String::new(),
325 dom_testbinding_preference_value_string_test: String::new(),
326 dom_testbinding_preference_value_truthy: false,
327 dom_testing_element_activation_enabled: false,
328 dom_testing_html_input_element_select_files_enabled: false,
329 dom_testperf_enabled: false,
330 dom_testutils_enabled: false,
331 dom_webgl2_enabled: false,
332 dom_webgpu_enabled: false,
333 dom_webgpu_wgpu_backend: String::new(),
334 dom_webrtc_enabled: false,
335 dom_webrtc_transceiver_enabled: false,
336 dom_webvtt_enabled: false,
337 dom_webxr_enabled: true,
338 dom_webxr_first_person_observer_view: false,
339 dom_webxr_glwindow_cubemap: false,
340 dom_webxr_glwindow_enabled: true,
341 dom_webxr_glwindow_left_right: false,
342 dom_webxr_glwindow_red_cyan: false,
343 dom_webxr_glwindow_spherical: false,
344 dom_webxr_hands_enabled: true,
345 dom_webxr_layers_enabled: false,
346 dom_webxr_openxr_enabled: true,
347 dom_webxr_sessionavailable: false,
348 dom_webxr_test: false,
349 dom_webxr_unsafe_assume_user_intent: false,
350 dom_worklet_blockingsleep: false,
351 dom_worklet_enabled: false,
352 dom_worklet_testing_enabled: false,
353 dom_worklet_timeout_ms: 10,
354 dom_xpath_enabled: false,
355 fonts_default: String::new(),
356 fonts_default_monospace_size: 13,
357 fonts_default_size: 16,
358 fonts_monospace: String::new(),
359 fonts_sans_serif: String::new(),
360 fonts_serif: String::new(),
361 gfx_precache_shaders: false,
362 gfx_text_antialiasing_enabled: true,
363 gfx_subpixel_text_antialiasing_enabled: true,
364 gfx_texture_swizzling_enabled: true,
365 image_key_batch_size: 10,
366 inspector_show_servo_internal_shadow_roots: false,
367 js_asmjs_enabled: true,
368 js_asyncstack: false,
369 js_baseline_interpreter_enabled: true,
370 js_baseline_jit_enabled: true,
371 js_baseline_jit_unsafe_eager_compilation_enabled: false,
372 js_disable_jit: false,
373 js_discard_system_source: false,
374 js_dump_stack_on_debuggee_would_run: false,
375 js_ion_enabled: true,
376 js_ion_offthread_compilation_enabled: true,
377 js_ion_unsafe_eager_compilation_enabled: false,
378 js_mem_gc_allocation_threshold_avoid_interrupt_factor: 100,
379 js_mem_gc_allocation_threshold_factor: 100,
380 js_mem_gc_allocation_threshold_mb: 30,
381 js_mem_gc_compacting_enabled: true,
382 js_mem_gc_decommit_threshold_mb: 32,
383 js_mem_gc_dynamic_heap_growth_enabled: true,
384 js_mem_gc_dynamic_mark_slice_enabled: true,
385 js_mem_gc_empty_chunk_count_min: 1,
386 js_mem_gc_high_frequency_heap_growth_max: 300,
387 js_mem_gc_high_frequency_heap_growth_min: 150,
388 js_mem_gc_high_frequency_high_limit_mb: 500,
389 js_mem_gc_high_frequency_low_limit_mb: 100,
390 js_mem_gc_high_frequency_time_limit_ms: 1000,
391 js_mem_gc_incremental_enabled: true,
392 js_mem_gc_incremental_slice_ms: 10,
393 js_mem_gc_low_frequency_heap_growth: 150,
394 js_mem_gc_per_zone_enabled: false,
395 js_mem_gc_zeal_frequency: 100,
396 js_mem_gc_zeal_level: 0,
397 js_mem_max: -1,
398 js_native_regex_enabled: true,
399 js_offthread_compilation_enabled: true,
400 js_shared_memory: true,
401 js_throw_on_asmjs_validation_failure: false,
402 js_throw_on_debuggee_would_run: false,
403 js_timers_minimum_duration: 1000,
404 js_wasm_baseline_enabled: true,
405 js_wasm_enabled: true,
406 js_wasm_ion_enabled: true,
407 js_werror_enabled: false,
408 layout_animations_test_enabled: false,
409 layout_columns_enabled: false,
410 layout_container_queries_enabled: false,
411 layout_css_transition_behavior_enabled: true,
412 layout_flexbox_enabled: true,
413 layout_grid_enabled: false,
414 layout_threads: 3,
416 layout_unimplemented: false,
417 layout_variable_fonts_enabled: false,
418 layout_writing_mode_enabled: false,
419 media_glvideo_enabled: false,
420 media_testing_enabled: false,
421 network_enforce_tls_enabled: false,
422 network_enforce_tls_localhost: false,
423 network_enforce_tls_onion: false,
424 network_http_cache_disabled: false,
425 network_local_directory_listing_enabled: true,
426 network_mime_sniff: false,
427 session_history_max_length: 20,
428 shell_background_color_rgba: [1.0, 1.0, 1.0, 1.0],
429 threadpools_async_runtime_workers_max: 6,
430 threadpools_fallback_worker_num: 3,
431 threadpools_image_cache_workers_max: 4,
432 threadpools_indexeddb_workers_max: 4,
433 threadpools_webstorage_workers_max: 4,
434 threadpools_resource_workers_max: 4,
435 threadpools_webrender_workers_max: 4,
436 webgl_testing_context_creation_error: false,
437 user_agent: String::new(),
438 viewport_meta_enabled: false,
439 log_filter: String::new(),
440 }
441 }
442}
443
444impl Default for Preferences {
445 fn default() -> Self {
446 let mut preferences = Self::const_default();
447 preferences.user_agent = UserAgentPlatform::default().to_user_agent_string();
448 preferences
449 }
450}
451
452pub enum UserAgentPlatform {
453 Desktop,
454 Android,
455 OpenHarmony,
456 Ios,
457}
458
459impl UserAgentPlatform {
460 pub const fn default() -> Self {
463 if cfg!(target_os = "android") {
464 Self::Android
465 } else if cfg!(target_env = "ohos") {
466 Self::OpenHarmony
467 } else if cfg!(target_os = "ios") {
468 Self::Ios
469 } else {
470 Self::Desktop
471 }
472 }
473}
474
475impl UserAgentPlatform {
476 pub fn to_user_agent_string(&self) -> String {
479 const SERVO_VERSION: &str = env!("CARGO_PKG_VERSION");
480 match self {
481 UserAgentPlatform::Desktop
482 if cfg!(all(target_os = "windows", target_arch = "x86_64")) =>
483 {
484 #[cfg(target_arch = "x86_64")]
485 const ARCHITECTURE: &str = "x86; ";
486 #[cfg(not(target_arch = "x86_64"))]
487 const ARCHITECTURE: &str = "";
488
489 format!(
490 "Mozilla/5.0 (Windows NT 10.0; Win64; {ARCHITECTURE}rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
491 )
492 },
493 UserAgentPlatform::Desktop if cfg!(target_os = "macos") => {
494 format!(
495 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
496 )
497 },
498 UserAgentPlatform::Desktop => {
499 #[cfg(target_arch = "x86_64")]
500 const ARCHITECTURE: &str = "x86_64";
501 #[cfg(not(target_arch = "x86_64"))]
503 const ARCHITECTURE: &str = "i686";
504
505 format!(
506 "Mozilla/5.0 (X11; Linux {ARCHITECTURE}; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
507 )
508 },
509 UserAgentPlatform::Android => {
510 format!(
511 "Mozilla/5.0 (Android 10; Mobile; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
512 )
513 },
514 UserAgentPlatform::OpenHarmony => format!(
515 "Mozilla/5.0 (OpenHarmony; Mobile; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
516 ),
517 UserAgentPlatform::Ios => format!(
518 "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
519 ),
520 }
521 }
522}