1use std::env::consts::ARCH;
6use std::sync::{RwLock, RwLockReadGuard};
7
8use serde::{Deserialize, Serialize};
9use servo_config_macro::ServoPreferences;
10
11pub use crate::pref_util::PrefValue;
12
13static PREFERENCES: RwLock<Preferences> = RwLock::new(Preferences::const_default());
14
15pub trait PreferencesObserver: Send + Sync {
16 fn prefs_changed(&self, _changes: &[(&'static str, PrefValue)]) {}
17}
18
19static OBSERVERS: RwLock<Vec<Box<dyn PreferencesObserver>>> = RwLock::new(Vec::new());
20
21#[inline]
22pub fn get() -> RwLockReadGuard<'static, Preferences> {
24 PREFERENCES.read().unwrap()
25}
26
27pub fn add_observer(observer: Box<dyn PreferencesObserver>) {
28 OBSERVERS.write().unwrap().push(observer);
29}
30
31pub fn set(preferences: Preferences) {
32 stylo_static_prefs::set_pref!("layout.unimplemented", preferences.layout_unimplemented);
36 stylo_static_prefs::set_pref!("layout.threads", preferences.layout_threads as i32);
37 stylo_static_prefs::set_pref!("layout.columns.enabled", preferences.layout_columns_enabled);
38 stylo_static_prefs::set_pref!("layout.grid.enabled", preferences.layout_grid_enabled);
39 stylo_static_prefs::set_pref!(
40 "layout.css.attr.enabled",
41 preferences.layout_css_attr_enabled
42 );
43 stylo_static_prefs::set_pref!(
44 "layout.writing-mode.enabled",
45 preferences.layout_writing_mode_enabled
46 );
47 stylo_static_prefs::set_pref!(
48 "layout.container-queries.enabled",
49 preferences.layout_container_queries_enabled
50 );
51 stylo_static_prefs::set_pref!(
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_listen_address: String,
87 pub dom_webgpu_enabled: bool,
89 pub dom_webgpu_wgpu_backend: String,
91 pub dom_abort_controller_enabled: bool,
93 pub dom_adoptedstylesheet_enabled: bool,
95 pub dom_async_clipboard_enabled: bool,
97 pub dom_bluetooth_enabled: bool,
98 pub dom_bluetooth_testing_enabled: bool,
99 pub dom_allow_scripts_to_close_windows: bool,
100 pub dom_canvas_capture_enabled: bool,
102 pub dom_canvas_text_enabled: bool,
103 pub dom_canvas_backend: String,
110 pub dom_clipboardevent_enabled: bool,
111 pub dom_command_invokers_enabled: bool,
112 pub dom_composition_event_enabled: bool,
113 pub dom_cookiestore_enabled: bool,
115 pub dom_credential_management_enabled: bool,
117 pub dom_crypto_subtle_enabled: bool,
119 pub dom_document_dblclick_timeout: i64,
120 pub dom_document_dblclick_dist: i64,
121 pub dom_exec_command_enabled: bool,
123 pub dom_fontface_enabled: bool,
125 pub dom_fullscreen_test: bool,
126 pub dom_gamepad_enabled: bool,
128 pub dom_geolocation_enabled: bool,
130 pub dom_indexeddb_enabled: bool,
132 pub dom_intersection_observer_enabled: bool,
134 pub dom_microdata_testing_enabled: bool,
135 pub dom_uievent_which_enabled: bool,
136 pub dom_mutation_observer_enabled: bool,
138 pub dom_navigator_protocol_handlers_enabled: bool,
140 pub dom_notification_enabled: bool,
142 pub dom_offscreen_canvas_enabled: bool,
144 pub dom_parallel_css_parsing_enabled: bool,
145 pub dom_permissions_enabled: bool,
147 pub dom_permissions_testing_allowed_in_nonsecure_contexts: bool,
148 pub dom_resize_observer_enabled: bool,
150 pub dom_script_asynch: bool,
151 pub dom_serviceworker_enabled: bool,
153 pub dom_serviceworker_timeout_seconds: i64,
154 pub dom_servo_helpers_enabled: bool,
155 pub dom_servoparser_async_html_tokenizer_enabled: bool,
156 pub dom_testbinding_enabled: bool,
157 pub dom_testbinding_prefcontrolled_enabled: bool,
158 pub dom_testbinding_prefcontrolled2_enabled: bool,
159 pub dom_testbinding_preference_value_falsy: bool,
160 pub dom_testbinding_preference_value_quote_string_test: String,
161 pub dom_testbinding_preference_value_space_string_test: String,
162 pub dom_testbinding_preference_value_string_empty: String,
163 pub dom_testbinding_preference_value_string_test: String,
164 pub dom_testbinding_preference_value_truthy: bool,
165 pub dom_testing_element_activation_enabled: bool,
166 pub dom_testing_html_input_element_select_files_enabled: bool,
167 pub dom_testperf_enabled: bool,
168 pub dom_testutils_enabled: bool,
170 pub dom_transient_activation_duration_ms: i64,
172 pub dom_webgl2_enabled: bool,
175 pub dom_webrtc_enabled: bool,
177 pub dom_webrtc_transceiver_enabled: bool,
179 pub dom_webvtt_enabled: bool,
181 pub dom_webxr_enabled: bool,
182 pub dom_webxr_test: bool,
183 pub dom_webxr_first_person_observer_view: bool,
184 pub dom_webxr_glwindow_enabled: bool,
185 pub dom_webxr_glwindow_left_right: bool,
186 pub dom_webxr_glwindow_red_cyan: bool,
187 pub dom_webxr_glwindow_spherical: bool,
188 pub dom_webxr_glwindow_cubemap: bool,
189 pub dom_webxr_hands_enabled: bool,
190 pub dom_webxr_layers_enabled: bool,
192 pub dom_webxr_openxr_enabled: bool,
193 pub dom_webxr_sessionavailable: bool,
194 pub dom_webxr_unsafe_assume_user_intent: bool,
195 pub dom_worklet_enabled: bool,
196 pub dom_worklet_blockingsleep_enabled: bool,
197 pub dom_worklet_testing_enabled: bool,
198 pub dom_worklet_timeout_ms: i64,
199 pub dom_visual_viewport_enabled: bool,
202 pub gfx_precache_shaders: bool,
206 pub gfx_text_antialiasing_enabled: bool,
208 pub gfx_subpixel_text_antialiasing_enabled: bool,
210 pub gfx_texture_swizzling_enabled: bool,
211 pub image_key_batch_size: i64,
213 pub inspector_show_servo_internal_shadow_roots: bool,
215 pub intl_locale_override: String,
219 pub js_asmjs_enabled: bool,
220 pub js_baseline_interpreter_enabled: bool,
221 pub js_disable_jit: bool,
223 pub js_baseline_jit_enabled: bool,
224 pub js_baseline_jit_unsafe_eager_compilation_enabled: bool,
225 pub js_ion_enabled: bool,
226 pub js_ion_unsafe_eager_compilation_enabled: bool,
227 pub js_mem_gc_compacting_enabled: bool,
228 pub js_mem_gc_empty_chunk_count_min: i64,
229 pub js_mem_gc_high_frequency_heap_growth_max: i64,
230 pub js_mem_gc_high_frequency_heap_growth_min: i64,
231 pub js_mem_gc_high_frequency_high_limit_mb: i64,
232 pub js_mem_gc_high_frequency_low_limit_mb: i64,
233 pub js_mem_gc_high_frequency_time_limit_ms: i64,
234 pub js_mem_gc_incremental_enabled: bool,
235 pub js_mem_gc_incremental_slice_ms: i64,
236 pub js_mem_gc_low_frequency_heap_growth: i64,
237 pub js_mem_gc_per_zone_enabled: bool,
238 pub js_mem_gc_zeal_frequency: i64,
239 pub js_mem_gc_zeal_level: i64,
240 pub js_mem_max: i64,
241 pub js_native_regex_enabled: bool,
242 pub js_offthread_compilation_enabled: bool,
243 pub js_timers_minimum_duration: i64,
244 pub js_wasm_baseline_enabled: bool,
245 pub js_wasm_enabled: bool,
246 pub js_wasm_ion_enabled: bool,
247 pub largest_contentful_paint_enabled: bool,
249 pub layout_animations_test_enabled: bool,
250 pub layout_columns_enabled: bool,
252 pub layout_grid_enabled: bool,
254 pub layout_container_queries_enabled: bool,
255 pub layout_css_attr_enabled: bool,
256 pub layout_style_sharing_cache_enabled: bool,
257 pub layout_threads: i64,
258 pub layout_unimplemented: bool,
259 pub layout_variable_fonts_enabled: bool,
261 pub layout_writing_mode_enabled: bool,
263 pub media_glvideo_enabled: bool,
265 pub media_testing_enabled: bool,
267 pub network_connection_timeout: u64,
272 pub network_enforce_tls_enabled: bool,
273 pub network_enforce_tls_localhost: bool,
274 pub network_enforce_tls_onion: bool,
275 pub network_http_cache_disabled: bool,
276 pub network_http_proxy_uri: String,
278 pub network_https_proxy_uri: String,
280 pub network_http_no_proxy: String,
284 pub network_http_cache_size: u64,
287 pub network_local_directory_listing_enabled: bool,
288 pub network_use_webpki_roots: bool,
292 pub session_history_max_length: i64,
297 pub shell_background_color_rgba: [f64; 4],
299 pub webgl_testing_context_creation_error: bool,
300 pub threadpools_fallback_worker_num: i64,
303 pub threadpools_image_cache_workers_max: i64,
305 pub threadpools_indexeddb_workers_max: i64,
307 pub threadpools_webstorage_workers_max: i64,
309 pub threadpools_async_runtime_workers_max: i64,
311 pub threadpools_webrender_workers_max: i64,
313 pub user_agent: String,
316 pub viewport_meta_enabled: bool,
318 pub log_filter: String,
319 pub accessibility_enabled: bool,
321}
322
323impl Preferences {
324 const fn const_default() -> Self {
325 Self {
326 css_animations_testing_enabled: false,
327 devtools_server_enabled: false,
328 devtools_server_listen_address: String::new(),
329 dom_abort_controller_enabled: true,
330 dom_adoptedstylesheet_enabled: false,
331 dom_allow_scripts_to_close_windows: false,
332 dom_async_clipboard_enabled: false,
333 dom_bluetooth_enabled: false,
334 dom_bluetooth_testing_enabled: false,
335 dom_canvas_capture_enabled: false,
336 dom_canvas_text_enabled: true,
337 dom_canvas_backend: String::new(),
338 dom_clipboardevent_enabled: true,
339 dom_command_invokers_enabled: false,
340 dom_composition_event_enabled: false,
341 dom_cookiestore_enabled: false,
342 dom_credential_management_enabled: false,
343 dom_crypto_subtle_enabled: true,
344 dom_document_dblclick_dist: 1,
345 dom_document_dblclick_timeout: 300,
346 dom_exec_command_enabled: false,
347 dom_fontface_enabled: false,
348 dom_fullscreen_test: false,
349 dom_gamepad_enabled: true,
350 dom_geolocation_enabled: false,
351 dom_indexeddb_enabled: false,
352 dom_intersection_observer_enabled: false,
353 dom_microdata_testing_enabled: false,
354 dom_uievent_which_enabled: true,
355 dom_mutation_observer_enabled: true,
356 dom_navigator_protocol_handlers_enabled: false,
357 dom_notification_enabled: false,
358 dom_parallel_css_parsing_enabled: true,
359 dom_offscreen_canvas_enabled: false,
360 dom_permissions_enabled: false,
361 dom_permissions_testing_allowed_in_nonsecure_contexts: false,
362 dom_resize_observer_enabled: true,
363 dom_script_asynch: true,
364 dom_serviceworker_enabled: false,
365 dom_serviceworker_timeout_seconds: 60,
366 dom_servo_helpers_enabled: false,
367 dom_servoparser_async_html_tokenizer_enabled: false,
368 dom_testbinding_enabled: false,
369 dom_testbinding_prefcontrolled2_enabled: false,
370 dom_testbinding_prefcontrolled_enabled: false,
371 dom_testbinding_preference_value_falsy: false,
372 dom_testbinding_preference_value_quote_string_test: String::new(),
373 dom_testbinding_preference_value_space_string_test: String::new(),
374 dom_testbinding_preference_value_string_empty: String::new(),
375 dom_testbinding_preference_value_string_test: String::new(),
376 dom_testbinding_preference_value_truthy: false,
377 dom_testing_element_activation_enabled: false,
378 dom_testing_html_input_element_select_files_enabled: false,
379 dom_testperf_enabled: false,
380 dom_testutils_enabled: false,
381 dom_transient_activation_duration_ms: 5000,
382 dom_webgl2_enabled: false,
383 dom_webgpu_enabled: false,
384 dom_webgpu_wgpu_backend: String::new(),
385 dom_webrtc_enabled: false,
386 dom_webrtc_transceiver_enabled: false,
387 dom_webvtt_enabled: false,
388 dom_webxr_enabled: true,
389 dom_webxr_first_person_observer_view: false,
390 dom_webxr_glwindow_cubemap: false,
391 dom_webxr_glwindow_enabled: true,
392 dom_webxr_glwindow_left_right: false,
393 dom_webxr_glwindow_red_cyan: false,
394 dom_webxr_glwindow_spherical: false,
395 dom_webxr_hands_enabled: true,
396 dom_webxr_layers_enabled: false,
397 dom_webxr_openxr_enabled: true,
398 dom_webxr_sessionavailable: false,
399 dom_webxr_test: false,
400 dom_webxr_unsafe_assume_user_intent: false,
401 dom_worklet_blockingsleep_enabled: false,
402 dom_worklet_enabled: false,
403 dom_worklet_testing_enabled: false,
404 dom_worklet_timeout_ms: 10,
405 dom_visual_viewport_enabled: false,
406 accessibility_enabled: false,
407 fonts_default: String::new(),
408 fonts_default_monospace_size: 13,
409 fonts_default_size: 16,
410 fonts_monospace: String::new(),
411 fonts_sans_serif: String::new(),
412 fonts_serif: String::new(),
413 gfx_precache_shaders: false,
414 gfx_text_antialiasing_enabled: true,
415 gfx_subpixel_text_antialiasing_enabled: true,
416 gfx_texture_swizzling_enabled: true,
417 image_key_batch_size: 10,
418 inspector_show_servo_internal_shadow_roots: false,
419 intl_locale_override: String::new(),
420 js_asmjs_enabled: true,
421 js_baseline_interpreter_enabled: true,
422 js_baseline_jit_enabled: true,
423 js_baseline_jit_unsafe_eager_compilation_enabled: false,
424 js_disable_jit: false,
425 js_ion_enabled: true,
426 js_ion_unsafe_eager_compilation_enabled: false,
427 js_mem_gc_compacting_enabled: true,
428 js_mem_gc_empty_chunk_count_min: 1,
429 js_mem_gc_high_frequency_heap_growth_max: 300,
430 js_mem_gc_high_frequency_heap_growth_min: 150,
431 js_mem_gc_high_frequency_high_limit_mb: 500,
432 js_mem_gc_high_frequency_low_limit_mb: 100,
433 js_mem_gc_high_frequency_time_limit_ms: 1000,
434 js_mem_gc_incremental_enabled: true,
435 js_mem_gc_incremental_slice_ms: 10,
436 js_mem_gc_low_frequency_heap_growth: 150,
437 js_mem_gc_per_zone_enabled: false,
438 js_mem_gc_zeal_frequency: 100,
439 js_mem_gc_zeal_level: 0,
440 js_mem_max: -1,
441 js_native_regex_enabled: true,
442 js_offthread_compilation_enabled: true,
443 js_timers_minimum_duration: 1000,
444 js_wasm_baseline_enabled: true,
445 js_wasm_enabled: true,
446 js_wasm_ion_enabled: true,
447 largest_contentful_paint_enabled: false,
448 layout_animations_test_enabled: false,
449 layout_columns_enabled: false,
450 layout_container_queries_enabled: false,
451 layout_css_attr_enabled: false,
452 layout_grid_enabled: false,
453 layout_style_sharing_cache_enabled: true,
454 layout_threads: 3,
456 layout_unimplemented: false,
457 layout_variable_fonts_enabled: false,
458 layout_writing_mode_enabled: false,
459 media_glvideo_enabled: false,
460 media_testing_enabled: false,
461 network_connection_timeout: 15,
462 network_enforce_tls_enabled: false,
463 network_enforce_tls_localhost: false,
464 network_enforce_tls_onion: false,
465 network_http_cache_disabled: false,
466 network_http_proxy_uri: String::new(),
467 network_https_proxy_uri: String::new(),
468 network_http_no_proxy: String::new(),
469 network_http_cache_size: 5000,
470 network_local_directory_listing_enabled: true,
471 network_use_webpki_roots: false,
472 session_history_max_length: 20,
473 shell_background_color_rgba: [1.0, 1.0, 1.0, 1.0],
474 threadpools_async_runtime_workers_max: 6,
475 threadpools_fallback_worker_num: 3,
476 threadpools_image_cache_workers_max: 4,
477 threadpools_indexeddb_workers_max: 4,
478 threadpools_webstorage_workers_max: 4,
479 threadpools_webrender_workers_max: 4,
480 webgl_testing_context_creation_error: false,
481 user_agent: String::new(),
482 viewport_meta_enabled: false,
483 log_filter: String::new(),
484 }
485 }
486}
487
488impl Default for Preferences {
489 fn default() -> Self {
490 let mut preferences = Self::const_default();
491 preferences.user_agent = UserAgentPlatform::default().to_user_agent_string();
492 if let Ok(proxy_uri) = std::env::var("http_proxy").or_else(|_| std::env::var("HTTP_PROXY"))
493 {
494 preferences.network_http_proxy_uri = proxy_uri;
495 }
496 if let Ok(proxy_uri) =
497 std::env::var("https_proxy").or_else(|_| std::env::var("HTTPS_PROXY"))
498 {
499 preferences.network_https_proxy_uri = proxy_uri;
500 }
501 if let Ok(no_proxy) = std::env::var("no_proxy").or_else(|_| std::env::var("NO_PROXY")) {
502 preferences.network_http_no_proxy = no_proxy
503 }
504
505 preferences
506 }
507}
508
509pub enum UserAgentPlatform {
510 Desktop,
511 Android,
512 OpenHarmony,
513 Ios,
514}
515
516impl UserAgentPlatform {
517 pub const fn default() -> Self {
520 if cfg!(target_os = "android") {
521 Self::Android
522 } else if cfg!(target_env = "ohos") {
523 Self::OpenHarmony
524 } else if cfg!(target_os = "ios") {
525 Self::Ios
526 } else {
527 Self::Desktop
528 }
529 }
530}
531
532impl UserAgentPlatform {
533 pub fn to_user_agent_string(&self) -> String {
536 const SERVO_VERSION: &str = env!("CARGO_PKG_VERSION");
537 match self {
538 UserAgentPlatform::Desktop
539 if cfg!(all(target_os = "windows", target_arch = "x86_64")) =>
540 {
541 format!(
542 "Mozilla/5.0 (Windows NT 10.0; Win64; {ARCH}rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
543 )
544 },
545 UserAgentPlatform::Desktop if cfg!(target_os = "macos") => {
546 format!(
547 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
548 )
549 },
550 UserAgentPlatform::Desktop => {
551 format!(
552 "Mozilla/5.0 (X11; Linux {ARCH}; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
553 )
554 },
555 UserAgentPlatform::Android => {
556 format!(
557 "Mozilla/5.0 (Android 10; Mobile; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
558 )
559 },
560 UserAgentPlatform::OpenHarmony => format!(
561 "Mozilla/5.0 (OpenHarmony; Mobile; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
562 ),
563 UserAgentPlatform::Ios => format!(
564 "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
565 ),
566 }
567 }
568}