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 let changed = preferences.diff(&PREFERENCES.read().unwrap());
45 if changed.is_empty() {
46 return;
47 }
48
49 stylo_static_prefs::set_pref!("layout.threads", preferences.layout_threads as i32);
51 stylo_static_prefs::set_pref!(
52 "layout.css.backdrop-filter.enabled",
53 preferences.layout_css_backdrop_filter_enabled
54 );
55 stylo_static_prefs::set_pref!(
56 "layout.css.columns.enabled",
57 preferences.layout_css_columns_enabled
58 );
59 stylo_static_prefs::set_pref!(
60 "layout.css.container-queries.enabled",
61 preferences.layout_css_container_queries_enabled
62 );
63 stylo_static_prefs::set_pref!(
64 "layout.css.ellipse-corners.enabled",
65 preferences.layout_css_ellipse_corners_enabled
66 );
67 stylo_static_prefs::set_pref!(
68 "layout.css.font-variations.enabled",
69 preferences.layout_css_font_variations_enabled
70 );
71 stylo_static_prefs::set_pref!(
72 "layout.css.writing-mode.enabled",
73 preferences.layout_css_writing_mode_enabled
74 );
75
76 *PREFERENCES.write().unwrap() = preferences;
77
78 for observer in &*OBSERVERS.read().unwrap() {
79 observer.prefs_changed(&changed);
80 }
81}
82
83#[macro_export]
86macro_rules! pref {
87 ($name: ident) => {
88 $crate::prefs::get().$name.clone()
89 };
90}
91
92#[derive(Clone, Deserialize, Serialize, ServoPreferences)]
103pub struct Preferences {
104 pub fonts_default: String,
105 pub fonts_serif: String,
106 pub fonts_sans_serif: String,
107 pub fonts_monospace: String,
108 pub fonts_default_size: i64,
109 pub fonts_default_monospace_size: i64,
110 pub editing_caret_blink_time: i64,
113 pub css_animations_testing_enabled: bool,
114 pub devtools_server_enabled: bool,
116 pub devtools_server_listen_address: String,
118 pub dom_webgpu_enabled: bool,
120 pub dom_webgpu_wgpu_backend: String,
122 pub dom_adoptedstylesheet_enabled: bool,
124 pub dom_allow_preloading_module_descendants: bool,
125 pub dom_async_clipboard_enabled: bool,
127 pub dom_bluetooth_enabled: bool,
128 pub dom_bluetooth_testing_enabled: bool,
129 pub dom_allow_scripts_to_close_windows: bool,
130 pub dom_canvas_capture_enabled: bool,
132 pub dom_canvas_text_enabled: bool,
133 pub dom_canvas_backend: String,
139 pub dom_canvas_msg_buffer_size: u64,
146 pub dom_composition_event_enabled: bool,
147 pub dom_cookiestore_enabled: bool,
149 pub dom_credential_management_enabled: bool,
151 pub dom_crypto_subtle_enabled: bool,
153 pub dom_document_dblclick_timeout: i64,
154 pub dom_document_dblclick_dist: i64,
155 pub dom_entries_api_enabled: bool,
157 pub dom_exec_command_enabled: bool,
159 pub dom_fontface_enabled: bool,
161 pub dom_fullscreen_test: bool,
162 pub dom_gamepad_enabled: bool,
164 pub dom_geolocation_enabled: bool,
166 pub dom_geolocation_test_position_enabled: bool,
169 pub dom_geolocation_test_accuracy: f64,
171 pub dom_geolocation_test_heading: f64,
173 pub dom_geolocation_test_latitude: f64,
175 pub dom_geolocation_test_longitude: f64,
177 pub dom_geolocation_test_speed: f64,
180 pub dom_wakelock_enabled: bool,
182 pub dom_indexeddb_enabled: bool,
184 pub dom_intersection_observer_enabled: bool,
186 pub dom_microdata_testing_enabled: bool,
187 pub dom_navigator_protocol_handlers_enabled: bool,
189 pub dom_notification_enabled: bool,
191 pub dom_offscreen_canvas_enabled: bool,
193 pub dom_parallel_css_parsing_enabled: bool,
194 pub dom_permissions_enabled: bool,
196 pub dom_permissions_testing_allowed_in_nonsecure_contexts: bool,
197 pub dom_resize_observer_enabled: bool,
199 pub dom_sanitizer_enabled: bool,
201 pub dom_script_asynch: bool,
202 pub dom_storage_manager_api_enabled: bool,
204 pub dom_serviceworker_enabled: bool,
206 pub dom_serviceworker_timeout_seconds: i64,
207 pub dom_sharedworker_enabled: bool,
209 pub dom_servo_helpers_enabled: bool,
210 pub dom_servoparser_async_html_tokenizer_enabled: bool,
211 pub dom_testbinding_enabled: bool,
212 pub dom_testbinding_prefcontrolled_enabled: bool,
213 pub dom_testbinding_prefcontrolled2_enabled: bool,
214 pub dom_testbinding_preference_value_falsy: bool,
215 pub dom_testbinding_preference_value_quote_string_test: String,
216 pub dom_testbinding_preference_value_space_string_test: String,
217 pub dom_testbinding_preference_value_string_empty: String,
218 pub dom_testbinding_preference_value_string_test: String,
219 pub dom_testbinding_preference_value_truthy: bool,
220 pub dom_testing_element_activation_enabled: bool,
221 pub dom_testing_html_input_element_select_files_enabled: bool,
222 pub dom_testperf_enabled: bool,
223 pub dom_testutils_enabled: bool,
225 pub dom_touch_events_legacy_apis_enabled: bool,
227 pub dom_transient_activation_duration_ms: i64,
229 pub dom_web_animations_enabled: bool,
231 pub dom_webgl2_enabled: bool,
234 pub dom_webrtc_enabled: bool,
236 pub dom_webrtc_transceiver_enabled: bool,
238 pub dom_webxr_enabled: bool,
239 pub dom_webxr_test: bool,
240 pub dom_webxr_first_person_observer_view: bool,
241 pub dom_webxr_glwindow_enabled: bool,
242 pub dom_webxr_glwindow_left_right: bool,
243 pub dom_webxr_glwindow_red_cyan: bool,
244 pub dom_webxr_glwindow_spherical: bool,
245 pub dom_webxr_glwindow_cubemap: bool,
246 pub dom_webxr_hands_enabled: bool,
247 pub dom_webxr_layers_enabled: bool,
249 pub dom_webxr_openxr_enabled: bool,
250 pub dom_webxr_sessionavailable: bool,
251 pub dom_webxr_unsafe_assume_user_intent: bool,
252 pub dom_worklet_enabled: bool,
253 pub dom_worklet_blockingsleep_enabled: bool,
254 pub dom_worklet_testing_enabled: bool,
255 pub dom_worklet_timeout_ms: i64,
256 pub dom_visual_viewport_enabled: bool,
259 pub gfx_precache_shaders: bool,
263 pub gfx_text_antialiasing_enabled: bool,
265 pub gfx_subpixel_text_antialiasing_enabled: bool,
267 pub gfx_texture_swizzling_enabled: bool,
268 pub image_key_batch_size: i64,
270 pub inspector_show_servo_internal_shadow_roots: bool,
272 pub intl_locale_override: String,
276 pub js_asmjs_enabled: bool,
277 pub js_baseline_interpreter_enabled: bool,
278 pub js_disable_jit: bool,
280 pub js_baseline_jit_enabled: bool,
281 pub js_baseline_jit_unsafe_eager_compilation_enabled: bool,
282 pub js_ion_enabled: bool,
283 pub js_ion_unsafe_eager_compilation_enabled: bool,
284 pub js_mem_gc_compacting_enabled: bool,
285 pub js_mem_gc_empty_chunk_count_min: i64,
286 pub js_mem_gc_high_frequency_heap_growth_max: i64,
287 pub js_mem_gc_high_frequency_heap_growth_min: i64,
288 pub js_mem_gc_high_frequency_high_limit_mb: i64,
289 pub js_mem_gc_high_frequency_low_limit_mb: i64,
290 pub js_mem_gc_high_frequency_time_limit_ms: i64,
291 pub js_mem_gc_incremental_enabled: bool,
297 pub js_mem_gc_incremental_slice_ms: i64,
298 pub js_mem_gc_low_frequency_heap_growth: i64,
299 pub js_mem_gc_malloc_threshold_base_mb: i64,
300 pub js_mem_gc_per_zone_enabled: bool,
301 pub js_mem_gc_urgent_threshold_mb: i64,
302 pub js_mem_gc_zeal_frequency: i64,
303 pub js_mem_gc_zeal_level: i64,
304 pub js_mem_max: i64,
305 pub js_native_regex_enabled: bool,
306 pub js_offthread_compilation_enabled: bool,
307 pub js_timers_minimum_duration: i64,
308 pub js_wasm_baseline_enabled: bool,
309 pub js_wasm_enabled: bool,
310 pub js_wasm_ion_enabled: bool,
311 pub container_timing_enabled: bool,
313 pub largest_contentful_paint_enabled: bool,
315 pub layout_animations_test_enabled: bool,
316 pub layout_css_backdrop_filter_enabled: bool,
317 pub layout_css_columns_enabled: bool,
319 pub layout_css_container_queries_enabled: bool,
320 pub layout_css_ellipse_corners_enabled: bool,
321 pub layout_css_font_variations_enabled: bool,
323 pub layout_css_writing_mode_enabled: bool,
325 pub layout_style_sharing_cache_enabled: bool,
326 pub layout_threads: i64,
327 pub layout_parallelism_job_count_minimum: u64,
339 pub layout_parallelism_job_size_minimum: u64,
350 pub mathml_core_enabled: bool,
352 pub media_glvideo_enabled: bool,
354 pub media_testing_enabled: bool,
356 pub network_connection_timeout: u64,
361 pub network_enforce_tls_enabled: bool,
362 pub network_enforce_tls_localhost: bool,
363 pub network_enforce_tls_onion: bool,
364 pub network_http_cache_disabled: bool,
365 pub network_http_disk_cache: String,
367 pub network_http_disk_cache_size: u64,
369 pub network_http_proxy_uri: String,
371 pub network_https_proxy_uri: String,
373 pub network_http_no_proxy: String,
377 pub network_http_cache_size: u64,
380 pub network_local_directory_listing_enabled: bool,
381 pub network_use_webpki_roots: bool,
385 pub network_max_content_length: u64,
387 #[doc(hidden)]
390 pub perf_thread_boost_enabled: bool,
391 pub session_history_max_length: i64,
396 pub shell_background_color_rgba: [f64; 4],
398 pub webgl_testing_context_creation_error: bool,
399 pub thread_pool_workers_max: u64,
401 pub thread_pool_fallback_workers: u64,
404 pub thread_pool_async_runtime_workers_max: u64,
406 pub thread_pool_canvas_workers: u64,
412 pub thread_pool_webrender_workers_max: u64,
414 pub user_agent: String,
417 pub viewport_meta_enabled: bool,
419 pub log_filter: String,
420 pub accessibility_enabled: bool,
422 pub expensive_accessibility_test_assertions_enabled: bool,
425 pub expose_servointernals_globally: bool,
428}
429
430impl Preferences {
431 const fn const_default() -> Self {
432 Self {
433 css_animations_testing_enabled: false,
434 editing_caret_blink_time: 600,
435 devtools_server_enabled: false,
436 devtools_server_listen_address: String::new(),
437 dom_adoptedstylesheet_enabled: false,
438 dom_allow_preloading_module_descendants: false,
439 dom_allow_scripts_to_close_windows: false,
440 dom_async_clipboard_enabled: false,
441 dom_bluetooth_enabled: false,
442 dom_bluetooth_testing_enabled: false,
443 dom_canvas_capture_enabled: false,
444 dom_canvas_text_enabled: true,
445 dom_canvas_backend: String::new(),
446 dom_canvas_msg_buffer_size: 16,
447 dom_composition_event_enabled: false,
448 dom_cookiestore_enabled: false,
449 dom_credential_management_enabled: false,
450 dom_crypto_subtle_enabled: true,
451 dom_document_dblclick_dist: 1,
452 dom_document_dblclick_timeout: 300,
453 dom_entries_api_enabled: false,
454 dom_exec_command_enabled: false,
455 dom_fontface_enabled: false,
456 dom_fullscreen_test: false,
457 dom_gamepad_enabled: true,
458 dom_geolocation_enabled: false,
459 dom_geolocation_test_position_enabled: false,
460 dom_geolocation_test_accuracy: 0.0,
461 dom_geolocation_test_heading: 0.0,
462 dom_geolocation_test_latitude: -37.0675,
463 dom_geolocation_test_longitude: -12.3111,
464 dom_geolocation_test_speed: 0.0,
465 dom_wakelock_enabled: false,
466 dom_indexeddb_enabled: false,
467 dom_intersection_observer_enabled: false,
468 dom_microdata_testing_enabled: false,
469 dom_navigator_protocol_handlers_enabled: false,
470 dom_notification_enabled: false,
471 dom_parallel_css_parsing_enabled: true,
472 dom_offscreen_canvas_enabled: false,
473 dom_permissions_enabled: false,
474 dom_permissions_testing_allowed_in_nonsecure_contexts: false,
475 dom_resize_observer_enabled: true,
476 dom_sanitizer_enabled: false,
477 dom_script_asynch: true,
478 dom_storage_manager_api_enabled: false,
479 dom_serviceworker_enabled: false,
480 dom_serviceworker_timeout_seconds: 60,
481 dom_sharedworker_enabled: true,
482 dom_servo_helpers_enabled: false,
483 dom_servoparser_async_html_tokenizer_enabled: false,
484 dom_testbinding_enabled: false,
485 dom_testbinding_prefcontrolled2_enabled: false,
486 dom_testbinding_prefcontrolled_enabled: false,
487 dom_testbinding_preference_value_falsy: false,
488 dom_testbinding_preference_value_quote_string_test: String::new(),
489 dom_testbinding_preference_value_space_string_test: String::new(),
490 dom_testbinding_preference_value_string_empty: String::new(),
491 dom_testbinding_preference_value_string_test: String::new(),
492 dom_testbinding_preference_value_truthy: false,
493 dom_testing_element_activation_enabled: false,
494 dom_testing_html_input_element_select_files_enabled: false,
495 dom_testperf_enabled: false,
496 dom_testutils_enabled: false,
497 dom_touch_events_legacy_apis_enabled: cfg!(target_os = "android") |
500 cfg!(target_env = "ohos"),
501 dom_transient_activation_duration_ms: 5000,
502 dom_web_animations_enabled: false,
503 dom_webgl2_enabled: false,
504 dom_webgpu_enabled: false,
505 dom_webgpu_wgpu_backend: String::new(),
506 dom_webrtc_enabled: false,
507 dom_webrtc_transceiver_enabled: false,
508 dom_webxr_enabled: true,
509 dom_webxr_first_person_observer_view: false,
510 dom_webxr_glwindow_cubemap: false,
511 dom_webxr_glwindow_enabled: true,
512 dom_webxr_glwindow_left_right: false,
513 dom_webxr_glwindow_red_cyan: false,
514 dom_webxr_glwindow_spherical: false,
515 dom_webxr_hands_enabled: true,
516 dom_webxr_layers_enabled: false,
517 dom_webxr_openxr_enabled: true,
518 dom_webxr_sessionavailable: false,
519 dom_webxr_test: false,
520 dom_webxr_unsafe_assume_user_intent: false,
521 dom_worklet_blockingsleep_enabled: false,
522 dom_worklet_enabled: false,
523 dom_worklet_testing_enabled: false,
524 dom_worklet_timeout_ms: 10,
525 dom_visual_viewport_enabled: false,
526 accessibility_enabled: false,
527 expensive_accessibility_test_assertions_enabled: false,
528 fonts_default: String::new(),
529 fonts_default_monospace_size: 13,
530 fonts_default_size: 16,
531 fonts_monospace: String::new(),
532 fonts_sans_serif: String::new(),
533 fonts_serif: String::new(),
534 gfx_precache_shaders: false,
535 gfx_text_antialiasing_enabled: true,
536 gfx_subpixel_text_antialiasing_enabled: true,
537 gfx_texture_swizzling_enabled: true,
538 image_key_batch_size: 10,
539 inspector_show_servo_internal_shadow_roots: false,
540 intl_locale_override: String::new(),
541 js_asmjs_enabled: true,
542 js_baseline_interpreter_enabled: true,
543 js_baseline_jit_enabled: true,
544 js_baseline_jit_unsafe_eager_compilation_enabled: false,
545 js_disable_jit: false,
546 js_ion_enabled: true,
547 js_ion_unsafe_eager_compilation_enabled: false,
548 js_mem_gc_compacting_enabled: false,
551 js_mem_gc_empty_chunk_count_min: 1,
552 js_mem_gc_high_frequency_heap_growth_max: 300,
553 js_mem_gc_high_frequency_heap_growth_min: 150,
554 js_mem_gc_high_frequency_high_limit_mb: 500,
555 js_mem_gc_high_frequency_low_limit_mb: 100,
556 js_mem_gc_high_frequency_time_limit_ms: 1000,
557 js_mem_gc_incremental_enabled: false,
558 js_mem_gc_incremental_slice_ms: 10,
559 js_mem_gc_low_frequency_heap_growth: 150,
560 js_mem_gc_malloc_threshold_base_mb: 38,
561 js_mem_gc_per_zone_enabled: false,
562 js_mem_gc_urgent_threshold_mb: 16,
563 js_mem_gc_zeal_frequency: 100,
564 js_mem_gc_zeal_level: 0,
565 js_mem_max: -1,
566 js_native_regex_enabled: true,
567 js_offthread_compilation_enabled: true,
568 js_timers_minimum_duration: 1000,
569 js_wasm_baseline_enabled: true,
570 js_wasm_enabled: true,
571 js_wasm_ion_enabled: true,
572 container_timing_enabled: false,
573 largest_contentful_paint_enabled: false,
574 layout_animations_test_enabled: false,
575 layout_css_backdrop_filter_enabled: false,
576 layout_css_columns_enabled: false,
577 layout_css_container_queries_enabled: false,
578 layout_css_ellipse_corners_enabled: false,
579 layout_css_font_variations_enabled: false,
580 layout_css_writing_mode_enabled: false,
581 layout_style_sharing_cache_enabled: true,
582 layout_threads: 3,
584 layout_parallelism_job_count_minimum: 4,
585 layout_parallelism_job_size_minimum: 16,
586 mathml_core_enabled: false,
587 media_glvideo_enabled: false,
588 media_testing_enabled: false,
589 network_connection_timeout: 15,
590 network_enforce_tls_enabled: false,
591 network_enforce_tls_localhost: false,
592 network_enforce_tls_onion: false,
593 network_http_cache_disabled: false,
594 network_http_disk_cache: String::new(),
595 network_http_disk_cache_size: 1024 * 1024 * 100, network_http_proxy_uri: String::new(),
597 network_https_proxy_uri: String::new(),
598 network_http_no_proxy: String::new(),
599 network_http_cache_size: 5000,
600 network_local_directory_listing_enabled: true,
601 network_use_webpki_roots: false,
602 network_max_content_length: 5 * 1024 * 1024,
603 perf_thread_boost_enabled: true,
604 session_history_max_length: 20,
605 shell_background_color_rgba: [1.0, 1.0, 1.0, 1.0],
606 log_filter: String::new(),
607 thread_pool_workers_max: 4,
608 thread_pool_async_runtime_workers_max: 6,
609 thread_pool_fallback_workers: 3,
610 thread_pool_canvas_workers: 3,
613 thread_pool_webrender_workers_max: 4,
614 webgl_testing_context_creation_error: false,
615 user_agent: String::new(),
616 viewport_meta_enabled: false,
617 expose_servointernals_globally: false,
618 }
619 }
620
621 pub fn editing_caret_blink_time(&self) -> Option<Duration> {
624 if self.editing_caret_blink_time > 0 {
625 Some(Duration::from_millis(self.editing_caret_blink_time as u64))
626 } else {
627 None
628 }
629 }
630}
631
632impl Default for Preferences {
633 fn default() -> Self {
634 let mut preferences = Self::const_default();
635 preferences.user_agent = UserAgentPlatform::default().to_user_agent_string();
636 if let Ok(proxy_uri) = std::env::var("http_proxy").or_else(|_| std::env::var("HTTP_PROXY"))
637 {
638 preferences.network_http_proxy_uri = proxy_uri;
639 }
640 if let Ok(proxy_uri) =
641 std::env::var("https_proxy").or_else(|_| std::env::var("HTTPS_PROXY"))
642 {
643 preferences.network_https_proxy_uri = proxy_uri;
644 }
645 if let Ok(no_proxy) = std::env::var("no_proxy").or_else(|_| std::env::var("NO_PROXY")) {
646 preferences.network_http_no_proxy = no_proxy
647 }
648
649 preferences
650 }
651}
652
653pub enum UserAgentPlatform {
654 Desktop,
655 Android,
656 OpenHarmony,
657 Ios,
658}
659
660impl UserAgentPlatform {
661 pub const fn default() -> Self {
664 if cfg!(target_os = "android") {
665 Self::Android
666 } else if cfg!(target_env = "ohos") {
667 Self::OpenHarmony
668 } else if cfg!(target_os = "ios") {
669 Self::Ios
670 } else {
671 Self::Desktop
672 }
673 }
674}
675
676impl UserAgentPlatform {
677 pub fn to_user_agent_string(&self) -> String {
680 const SERVO_VERSION: &str = env!("CARGO_PKG_VERSION");
681 match self {
682 UserAgentPlatform::Desktop
683 if cfg!(all(target_os = "windows", target_arch = "x86_64")) =>
684 {
685 format!(
686 "Mozilla/5.0 (Windows NT 10.0; Win64; {ARCH}; rv:153.0) Servo/{SERVO_VERSION} Firefox/153.0"
687 )
688 },
689 UserAgentPlatform::Desktop if cfg!(target_os = "macos") => {
690 format!(
691 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:153.0) Servo/{SERVO_VERSION} Firefox/153.0"
692 )
693 },
694 UserAgentPlatform::Desktop => {
695 format!(
696 "Mozilla/5.0 (X11; Linux {ARCH}; rv:153.0) Servo/{SERVO_VERSION} Firefox/153.0"
697 )
698 },
699 UserAgentPlatform::Android => {
700 format!(
701 "Mozilla/5.0 (Android 10; Mobile; rv:153.0) Servo/{SERVO_VERSION} Firefox/153.0"
702 )
703 },
704 UserAgentPlatform::OpenHarmony => format!(
705 "Mozilla/5.0 (OpenHarmony; Mobile; rv:153.0) Servo/{SERVO_VERSION} Firefox/153.0"
706 ),
707 UserAgentPlatform::Ios => format!(
708 "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X; rv:153.0) Servo/{SERVO_VERSION} Firefox/153.0"
709 ),
710 }
711 }
712}