servo_config/
prefs.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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]
21/// Get the current set of global preferences for Servo.
22pub 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    // Map between Stylo preference names and Servo preference names as the This should be
32    // kept in sync with components/script/dom/bindings/codegen/run.py which generates the
33    // DOM CSS style accessors.
34    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/// A convenience macro for accessing a preference value using its static path.
66/// Passing an invalid path is a compile-time error.
67#[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    /// Start the devtools server at startup
84    pub devtools_server_enabled: bool,
85    /// Port number to start a server to listen to remote Firefox devtools connections.
86    /// 0 for random port.
87    pub devtools_server_port: i64,
88    pub dom_webgpu_enabled: bool,
89    /// List of comma-separated backends to be used by wgpu.
90    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    /// Selects canvas backend
100    ///
101    /// Available values:
102    /// - ` `/`auto`
103    /// - vello
104    /// - vello_cpu
105    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_indexeddb_enabled: bool,
118    pub dom_intersection_observer_enabled: bool,
119    pub dom_microdata_testing_enabled: bool,
120    pub dom_mouse_event_which_enabled: bool,
121    pub dom_mutation_observer_enabled: bool,
122    pub dom_navigator_sendbeacon_enabled: bool,
123    pub dom_notification_enabled: bool,
124    pub dom_offscreen_canvas_enabled: bool,
125    pub dom_permissions_enabled: bool,
126    pub dom_permissions_testing_allowed_in_nonsecure_contexts: bool,
127    pub dom_resize_observer_enabled: bool,
128    pub dom_script_asynch: bool,
129    pub dom_serviceworker_enabled: bool,
130    pub dom_serviceworker_timeout_seconds: i64,
131    pub dom_servo_helpers_enabled: bool,
132    pub dom_servoparser_async_html_tokenizer_enabled: bool,
133    pub dom_testable_crash_enabled: bool,
134    pub dom_testbinding_enabled: bool,
135    pub dom_testbinding_prefcontrolled_enabled: bool,
136    pub dom_testbinding_prefcontrolled2_enabled: bool,
137    pub dom_testbinding_preference_value_falsy: bool,
138    pub dom_testbinding_preference_value_quote_string_test: String,
139    pub dom_testbinding_preference_value_space_string_test: String,
140    pub dom_testbinding_preference_value_string_empty: String,
141    pub dom_testbinding_preference_value_string_test: String,
142    pub dom_testbinding_preference_value_truthy: bool,
143    pub dom_testing_element_activation_enabled: bool,
144    pub dom_testing_html_input_element_select_files_enabled: bool,
145    pub dom_testperf_enabled: bool,
146    // https://testutils.spec.whatwg.org#availability
147    pub dom_testutils_enabled: bool,
148    pub dom_xpath_enabled: bool,
149    /// Enable WebGL2 APIs.
150    pub dom_webgl2_enabled: bool,
151    pub dom_webrtc_enabled: bool,
152    pub dom_webrtc_transceiver_enabled: bool,
153    pub dom_webvtt_enabled: bool,
154    pub dom_webxr_enabled: bool,
155    pub dom_webxr_test: bool,
156    pub dom_webxr_first_person_observer_view: bool,
157    pub dom_webxr_glwindow_enabled: bool,
158    pub dom_webxr_glwindow_left_right: bool,
159    pub dom_webxr_glwindow_red_cyan: bool,
160    pub dom_webxr_glwindow_spherical: bool,
161    pub dom_webxr_glwindow_cubemap: bool,
162    pub dom_webxr_hands_enabled: bool,
163    pub dom_webxr_layers_enabled: bool,
164    pub dom_webxr_openxr_enabled: bool,
165    pub dom_webxr_sessionavailable: bool,
166    pub dom_webxr_unsafe_assume_user_intent: bool,
167    pub dom_worklet_enabled: bool,
168    pub dom_worklet_blockingsleep: bool,
169    pub dom_worklet_testing_enabled: bool,
170    pub dom_worklet_timeout_ms: i64,
171    /// True to compile all WebRender shaders when Servo initializes. This is mostly
172    /// useful when modifying the shaders, to ensure they all compile after each change is
173    /// made.
174    pub gfx_precache_shaders: bool,
175    /// Whether or not antialiasing is enabled for text rendering.
176    pub gfx_text_antialiasing_enabled: bool,
177    /// Whether or not subpixel antialiasing is enabled for text rendering.
178    pub gfx_subpixel_text_antialiasing_enabled: bool,
179    pub gfx_texture_swizzling_enabled: bool,
180    /// The amount of image keys we request per batch for the image cache.
181    pub image_key_batch_size: i64,
182    /// Whether or not the DOM inspector should show shadow roots of user-agent shadow trees
183    pub inspector_show_servo_internal_shadow_roots: bool,
184    pub js_asmjs_enabled: bool,
185    pub js_asyncstack: bool,
186    pub js_baseline_interpreter_enabled: bool,
187    /// Whether to disable the jit within SpiderMonkey
188    pub js_disable_jit: bool,
189    pub js_baseline_jit_enabled: bool,
190    pub js_baseline_jit_unsafe_eager_compilation_enabled: bool,
191    pub js_discard_system_source: bool,
192    pub js_dump_stack_on_debuggee_would_run: bool,
193    pub js_ion_enabled: bool,
194    pub js_ion_offthread_compilation_enabled: bool,
195    pub js_ion_unsafe_eager_compilation_enabled: bool,
196    pub js_mem_gc_allocation_threshold_mb: i64,
197    pub js_mem_gc_allocation_threshold_factor: i64,
198    pub js_mem_gc_allocation_threshold_avoid_interrupt_factor: i64,
199    pub js_mem_gc_compacting_enabled: bool,
200    pub js_mem_gc_decommit_threshold_mb: i64,
201    pub js_mem_gc_dynamic_heap_growth_enabled: bool,
202    pub js_mem_gc_dynamic_mark_slice_enabled: bool,
203    pub js_mem_gc_empty_chunk_count_min: i64,
204    pub js_mem_gc_high_frequency_heap_growth_max: i64,
205    pub js_mem_gc_high_frequency_heap_growth_min: i64,
206    pub js_mem_gc_high_frequency_high_limit_mb: i64,
207    pub js_mem_gc_high_frequency_low_limit_mb: i64,
208    pub js_mem_gc_high_frequency_time_limit_ms: i64,
209    pub js_mem_gc_incremental_enabled: bool,
210    pub js_mem_gc_incremental_slice_ms: i64,
211    pub js_mem_gc_low_frequency_heap_growth: i64,
212    pub js_mem_gc_per_zone_enabled: bool,
213    pub js_mem_gc_zeal_frequency: i64,
214    pub js_mem_gc_zeal_level: i64,
215    pub js_mem_max: i64,
216    pub js_native_regex_enabled: bool,
217    pub js_offthread_compilation_enabled: bool,
218    pub js_shared_memory: bool,
219    pub js_throw_on_asmjs_validation_failure: bool,
220    pub js_throw_on_debuggee_would_run: bool,
221    pub js_timers_minimum_duration: i64,
222    pub js_wasm_baseline_enabled: bool,
223    pub js_wasm_enabled: bool,
224    pub js_wasm_ion_enabled: bool,
225    pub js_werror_enabled: bool,
226    pub layout_animations_test_enabled: bool,
227    pub layout_columns_enabled: bool,
228    pub layout_grid_enabled: bool,
229    pub layout_container_queries_enabled: bool,
230    pub layout_css_transition_behavior_enabled: bool,
231    pub layout_flexbox_enabled: bool,
232    pub layout_threads: i64,
233    pub layout_unimplemented: bool,
234    pub layout_variable_fonts_enabled: bool,
235    pub layout_writing_mode_enabled: bool,
236    /// Enable hardware acceleration for video playback.
237    pub media_glvideo_enabled: bool,
238    /// Enable a non-standard event handler for verifying behavior of media elements during tests.
239    pub media_testing_enabled: bool,
240    pub network_enforce_tls_enabled: bool,
241    pub network_enforce_tls_localhost: bool,
242    pub network_enforce_tls_onion: bool,
243    pub network_http_cache_disabled: bool,
244    pub network_local_directory_listing_enabled: bool,
245    pub network_mime_sniff: bool,
246    pub session_history_max_length: i64,
247    /// The background color of shell's viewport. This will be used by OpenGL's `glClearColor`.
248    pub shell_background_color_rgba: [f64; 4],
249    pub webgl_testing_context_creation_error: bool,
250    /// Number of workers per threadpool, if we fail to detect how much
251    /// parallelism is available at runtime.
252    pub threadpools_fallback_worker_num: i64,
253    /// Maximum number of workers for the Image Cache thread pool
254    pub threadpools_image_cache_workers_max: i64,
255    /// Maximum number of workers for the IndexedDB thread pool
256    pub threadpools_indexeddb_workers_max: i64,
257    /// Maximum number of workers for the Networking async runtime thread pool
258    pub threadpools_async_runtime_workers_max: i64,
259    /// Maximum number of workers for the Core Resource Manager
260    pub threadpools_resource_workers_max: i64,
261    /// Maximum number of workers for webrender
262    pub threadpools_webrender_workers_max: i64,
263    /// The user-agent to use for Servo. This can also be set via [`UserAgentPlatform`] in
264    /// order to set the value to the default value for the given platform.
265    pub user_agent: String,
266    /// Whether or not the viewport meta tag is enabled.
267    pub viewport_meta_enabled: bool,
268    pub log_filter: String,
269}
270
271impl Preferences {
272    const fn const_default() -> Self {
273        Self {
274            css_animations_testing_enabled: false,
275            devtools_server_enabled: false,
276            devtools_server_port: 0,
277            dom_abort_controller_enabled: false,
278            dom_adoptedstylesheet_enabled: false,
279            dom_allow_scripts_to_close_windows: false,
280            dom_async_clipboard_enabled: false,
281            dom_bluetooth_enabled: false,
282            dom_bluetooth_testing_enabled: false,
283            dom_canvas_capture_enabled: false,
284            dom_canvas_text_enabled: true,
285            dom_canvas_backend: String::new(),
286            dom_clipboardevent_enabled: true,
287            dom_composition_event_enabled: false,
288            dom_cookiestore_enabled: false,
289            dom_credential_management_enabled: false,
290            dom_crypto_subtle_enabled: true,
291            dom_customelements_enabled: true,
292            dom_document_dblclick_dist: 1,
293            dom_document_dblclick_timeout: 300,
294            dom_fontface_enabled: false,
295            dom_fullscreen_test: false,
296            dom_gamepad_enabled: true,
297            dom_indexeddb_enabled: false,
298            dom_intersection_observer_enabled: false,
299            dom_microdata_testing_enabled: false,
300            dom_mouse_event_which_enabled: false,
301            dom_mutation_observer_enabled: true,
302            dom_navigator_sendbeacon_enabled: false,
303            dom_notification_enabled: false,
304            dom_offscreen_canvas_enabled: false,
305            dom_permissions_enabled: false,
306            dom_permissions_testing_allowed_in_nonsecure_contexts: false,
307            dom_resize_observer_enabled: false,
308            dom_script_asynch: true,
309            dom_serviceworker_enabled: false,
310            dom_serviceworker_timeout_seconds: 60,
311            dom_servo_helpers_enabled: false,
312            dom_servoparser_async_html_tokenizer_enabled: false,
313            dom_testable_crash_enabled: false,
314            dom_testbinding_enabled: false,
315            dom_testbinding_prefcontrolled2_enabled: false,
316            dom_testbinding_prefcontrolled_enabled: false,
317            dom_testbinding_preference_value_falsy: false,
318            dom_testbinding_preference_value_quote_string_test: String::new(),
319            dom_testbinding_preference_value_space_string_test: String::new(),
320            dom_testbinding_preference_value_string_empty: String::new(),
321            dom_testbinding_preference_value_string_test: String::new(),
322            dom_testbinding_preference_value_truthy: false,
323            dom_testing_element_activation_enabled: false,
324            dom_testing_html_input_element_select_files_enabled: false,
325            dom_testperf_enabled: false,
326            dom_testutils_enabled: false,
327            dom_webgl2_enabled: false,
328            dom_webgpu_enabled: false,
329            dom_webgpu_wgpu_backend: String::new(),
330            dom_webrtc_enabled: false,
331            dom_webrtc_transceiver_enabled: false,
332            dom_webvtt_enabled: false,
333            dom_webxr_enabled: true,
334            dom_webxr_first_person_observer_view: false,
335            dom_webxr_glwindow_cubemap: false,
336            dom_webxr_glwindow_enabled: true,
337            dom_webxr_glwindow_left_right: false,
338            dom_webxr_glwindow_red_cyan: false,
339            dom_webxr_glwindow_spherical: false,
340            dom_webxr_hands_enabled: true,
341            dom_webxr_layers_enabled: false,
342            dom_webxr_openxr_enabled: true,
343            dom_webxr_sessionavailable: false,
344            dom_webxr_test: false,
345            dom_webxr_unsafe_assume_user_intent: false,
346            dom_worklet_blockingsleep: false,
347            dom_worklet_enabled: false,
348            dom_worklet_testing_enabled: false,
349            dom_worklet_timeout_ms: 10,
350            dom_xpath_enabled: false,
351            fonts_default: String::new(),
352            fonts_default_monospace_size: 13,
353            fonts_default_size: 16,
354            fonts_monospace: String::new(),
355            fonts_sans_serif: String::new(),
356            fonts_serif: String::new(),
357            gfx_precache_shaders: false,
358            gfx_text_antialiasing_enabled: true,
359            gfx_subpixel_text_antialiasing_enabled: true,
360            gfx_texture_swizzling_enabled: true,
361            image_key_batch_size: 10,
362            inspector_show_servo_internal_shadow_roots: false,
363            js_asmjs_enabled: true,
364            js_asyncstack: false,
365            js_baseline_interpreter_enabled: true,
366            js_baseline_jit_enabled: true,
367            js_baseline_jit_unsafe_eager_compilation_enabled: false,
368            js_disable_jit: false,
369            js_discard_system_source: false,
370            js_dump_stack_on_debuggee_would_run: false,
371            js_ion_enabled: true,
372            js_ion_offthread_compilation_enabled: true,
373            js_ion_unsafe_eager_compilation_enabled: false,
374            js_mem_gc_allocation_threshold_avoid_interrupt_factor: 100,
375            js_mem_gc_allocation_threshold_factor: 100,
376            js_mem_gc_allocation_threshold_mb: 30,
377            js_mem_gc_compacting_enabled: true,
378            js_mem_gc_decommit_threshold_mb: 32,
379            js_mem_gc_dynamic_heap_growth_enabled: true,
380            js_mem_gc_dynamic_mark_slice_enabled: true,
381            js_mem_gc_empty_chunk_count_min: 1,
382            js_mem_gc_high_frequency_heap_growth_max: 300,
383            js_mem_gc_high_frequency_heap_growth_min: 150,
384            js_mem_gc_high_frequency_high_limit_mb: 500,
385            js_mem_gc_high_frequency_low_limit_mb: 100,
386            js_mem_gc_high_frequency_time_limit_ms: 1000,
387            js_mem_gc_incremental_enabled: true,
388            js_mem_gc_incremental_slice_ms: 10,
389            js_mem_gc_low_frequency_heap_growth: 150,
390            js_mem_gc_per_zone_enabled: false,
391            js_mem_gc_zeal_frequency: 100,
392            js_mem_gc_zeal_level: 0,
393            js_mem_max: -1,
394            js_native_regex_enabled: true,
395            js_offthread_compilation_enabled: true,
396            js_shared_memory: true,
397            js_throw_on_asmjs_validation_failure: false,
398            js_throw_on_debuggee_would_run: false,
399            js_timers_minimum_duration: 1000,
400            js_wasm_baseline_enabled: true,
401            js_wasm_enabled: true,
402            js_wasm_ion_enabled: true,
403            js_werror_enabled: false,
404            layout_animations_test_enabled: false,
405            layout_columns_enabled: false,
406            layout_container_queries_enabled: false,
407            layout_css_transition_behavior_enabled: true,
408            layout_flexbox_enabled: true,
409            layout_grid_enabled: false,
410            // TODO(mrobinson): This should likely be based on the number of processors.
411            layout_threads: 3,
412            layout_unimplemented: false,
413            layout_variable_fonts_enabled: false,
414            layout_writing_mode_enabled: false,
415            media_glvideo_enabled: false,
416            media_testing_enabled: false,
417            network_enforce_tls_enabled: false,
418            network_enforce_tls_localhost: false,
419            network_enforce_tls_onion: false,
420            network_http_cache_disabled: false,
421            network_local_directory_listing_enabled: true,
422            network_mime_sniff: false,
423            session_history_max_length: 20,
424            shell_background_color_rgba: [1.0, 1.0, 1.0, 1.0],
425            threadpools_async_runtime_workers_max: 6,
426            threadpools_fallback_worker_num: 3,
427            threadpools_image_cache_workers_max: 4,
428            threadpools_indexeddb_workers_max: 4,
429            threadpools_resource_workers_max: 4,
430            threadpools_webrender_workers_max: 4,
431            webgl_testing_context_creation_error: false,
432            user_agent: String::new(),
433            viewport_meta_enabled: false,
434            log_filter: String::new(),
435        }
436    }
437}
438
439impl Default for Preferences {
440    fn default() -> Self {
441        let mut preferences = Self::const_default();
442        preferences.user_agent = UserAgentPlatform::default().to_user_agent_string();
443        preferences
444    }
445}
446
447pub enum UserAgentPlatform {
448    Desktop,
449    Android,
450    OpenHarmony,
451    Ios,
452}
453
454impl UserAgentPlatform {
455    /// Return the default `UserAgentPlatform` for this platform. This is
456    /// not an implementation of `Default` so that it can be `const`.
457    pub const fn default() -> Self {
458        if cfg!(target_os = "android") {
459            Self::Android
460        } else if cfg!(target_env = "ohos") {
461            Self::OpenHarmony
462        } else if cfg!(target_os = "ios") {
463            Self::Ios
464        } else {
465            Self::Desktop
466        }
467    }
468}
469
470impl UserAgentPlatform {
471    /// Convert this [`UserAgentPlatform`] into its corresponding `String` value, ie the
472    /// default user-agent to use for this platform.
473    pub fn to_user_agent_string(&self) -> String {
474        const SERVO_VERSION: &str = env!("CARGO_PKG_VERSION");
475        match self {
476            UserAgentPlatform::Desktop
477                if cfg!(all(target_os = "windows", target_arch = "x86_64")) =>
478            {
479                #[cfg(target_arch = "x86_64")]
480                const ARCHITECTURE: &str = "x86; ";
481                #[cfg(not(target_arch = "x86_64"))]
482                const ARCHITECTURE: &str = "";
483
484                format!(
485                    "Mozilla/5.0 (Windows NT 10.0; Win64; {ARCHITECTURE}rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
486                )
487            },
488            UserAgentPlatform::Desktop if cfg!(target_os = "macos") => {
489                format!(
490                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
491                )
492            },
493            UserAgentPlatform::Desktop => {
494                #[cfg(target_arch = "x86_64")]
495                const ARCHITECTURE: &str = "x86_64";
496                // TODO: This is clearly wrong for other platforms.
497                #[cfg(not(target_arch = "x86_64"))]
498                const ARCHITECTURE: &str = "i686";
499
500                format!(
501                    "Mozilla/5.0 (X11; Linux {ARCHITECTURE}; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
502                )
503            },
504            UserAgentPlatform::Android => {
505                format!(
506                    "Mozilla/5.0 (Android 10; Mobile; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
507                )
508            },
509            UserAgentPlatform::OpenHarmony => format!(
510                "Mozilla/5.0 (OpenHarmony; Mobile; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
511            ),
512            UserAgentPlatform::Ios => format!(
513                "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
514            ),
515        }
516    }
517}