1use std::env::consts::ARCH;
8use std::sync::{RwLock, RwLockReadGuard};
9use std::time::Duration;
10
11use serde::{Deserialize, Serialize};
12use servo_config_macro::ServoPreferences;
13
14pub use crate::pref_util::PrefValue;
15
16static PREFERENCES: RwLock<Preferences> = RwLock::new(Preferences::const_default());
17
18pub trait PreferencesObserver: Send + Sync {
21 fn prefs_changed(&self, _changes: &[(&'static str, PrefValue)]) {}
25}
26
27static OBSERVERS: RwLock<Vec<Box<dyn PreferencesObserver>>> = RwLock::new(Vec::new());
28
29#[inline]
30pub fn get() -> RwLockReadGuard<'static, Preferences> {
32 PREFERENCES.read().unwrap()
33}
34
35pub fn add_observer(observer: Box<dyn PreferencesObserver>) {
37 OBSERVERS.write().unwrap().push(observer);
38}
39
40pub fn set(preferences: Preferences) {
43 stylo_static_prefs::set_pref!("layout.unimplemented", preferences.layout_unimplemented);
47 stylo_static_prefs::set_pref!("layout.threads", preferences.layout_threads as i32);
48 stylo_static_prefs::set_pref!("layout.columns.enabled", preferences.layout_columns_enabled);
49 stylo_static_prefs::set_pref!("layout.grid.enabled", preferences.layout_grid_enabled);
50 stylo_static_prefs::set_pref!(
51 "layout.css.attr.enabled",
52 preferences.layout_css_attr_enabled
53 );
54 stylo_static_prefs::set_pref!(
55 "layout.writing-mode.enabled",
56 preferences.layout_writing_mode_enabled
57 );
58 stylo_static_prefs::set_pref!(
59 "layout.container-queries.enabled",
60 preferences.layout_container_queries_enabled
61 );
62 stylo_static_prefs::set_pref!(
63 "layout.variable_fonts.enabled",
64 preferences.layout_variable_fonts_enabled
65 );
66
67 let changed = preferences.diff(&PREFERENCES.read().unwrap());
68
69 *PREFERENCES.write().unwrap() = preferences;
70
71 for observer in &*OBSERVERS.read().unwrap() {
72 observer.prefs_changed(&changed);
73 }
74}
75
76#[macro_export]
79macro_rules! pref {
80 ($name: ident) => {
81 $crate::prefs::get().$name.clone()
82 };
83}
84
85#[derive(Clone, Deserialize, Serialize, ServoPreferences)]
96pub struct Preferences {
97 pub fonts_default: String,
98 pub fonts_serif: String,
99 pub fonts_sans_serif: String,
100 pub fonts_monospace: String,
101 pub fonts_default_size: i64,
102 pub fonts_default_monospace_size: i64,
103 pub editing_caret_blink_time: i64,
106 pub css_animations_testing_enabled: bool,
107 pub devtools_server_enabled: bool,
109 pub devtools_server_listen_address: String,
111 pub dom_webgpu_enabled: bool,
113 pub dom_webgpu_wgpu_backend: String,
115 pub dom_abort_controller_enabled: bool,
117 pub dom_adoptedstylesheet_enabled: bool,
119 pub dom_allow_preloading_module_descendants: bool,
120 pub dom_async_clipboard_enabled: bool,
122 pub dom_bluetooth_enabled: bool,
123 pub dom_bluetooth_testing_enabled: bool,
124 pub dom_allow_scripts_to_close_windows: bool,
125 pub dom_canvas_capture_enabled: bool,
127 pub dom_canvas_text_enabled: bool,
128 pub dom_canvas_backend: String,
135 pub dom_clipboardevent_enabled: bool,
136 pub dom_composition_event_enabled: bool,
137 pub dom_cookiestore_enabled: bool,
139 pub dom_credential_management_enabled: bool,
141 pub dom_crypto_subtle_enabled: bool,
143 pub dom_document_dblclick_timeout: i64,
144 pub dom_document_dblclick_dist: i64,
145 pub dom_exec_command_enabled: bool,
147 pub dom_fontface_enabled: bool,
149 pub dom_fullscreen_test: bool,
150 pub dom_gamepad_enabled: bool,
152 pub dom_geolocation_enabled: bool,
154 pub dom_wakelock_enabled: bool,
156 pub dom_indexeddb_enabled: bool,
158 pub dom_intersection_observer_enabled: bool,
160 pub dom_microdata_testing_enabled: bool,
161 pub dom_uievent_which_enabled: bool,
162 pub dom_mutation_observer_enabled: bool,
164 pub dom_navigator_protocol_handlers_enabled: bool,
166 pub dom_notification_enabled: bool,
168 pub dom_offscreen_canvas_enabled: bool,
170 pub dom_parallel_css_parsing_enabled: bool,
171 pub dom_permissions_enabled: bool,
173 pub dom_permissions_testing_allowed_in_nonsecure_contexts: bool,
174 pub dom_resize_observer_enabled: bool,
176 pub dom_sanitizer_enabled: bool,
178 pub dom_script_asynch: bool,
179 pub dom_storage_manager_api_enabled: bool,
181 pub dom_serviceworker_enabled: bool,
183 pub dom_serviceworker_timeout_seconds: i64,
184 pub dom_sharedworker_enabled: bool,
186 pub dom_servo_helpers_enabled: bool,
187 pub dom_servoparser_async_html_tokenizer_enabled: bool,
188 pub dom_testbinding_enabled: bool,
189 pub dom_testbinding_prefcontrolled_enabled: bool,
190 pub dom_testbinding_prefcontrolled2_enabled: bool,
191 pub dom_testbinding_preference_value_falsy: bool,
192 pub dom_testbinding_preference_value_quote_string_test: String,
193 pub dom_testbinding_preference_value_space_string_test: String,
194 pub dom_testbinding_preference_value_string_empty: String,
195 pub dom_testbinding_preference_value_string_test: String,
196 pub dom_testbinding_preference_value_truthy: bool,
197 pub dom_testing_element_activation_enabled: bool,
198 pub dom_testing_html_input_element_select_files_enabled: bool,
199 pub dom_testperf_enabled: bool,
200 pub dom_testutils_enabled: bool,
202 pub dom_touch_events_legacy_apis_enabled: bool,
204 pub dom_transient_activation_duration_ms: i64,
206 pub dom_webgl2_enabled: bool,
209 pub dom_webrtc_enabled: bool,
211 pub dom_webrtc_transceiver_enabled: bool,
213 pub dom_webvtt_enabled: bool,
215 pub dom_webxr_enabled: bool,
216 pub dom_webxr_test: bool,
217 pub dom_webxr_first_person_observer_view: bool,
218 pub dom_webxr_glwindow_enabled: bool,
219 pub dom_webxr_glwindow_left_right: bool,
220 pub dom_webxr_glwindow_red_cyan: bool,
221 pub dom_webxr_glwindow_spherical: bool,
222 pub dom_webxr_glwindow_cubemap: bool,
223 pub dom_webxr_hands_enabled: bool,
224 pub dom_webxr_layers_enabled: bool,
226 pub dom_webxr_openxr_enabled: bool,
227 pub dom_webxr_sessionavailable: bool,
228 pub dom_webxr_unsafe_assume_user_intent: bool,
229 pub dom_worklet_enabled: bool,
230 pub dom_worklet_blockingsleep_enabled: bool,
231 pub dom_worklet_testing_enabled: bool,
232 pub dom_worklet_timeout_ms: i64,
233 pub dom_visual_viewport_enabled: bool,
236 pub gfx_precache_shaders: bool,
240 pub gfx_text_antialiasing_enabled: bool,
242 pub gfx_subpixel_text_antialiasing_enabled: bool,
244 pub gfx_texture_swizzling_enabled: bool,
245 pub image_key_batch_size: i64,
247 pub inspector_show_servo_internal_shadow_roots: bool,
249 pub intl_locale_override: String,
253 pub js_asmjs_enabled: bool,
254 pub js_baseline_interpreter_enabled: bool,
255 pub js_disable_jit: bool,
257 pub js_baseline_jit_enabled: bool,
258 pub js_baseline_jit_unsafe_eager_compilation_enabled: bool,
259 pub js_ion_enabled: bool,
260 pub js_ion_unsafe_eager_compilation_enabled: bool,
261 pub js_mem_gc_compacting_enabled: bool,
262 pub js_mem_gc_empty_chunk_count_min: i64,
263 pub js_mem_gc_high_frequency_heap_growth_max: i64,
264 pub js_mem_gc_high_frequency_heap_growth_min: i64,
265 pub js_mem_gc_high_frequency_high_limit_mb: i64,
266 pub js_mem_gc_high_frequency_low_limit_mb: i64,
267 pub js_mem_gc_high_frequency_time_limit_ms: i64,
268 pub js_mem_gc_incremental_enabled: bool,
269 pub js_mem_gc_incremental_slice_ms: i64,
270 pub js_mem_gc_low_frequency_heap_growth: i64,
271 pub js_mem_gc_per_zone_enabled: bool,
272 pub js_mem_gc_zeal_frequency: i64,
273 pub js_mem_gc_zeal_level: i64,
274 pub js_mem_max: i64,
275 pub js_native_regex_enabled: bool,
276 pub js_offthread_compilation_enabled: bool,
277 pub js_timers_minimum_duration: i64,
278 pub js_wasm_baseline_enabled: bool,
279 pub js_wasm_enabled: bool,
280 pub js_wasm_ion_enabled: bool,
281 pub largest_contentful_paint_enabled: bool,
283 pub layout_animations_test_enabled: bool,
284 pub layout_columns_enabled: bool,
286 pub layout_grid_enabled: bool,
288 pub layout_container_queries_enabled: bool,
289 pub layout_css_attr_enabled: bool,
290 pub layout_style_sharing_cache_enabled: bool,
291 pub layout_threads: i64,
292 pub layout_unimplemented: bool,
293 pub layout_variable_fonts_enabled: bool,
295 pub layout_writing_mode_enabled: bool,
297 pub media_glvideo_enabled: bool,
299 pub media_testing_enabled: bool,
301 pub network_connection_timeout: u64,
306 pub network_enforce_tls_enabled: bool,
307 pub network_enforce_tls_localhost: bool,
308 pub network_enforce_tls_onion: bool,
309 pub network_http_cache_disabled: bool,
310 pub network_http_proxy_uri: String,
312 pub network_https_proxy_uri: String,
314 pub network_http_no_proxy: String,
318 pub network_http_cache_size: u64,
321 pub network_local_directory_listing_enabled: bool,
322 pub network_use_webpki_roots: bool,
326 pub session_history_max_length: i64,
331 pub shell_background_color_rgba: [f64; 4],
333 pub webgl_testing_context_creation_error: bool,
334 pub thread_pool_workers_max: u64,
336 pub thread_pool_fallback_workers: u64,
339 pub thread_pool_async_runtime_workers_max: u64,
341 pub thread_pool_webrender_workers_max: u64,
343 pub user_agent: String,
346 pub viewport_meta_enabled: bool,
348 pub log_filter: String,
349 pub accessibility_enabled: bool,
351 pub expensive_accessibility_test_assertions_enabled: bool,
354}
355
356impl Preferences {
357 const fn const_default() -> Self {
358 Self {
359 css_animations_testing_enabled: false,
360 editing_caret_blink_time: 600,
361 devtools_server_enabled: false,
362 devtools_server_listen_address: String::new(),
363 dom_abort_controller_enabled: true,
364 dom_adoptedstylesheet_enabled: false,
365 dom_allow_preloading_module_descendants: false,
366 dom_allow_scripts_to_close_windows: false,
367 dom_async_clipboard_enabled: false,
368 dom_bluetooth_enabled: false,
369 dom_bluetooth_testing_enabled: false,
370 dom_canvas_capture_enabled: false,
371 dom_canvas_text_enabled: true,
372 dom_canvas_backend: String::new(),
373 dom_clipboardevent_enabled: true,
374 dom_composition_event_enabled: false,
375 dom_cookiestore_enabled: false,
376 dom_credential_management_enabled: false,
377 dom_crypto_subtle_enabled: true,
378 dom_document_dblclick_dist: 1,
379 dom_document_dblclick_timeout: 300,
380 dom_exec_command_enabled: false,
381 dom_fontface_enabled: false,
382 dom_fullscreen_test: false,
383 dom_gamepad_enabled: true,
384 dom_geolocation_enabled: false,
385 dom_wakelock_enabled: false,
386 dom_indexeddb_enabled: false,
387 dom_intersection_observer_enabled: false,
388 dom_microdata_testing_enabled: false,
389 dom_uievent_which_enabled: true,
390 dom_mutation_observer_enabled: true,
391 dom_navigator_protocol_handlers_enabled: false,
392 dom_notification_enabled: false,
393 dom_parallel_css_parsing_enabled: true,
394 dom_offscreen_canvas_enabled: false,
395 dom_permissions_enabled: false,
396 dom_permissions_testing_allowed_in_nonsecure_contexts: false,
397 dom_resize_observer_enabled: true,
398 dom_sanitizer_enabled: false,
399 dom_script_asynch: true,
400 dom_storage_manager_api_enabled: false,
401 dom_serviceworker_enabled: false,
402 dom_serviceworker_timeout_seconds: 60,
403 dom_sharedworker_enabled: false,
404 dom_servo_helpers_enabled: false,
405 dom_servoparser_async_html_tokenizer_enabled: false,
406 dom_testbinding_enabled: false,
407 dom_testbinding_prefcontrolled2_enabled: false,
408 dom_testbinding_prefcontrolled_enabled: false,
409 dom_testbinding_preference_value_falsy: false,
410 dom_testbinding_preference_value_quote_string_test: String::new(),
411 dom_testbinding_preference_value_space_string_test: String::new(),
412 dom_testbinding_preference_value_string_empty: String::new(),
413 dom_testbinding_preference_value_string_test: String::new(),
414 dom_testbinding_preference_value_truthy: false,
415 dom_testing_element_activation_enabled: false,
416 dom_testing_html_input_element_select_files_enabled: false,
417 dom_testperf_enabled: false,
418 dom_testutils_enabled: false,
419 dom_touch_events_legacy_apis_enabled: cfg!(target_os = "android") |
422 cfg!(target_env = "ohos"),
423 dom_transient_activation_duration_ms: 5000,
424 dom_webgl2_enabled: false,
425 dom_webgpu_enabled: false,
426 dom_webgpu_wgpu_backend: String::new(),
427 dom_webrtc_enabled: false,
428 dom_webrtc_transceiver_enabled: false,
429 dom_webvtt_enabled: false,
430 dom_webxr_enabled: true,
431 dom_webxr_first_person_observer_view: false,
432 dom_webxr_glwindow_cubemap: false,
433 dom_webxr_glwindow_enabled: true,
434 dom_webxr_glwindow_left_right: false,
435 dom_webxr_glwindow_red_cyan: false,
436 dom_webxr_glwindow_spherical: false,
437 dom_webxr_hands_enabled: true,
438 dom_webxr_layers_enabled: false,
439 dom_webxr_openxr_enabled: true,
440 dom_webxr_sessionavailable: false,
441 dom_webxr_test: false,
442 dom_webxr_unsafe_assume_user_intent: false,
443 dom_worklet_blockingsleep_enabled: false,
444 dom_worklet_enabled: false,
445 dom_worklet_testing_enabled: false,
446 dom_worklet_timeout_ms: 10,
447 dom_visual_viewport_enabled: false,
448 accessibility_enabled: false,
449 expensive_accessibility_test_assertions_enabled: false,
450 fonts_default: String::new(),
451 fonts_default_monospace_size: 13,
452 fonts_default_size: 16,
453 fonts_monospace: String::new(),
454 fonts_sans_serif: String::new(),
455 fonts_serif: String::new(),
456 gfx_precache_shaders: false,
457 gfx_text_antialiasing_enabled: true,
458 gfx_subpixel_text_antialiasing_enabled: true,
459 gfx_texture_swizzling_enabled: true,
460 image_key_batch_size: 10,
461 inspector_show_servo_internal_shadow_roots: false,
462 intl_locale_override: String::new(),
463 js_asmjs_enabled: true,
464 js_baseline_interpreter_enabled: true,
465 js_baseline_jit_enabled: true,
466 js_baseline_jit_unsafe_eager_compilation_enabled: false,
467 js_disable_jit: false,
468 js_ion_enabled: true,
469 js_ion_unsafe_eager_compilation_enabled: false,
470 js_mem_gc_compacting_enabled: true,
471 js_mem_gc_empty_chunk_count_min: 1,
472 js_mem_gc_high_frequency_heap_growth_max: 300,
473 js_mem_gc_high_frequency_heap_growth_min: 150,
474 js_mem_gc_high_frequency_high_limit_mb: 500,
475 js_mem_gc_high_frequency_low_limit_mb: 100,
476 js_mem_gc_high_frequency_time_limit_ms: 1000,
477 js_mem_gc_incremental_enabled: true,
478 js_mem_gc_incremental_slice_ms: 10,
479 js_mem_gc_low_frequency_heap_growth: 150,
480 js_mem_gc_per_zone_enabled: false,
481 js_mem_gc_zeal_frequency: 100,
482 js_mem_gc_zeal_level: 0,
483 js_mem_max: -1,
484 js_native_regex_enabled: true,
485 js_offthread_compilation_enabled: true,
486 js_timers_minimum_duration: 1000,
487 js_wasm_baseline_enabled: true,
488 js_wasm_enabled: true,
489 js_wasm_ion_enabled: true,
490 largest_contentful_paint_enabled: false,
491 layout_animations_test_enabled: false,
492 layout_columns_enabled: false,
493 layout_container_queries_enabled: false,
494 layout_css_attr_enabled: false,
495 layout_grid_enabled: false,
496 layout_style_sharing_cache_enabled: true,
497 layout_threads: 3,
499 layout_unimplemented: false,
500 layout_variable_fonts_enabled: false,
501 layout_writing_mode_enabled: false,
502 media_glvideo_enabled: false,
503 media_testing_enabled: false,
504 network_connection_timeout: 15,
505 network_enforce_tls_enabled: false,
506 network_enforce_tls_localhost: false,
507 network_enforce_tls_onion: false,
508 network_http_cache_disabled: false,
509 network_http_proxy_uri: String::new(),
510 network_https_proxy_uri: String::new(),
511 network_http_no_proxy: String::new(),
512 network_http_cache_size: 5000,
513 network_local_directory_listing_enabled: true,
514 network_use_webpki_roots: false,
515 session_history_max_length: 20,
516 shell_background_color_rgba: [1.0, 1.0, 1.0, 1.0],
517 log_filter: String::new(),
518 thread_pool_workers_max: 4,
519 thread_pool_async_runtime_workers_max: 6,
520 thread_pool_fallback_workers: 3,
521 thread_pool_webrender_workers_max: 4,
522 webgl_testing_context_creation_error: false,
523 user_agent: String::new(),
524 viewport_meta_enabled: false,
525 }
526 }
527
528 pub fn editing_caret_blink_time(&self) -> Option<Duration> {
531 if self.editing_caret_blink_time > 0 {
532 Some(Duration::from_millis(self.editing_caret_blink_time as u64))
533 } else {
534 None
535 }
536 }
537}
538
539impl Default for Preferences {
540 fn default() -> Self {
541 let mut preferences = Self::const_default();
542 preferences.user_agent = UserAgentPlatform::default().to_user_agent_string();
543 if let Ok(proxy_uri) = std::env::var("http_proxy").or_else(|_| std::env::var("HTTP_PROXY"))
544 {
545 preferences.network_http_proxy_uri = proxy_uri;
546 }
547 if let Ok(proxy_uri) =
548 std::env::var("https_proxy").or_else(|_| std::env::var("HTTPS_PROXY"))
549 {
550 preferences.network_https_proxy_uri = proxy_uri;
551 }
552 if let Ok(no_proxy) = std::env::var("no_proxy").or_else(|_| std::env::var("NO_PROXY")) {
553 preferences.network_http_no_proxy = no_proxy
554 }
555
556 preferences
557 }
558}
559
560pub enum UserAgentPlatform {
561 Desktop,
562 Android,
563 OpenHarmony,
564 Ios,
565}
566
567impl UserAgentPlatform {
568 pub const fn default() -> Self {
571 if cfg!(target_os = "android") {
572 Self::Android
573 } else if cfg!(target_env = "ohos") {
574 Self::OpenHarmony
575 } else if cfg!(target_os = "ios") {
576 Self::Ios
577 } else {
578 Self::Desktop
579 }
580 }
581}
582
583impl UserAgentPlatform {
584 pub fn to_user_agent_string(&self) -> String {
587 const SERVO_VERSION: &str = env!("CARGO_PKG_VERSION");
588 match self {
589 UserAgentPlatform::Desktop
590 if cfg!(all(target_os = "windows", target_arch = "x86_64")) =>
591 {
592 format!(
593 "Mozilla/5.0 (Windows NT 10.0; Win64; {ARCH}rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
594 )
595 },
596 UserAgentPlatform::Desktop if cfg!(target_os = "macos") => {
597 format!(
598 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
599 )
600 },
601 UserAgentPlatform::Desktop => {
602 format!(
603 "Mozilla/5.0 (X11; Linux {ARCH}; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
604 )
605 },
606 UserAgentPlatform::Android => {
607 format!(
608 "Mozilla/5.0 (Android 10; Mobile; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
609 )
610 },
611 UserAgentPlatform::OpenHarmony => format!(
612 "Mozilla/5.0 (OpenHarmony; Mobile; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
613 ),
614 UserAgentPlatform::Ios => format!(
615 "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
616 ),
617 }
618 }
619}