Skip to main content

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
5//! Preferences are the global configuration options that can be changed at runtime.
6
7use 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
18/// A trait to be implemented by components that wish to be notified about runtime changes to the
19/// global preferences for the current process.
20pub trait PreferencesObserver: Send + Sync {
21    /// This method is called when the global preferences have been updated. The argument to the
22    /// method is an array of tuples where the first component is the name of the preference and
23    /// the second component is the new value of the preference.
24    fn prefs_changed(&self, _changes: &[(&'static str, PrefValue)]) {}
25}
26
27static OBSERVERS: RwLock<Vec<Box<dyn PreferencesObserver>>> = RwLock::new(Vec::new());
28
29#[inline]
30/// Get the current set of global preferences for Servo.
31pub fn get() -> RwLockReadGuard<'static, Preferences> {
32    PREFERENCES.read().unwrap()
33}
34
35/// Subscribe to notifications about changes to the global preferences for the current process.
36pub fn add_observer(observer: Box<dyn PreferencesObserver>) {
37    OBSERVERS.write().unwrap().push(observer);
38}
39
40/// Update the values of the global preferences for the current process. This also notifies the
41/// observers previously added using [`add_observer`].
42pub fn set(preferences: Preferences) {
43    // Get list of changes, returning early if the preferences haven't changed.
44    let changed = preferences.diff(&PREFERENCES.read().unwrap());
45    if changed.is_empty() {
46        return;
47    }
48
49    // Map between Stylo preference names and Servo preference names as the This should be
50    // kept in sync with components/script/dom/bindings/codegen/run.py which generates the
51    // DOM CSS style accessors.
52    stylo_static_prefs::set_pref!("layout.unimplemented", preferences.layout_unimplemented);
53    stylo_static_prefs::set_pref!("layout.threads", preferences.layout_threads as i32);
54    stylo_static_prefs::set_pref!("layout.columns.enabled", preferences.layout_columns_enabled);
55    stylo_static_prefs::set_pref!("layout.grid.enabled", preferences.layout_grid_enabled);
56    stylo_static_prefs::set_pref!(
57        "layout.css.attr.enabled",
58        preferences.layout_css_attr_enabled
59    );
60    stylo_static_prefs::set_pref!(
61        "layout.writing-mode.enabled",
62        preferences.layout_writing_mode_enabled
63    );
64    stylo_static_prefs::set_pref!(
65        "layout.container-queries.enabled",
66        preferences.layout_container_queries_enabled
67    );
68    stylo_static_prefs::set_pref!(
69        "layout.variable_fonts.enabled",
70        preferences.layout_variable_fonts_enabled
71    );
72
73    *PREFERENCES.write().unwrap() = preferences;
74
75    for observer in &*OBSERVERS.read().unwrap() {
76        observer.prefs_changed(&changed);
77    }
78}
79
80/// A convenience macro for accessing a preference value using its static path.
81/// Passing an invalid path is a compile-time error.
82#[macro_export]
83macro_rules! pref {
84    ($name: ident) => {
85        $crate::prefs::get().$name.clone()
86    };
87}
88
89/// The set of global preferences supported by Servo.
90///
91/// Each preference has a default value that determines its initial state. These defaults
92/// fall into roughly three categories:
93/// - **Stable**: enabled by default.
94/// - **Experimental**: disabled by default, but intended to be enabled for experimental use.
95/// - **Unstable**: disabled by default.
96///
97/// For a full overview of which preferences are experimental, see the
98/// [experimental features documentation](https://book.servo.org/design-documentation/experimental-features.html).
99#[derive(Clone, Deserialize, Serialize, ServoPreferences)]
100pub struct Preferences {
101    pub fonts_default: String,
102    pub fonts_serif: String,
103    pub fonts_sans_serif: String,
104    pub fonts_monospace: String,
105    pub fonts_default_size: i64,
106    pub fonts_default_monospace_size: i64,
107    /// The amount of time that a half cycle of a text caret blink takes in milliseconds.
108    /// If this value is less than or equal to zero, then caret blink is disabled.
109    pub editing_caret_blink_time: i64,
110    pub css_animations_testing_enabled: bool,
111    /// Start the devtools server at startup
112    pub devtools_server_enabled: bool,
113    /// The address:port the devtools server listens to, default to 127.0.0.1:7000.
114    pub devtools_server_listen_address: String,
115    // feature: WebGPU | #24706 | Web/API/WebGPU_API
116    pub dom_webgpu_enabled: bool,
117    /// List of comma-separated backends to be used by wgpu.
118    pub dom_webgpu_wgpu_backend: String,
119    // feature: AbortController | #34866 | Web/API/AbortController
120    pub dom_abort_controller_enabled: bool,
121    // feature: Adopted Stylesheet | #38132 | Web/API/Document/adoptedStyleSheets
122    pub dom_adoptedstylesheet_enabled: bool,
123    pub dom_allow_preloading_module_descendants: bool,
124    // feature: Clipboard API | #36084 | Web/API/Clipboard_API
125    pub dom_async_clipboard_enabled: bool,
126    pub dom_bluetooth_enabled: bool,
127    pub dom_bluetooth_testing_enabled: bool,
128    pub dom_allow_scripts_to_close_windows: bool,
129    // feature: Media Capture and Streams API | #26861 | Web/API/Media_Capture_and_Streams_API
130    pub dom_canvas_capture_enabled: bool,
131    pub dom_canvas_text_enabled: bool,
132    /// Selects canvas backend
133    ///
134    /// Available values:
135    /// - ` `/`auto`
136    /// - vello
137    /// - vello_cpu
138    pub dom_canvas_backend: String,
139    pub dom_clipboardevent_enabled: bool,
140    pub dom_composition_event_enabled: bool,
141    // feature: CookieStore | #37674 | Web/API/CookieStore
142    pub dom_cookiestore_enabled: bool,
143    // feature: Credential Management API | #38788 | Web/API/Credential_Management_API
144    pub dom_credential_management_enabled: bool,
145    // feature: WebCrypto API | #40687 | Web/API/Web_Crypto_API
146    pub dom_crypto_subtle_enabled: bool,
147    pub dom_document_dblclick_timeout: i64,
148    pub dom_document_dblclick_dist: i64,
149    // feature: Document.execCommand | #25005 | Web/API/Document/execCommand
150    pub dom_exec_command_enabled: bool,
151    // feature: CSS Font Loading API | #29376 | Web/API/CSS_Font_Loading_API
152    pub dom_fontface_enabled: bool,
153    pub dom_fullscreen_test: bool,
154    // feature: Gamepad API | #10977 | Web/API/Gamepad_API
155    pub dom_gamepad_enabled: bool,
156    // feature: Geolocation API | #38903 | Web/API/Geolocation_API
157    pub dom_geolocation_enabled: bool,
158    // feature: Screen Wake Lock API | #43615 | Web/API/Screen_Wake_Lock_API
159    pub dom_wakelock_enabled: bool,
160    // feature: IndexedDB | #6963 | Web/API/IndexedDB_API
161    pub dom_indexeddb_enabled: bool,
162    // feature: IntersectionObserver | #35767 | Web/API/Intersection_Observer_API
163    pub dom_intersection_observer_enabled: bool,
164    pub dom_microdata_testing_enabled: bool,
165    pub dom_uievent_which_enabled: bool,
166    // feature: MutationObserver | #6633 | Web/API/MutationObserver
167    pub dom_mutation_observer_enabled: bool,
168    // feature: Navigator.registerProtocolHandler() | #40615 | Web/API/Navigator/registerProtocolHandler
169    pub dom_navigator_protocol_handlers_enabled: bool,
170    // feature: Notification API | #34841 | Web/API/Notifications_API
171    pub dom_notification_enabled: bool,
172    // feature: OffscreenCanvas | #34111 | Web/API/OffscreenCanvas
173    pub dom_offscreen_canvas_enabled: bool,
174    pub dom_parallel_css_parsing_enabled: bool,
175    // feature: Permissions API | #31235 | Web/API/Permissions_API
176    pub dom_permissions_enabled: bool,
177    pub dom_permissions_testing_allowed_in_nonsecure_contexts: bool,
178    // feature: ResizeObserver | #39790 | Web/API/ResizeObserver
179    pub dom_resize_observer_enabled: bool,
180    // feature: Sanitizer API | #43948 | Web/API/HTML_Sanitizer_API
181    pub dom_sanitizer_enabled: bool,
182    pub dom_script_asynch: bool,
183    // feature: Storage API | #43976 | Web/API/Storage_API
184    pub dom_storage_manager_api_enabled: bool,
185    // feature: ServiceWorker | #36538 | Web/API/Service_Worker_API
186    pub dom_serviceworker_enabled: bool,
187    pub dom_serviceworker_timeout_seconds: i64,
188    // feature: SharedWorker | #7458 | Web/API/SharedWorker
189    pub dom_sharedworker_enabled: bool,
190    pub dom_servo_helpers_enabled: bool,
191    pub dom_servoparser_async_html_tokenizer_enabled: bool,
192    pub dom_testbinding_enabled: bool,
193    pub dom_testbinding_prefcontrolled_enabled: bool,
194    pub dom_testbinding_prefcontrolled2_enabled: bool,
195    pub dom_testbinding_preference_value_falsy: bool,
196    pub dom_testbinding_preference_value_quote_string_test: String,
197    pub dom_testbinding_preference_value_space_string_test: String,
198    pub dom_testbinding_preference_value_string_empty: String,
199    pub dom_testbinding_preference_value_string_test: String,
200    pub dom_testbinding_preference_value_truthy: bool,
201    pub dom_testing_element_activation_enabled: bool,
202    pub dom_testing_html_input_element_select_files_enabled: bool,
203    pub dom_testperf_enabled: bool,
204    // https://testutils.spec.whatwg.org#availability
205    pub dom_testutils_enabled: bool,
206    /// <https://w3c.github.io/touch-events/#conditionally-exposing-legacy-touch-event-apis>
207    pub dom_touch_events_legacy_apis_enabled: bool,
208    /// <https://html.spec.whatwg.org/multipage/#transient-activation-duration>
209    pub dom_transient_activation_duration_ms: i64,
210    /// Enable WebGL2 APIs.
211    // feature: WebGL2 | #41394 | Web/API/WebGL2RenderingContext
212    pub dom_webgl2_enabled: bool,
213    // feature: WebRTC | #41396 | Web/API/WebRTC_API
214    pub dom_webrtc_enabled: bool,
215    // feature: WebRTC Transceiver | #41396 | Web/API/RTCRtpTransceiver
216    pub dom_webrtc_transceiver_enabled: bool,
217    // feature: WebVTT | #22312 | Web/API/WebVTT_API
218    pub dom_webvtt_enabled: bool,
219    pub dom_webxr_enabled: bool,
220    pub dom_webxr_test: bool,
221    pub dom_webxr_first_person_observer_view: bool,
222    pub dom_webxr_glwindow_enabled: bool,
223    pub dom_webxr_glwindow_left_right: bool,
224    pub dom_webxr_glwindow_red_cyan: bool,
225    pub dom_webxr_glwindow_spherical: bool,
226    pub dom_webxr_glwindow_cubemap: bool,
227    pub dom_webxr_hands_enabled: bool,
228    // feature: WebXR Layers | #27468 | Web/API/XRCompositionLayer
229    pub dom_webxr_layers_enabled: bool,
230    pub dom_webxr_openxr_enabled: bool,
231    pub dom_webxr_sessionavailable: bool,
232    pub dom_webxr_unsafe_assume_user_intent: bool,
233    pub dom_worklet_enabled: bool,
234    pub dom_worklet_blockingsleep_enabled: bool,
235    pub dom_worklet_testing_enabled: bool,
236    pub dom_worklet_timeout_ms: i64,
237    /// <https://drafts.csswg.org/cssom-view/#the-visualviewport-interface>
238    // feature: VisualViewport | #41341 | Web/API/VisualViewport
239    pub dom_visual_viewport_enabled: bool,
240    /// True to compile all WebRender shaders when Servo initializes. This is mostly
241    /// useful when modifying the shaders, to ensure they all compile after each change is
242    /// made.
243    pub gfx_precache_shaders: bool,
244    /// Whether or not antialiasing is enabled for text rendering.
245    pub gfx_text_antialiasing_enabled: bool,
246    /// Whether or not subpixel antialiasing is enabled for text rendering.
247    pub gfx_subpixel_text_antialiasing_enabled: bool,
248    pub gfx_texture_swizzling_enabled: bool,
249    /// The amount of image keys we request per batch for the image cache.
250    pub image_key_batch_size: i64,
251    /// Whether or not the DOM inspector should show shadow roots of user-agent shadow trees
252    pub inspector_show_servo_internal_shadow_roots: bool,
253    /// A locale tag (eg. es-ES) to use for language negotiation instead of the system locale.
254    /// An empty string represents no override.
255    /// TODO: Option<> support in PrefValue
256    pub intl_locale_override: String,
257    pub js_asmjs_enabled: bool,
258    pub js_baseline_interpreter_enabled: bool,
259    /// Whether to disable the jit within SpiderMonkey
260    pub js_disable_jit: bool,
261    pub js_baseline_jit_enabled: bool,
262    pub js_baseline_jit_unsafe_eager_compilation_enabled: bool,
263    pub js_ion_enabled: bool,
264    pub js_ion_unsafe_eager_compilation_enabled: bool,
265    pub js_mem_gc_compacting_enabled: bool,
266    pub js_mem_gc_empty_chunk_count_min: i64,
267    pub js_mem_gc_high_frequency_heap_growth_max: i64,
268    pub js_mem_gc_high_frequency_heap_growth_min: i64,
269    pub js_mem_gc_high_frequency_high_limit_mb: i64,
270    pub js_mem_gc_high_frequency_low_limit_mb: i64,
271    pub js_mem_gc_high_frequency_time_limit_ms: i64,
272    pub js_mem_gc_incremental_enabled: bool,
273    pub js_mem_gc_incremental_slice_ms: i64,
274    pub js_mem_gc_low_frequency_heap_growth: i64,
275    pub js_mem_gc_per_zone_enabled: bool,
276    pub js_mem_gc_zeal_frequency: i64,
277    pub js_mem_gc_zeal_level: i64,
278    pub js_mem_max: i64,
279    pub js_native_regex_enabled: bool,
280    pub js_offthread_compilation_enabled: bool,
281    pub js_timers_minimum_duration: i64,
282    pub js_wasm_baseline_enabled: bool,
283    pub js_wasm_enabled: bool,
284    pub js_wasm_ion_enabled: bool,
285    // feature: Largest Contentful Paint | #42000 | Web/API/LargestContentfulPaint
286    pub largest_contentful_paint_enabled: bool,
287    pub layout_animations_test_enabled: bool,
288    // feature: CSS Multicol | #22397 | Web/CSS/Guides/Multicol_layout
289    pub layout_columns_enabled: bool,
290    // feature: CSS Grid | #34479 | Web/CSS/Guides/Grid_layout
291    pub layout_grid_enabled: bool,
292    pub layout_container_queries_enabled: bool,
293    pub layout_css_attr_enabled: bool,
294    pub layout_style_sharing_cache_enabled: bool,
295    pub layout_threads: i64,
296    pub layout_unimplemented: bool,
297    // feature: Variable fonts | #38800 | Web/CSS/Guides/Fonts/Variable_fonts
298    pub layout_variable_fonts_enabled: bool,
299    // feature: CSS writing modes | #2560 | Web/CSS/Guides/Writing_modes
300    pub layout_writing_mode_enabled: bool,
301    /// Enable hardware acceleration for video playback.
302    pub media_glvideo_enabled: bool,
303    /// Enable a non-standard event handler for verifying behavior of media elements during tests.
304    pub media_testing_enabled: bool,
305    /// The default timeout set for establishing a network connection in seconds. This amount
306    /// if for the entire process of connecting to an address. For instance, if a particular host is
307    /// associated with multiple IP addresses, this timeout will be divided equally among
308    /// each IP address.
309    pub network_connection_timeout: u64,
310    pub network_enforce_tls_enabled: bool,
311    pub network_enforce_tls_localhost: bool,
312    pub network_enforce_tls_onion: bool,
313    pub network_http_cache_disabled: bool,
314    /// A url for a http proxy. We treat an empty string as no proxy.
315    pub network_http_proxy_uri: String,
316    /// A url for a https proxy. We treat an empty string as no proxy.
317    pub network_https_proxy_uri: String,
318    /// The domains for which we will not have a proxy. No effect if `network_http_proxy_uri` is not set.
319    /// The exact behavior is given by
320    /// <https://docs.rs/hyper-util/latest/hyper_util/client/proxy/matcher/struct.Builder.html#method.no>
321    pub network_http_no_proxy: String,
322    /// The weight of the http memory cache
323    /// Notice that this is not equal to the number of different urls in the cache.
324    pub network_http_cache_size: u64,
325    pub network_local_directory_listing_enabled: bool,
326    /// Force the use of `rust-webpki` verification for CA roots. If this is false (the
327    /// default), then `rustls-platform-verifier` will be used, except on Android where
328    /// `rust-webpki` is always used.
329    pub network_use_webpki_roots: bool,
330    /// The length of the session history, in navigations, for each `WebView. Back-forward
331    /// cache entries that are more than `session_history_max_length` steps in the future or
332    /// `session_history_max_length` steps in the past will be discarded. Navigating forward
333    /// or backward to that entry will cause the entire page to be reloaded.
334    pub session_history_max_length: i64,
335    /// The background color of shell's viewport. This will be used by OpenGL's `glClearColor`.
336    pub shell_background_color_rgba: [f64; 4],
337    pub webgl_testing_context_creation_error: bool,
338    /// Maximum number of workers for the main thread pool
339    pub thread_pool_workers_max: u64,
340    /// Number of workers per thread pool, if we fail to detect how much
341    /// parallelism is available at runtime.
342    pub thread_pool_fallback_workers: u64,
343    /// Maximum number of workers for the asynchronous networking runtime thread pool
344    pub thread_pool_async_runtime_workers_max: u64,
345    /// Maximum number of workers for WebRender
346    pub thread_pool_webrender_workers_max: u64,
347    /// The user-agent to use for Servo. This can also be set via [`UserAgentPlatform`] in
348    /// order to set the value to the default value for the given platform.
349    pub user_agent: String,
350    /// Whether or not the viewport meta tag is enabled.
351    pub viewport_meta_enabled: bool,
352    pub log_filter: String,
353    /// Whether the accessibility code is enabled.
354    pub accessibility_enabled: bool,
355    /// Whether to run accessibility tree integrity checks, and any other expensive checks.
356    /// This should only be true in tests.
357    pub expensive_accessibility_test_assertions_enabled: bool,
358}
359
360impl Preferences {
361    const fn const_default() -> Self {
362        Self {
363            css_animations_testing_enabled: false,
364            editing_caret_blink_time: 600,
365            devtools_server_enabled: false,
366            devtools_server_listen_address: String::new(),
367            dom_abort_controller_enabled: true,
368            dom_adoptedstylesheet_enabled: false,
369            dom_allow_preloading_module_descendants: false,
370            dom_allow_scripts_to_close_windows: false,
371            dom_async_clipboard_enabled: false,
372            dom_bluetooth_enabled: false,
373            dom_bluetooth_testing_enabled: false,
374            dom_canvas_capture_enabled: false,
375            dom_canvas_text_enabled: true,
376            dom_canvas_backend: String::new(),
377            dom_clipboardevent_enabled: true,
378            dom_composition_event_enabled: false,
379            dom_cookiestore_enabled: false,
380            dom_credential_management_enabled: false,
381            dom_crypto_subtle_enabled: true,
382            dom_document_dblclick_dist: 1,
383            dom_document_dblclick_timeout: 300,
384            dom_exec_command_enabled: false,
385            dom_fontface_enabled: false,
386            dom_fullscreen_test: false,
387            dom_gamepad_enabled: true,
388            dom_geolocation_enabled: false,
389            dom_wakelock_enabled: false,
390            dom_indexeddb_enabled: false,
391            dom_intersection_observer_enabled: false,
392            dom_microdata_testing_enabled: false,
393            dom_uievent_which_enabled: true,
394            dom_mutation_observer_enabled: true,
395            dom_navigator_protocol_handlers_enabled: false,
396            dom_notification_enabled: false,
397            dom_parallel_css_parsing_enabled: true,
398            dom_offscreen_canvas_enabled: false,
399            dom_permissions_enabled: false,
400            dom_permissions_testing_allowed_in_nonsecure_contexts: false,
401            dom_resize_observer_enabled: true,
402            dom_sanitizer_enabled: false,
403            dom_script_asynch: true,
404            dom_storage_manager_api_enabled: false,
405            dom_serviceworker_enabled: false,
406            dom_serviceworker_timeout_seconds: 60,
407            dom_sharedworker_enabled: false,
408            dom_servo_helpers_enabled: false,
409            dom_servoparser_async_html_tokenizer_enabled: false,
410            dom_testbinding_enabled: false,
411            dom_testbinding_prefcontrolled2_enabled: false,
412            dom_testbinding_prefcontrolled_enabled: false,
413            dom_testbinding_preference_value_falsy: false,
414            dom_testbinding_preference_value_quote_string_test: String::new(),
415            dom_testbinding_preference_value_space_string_test: String::new(),
416            dom_testbinding_preference_value_string_empty: String::new(),
417            dom_testbinding_preference_value_string_test: String::new(),
418            dom_testbinding_preference_value_truthy: false,
419            dom_testing_element_activation_enabled: false,
420            dom_testing_html_input_element_select_files_enabled: false,
421            dom_testperf_enabled: false,
422            dom_testutils_enabled: false,
423            // Following Firefox and Chrome, we are enabling the touch events legacy APIs for android.
424            // Additionally, enabling it in ohos for compatibility as well.
425            dom_touch_events_legacy_apis_enabled: cfg!(target_os = "android") |
426                cfg!(target_env = "ohos"),
427            dom_transient_activation_duration_ms: 5000,
428            dom_webgl2_enabled: false,
429            dom_webgpu_enabled: false,
430            dom_webgpu_wgpu_backend: String::new(),
431            dom_webrtc_enabled: false,
432            dom_webrtc_transceiver_enabled: false,
433            dom_webvtt_enabled: false,
434            dom_webxr_enabled: true,
435            dom_webxr_first_person_observer_view: false,
436            dom_webxr_glwindow_cubemap: false,
437            dom_webxr_glwindow_enabled: true,
438            dom_webxr_glwindow_left_right: false,
439            dom_webxr_glwindow_red_cyan: false,
440            dom_webxr_glwindow_spherical: false,
441            dom_webxr_hands_enabled: true,
442            dom_webxr_layers_enabled: false,
443            dom_webxr_openxr_enabled: true,
444            dom_webxr_sessionavailable: false,
445            dom_webxr_test: false,
446            dom_webxr_unsafe_assume_user_intent: false,
447            dom_worklet_blockingsleep_enabled: false,
448            dom_worklet_enabled: false,
449            dom_worklet_testing_enabled: false,
450            dom_worklet_timeout_ms: 10,
451            dom_visual_viewport_enabled: false,
452            accessibility_enabled: false,
453            expensive_accessibility_test_assertions_enabled: false,
454            fonts_default: String::new(),
455            fonts_default_monospace_size: 13,
456            fonts_default_size: 16,
457            fonts_monospace: String::new(),
458            fonts_sans_serif: String::new(),
459            fonts_serif: String::new(),
460            gfx_precache_shaders: false,
461            gfx_text_antialiasing_enabled: true,
462            gfx_subpixel_text_antialiasing_enabled: true,
463            gfx_texture_swizzling_enabled: true,
464            image_key_batch_size: 10,
465            inspector_show_servo_internal_shadow_roots: false,
466            intl_locale_override: String::new(),
467            js_asmjs_enabled: true,
468            js_baseline_interpreter_enabled: true,
469            js_baseline_jit_enabled: true,
470            js_baseline_jit_unsafe_eager_compilation_enabled: false,
471            js_disable_jit: false,
472            js_ion_enabled: true,
473            js_ion_unsafe_eager_compilation_enabled: false,
474            js_mem_gc_compacting_enabled: true,
475            js_mem_gc_empty_chunk_count_min: 1,
476            js_mem_gc_high_frequency_heap_growth_max: 300,
477            js_mem_gc_high_frequency_heap_growth_min: 150,
478            js_mem_gc_high_frequency_high_limit_mb: 500,
479            js_mem_gc_high_frequency_low_limit_mb: 100,
480            js_mem_gc_high_frequency_time_limit_ms: 1000,
481            js_mem_gc_incremental_enabled: true,
482            js_mem_gc_incremental_slice_ms: 10,
483            js_mem_gc_low_frequency_heap_growth: 150,
484            js_mem_gc_per_zone_enabled: false,
485            js_mem_gc_zeal_frequency: 100,
486            js_mem_gc_zeal_level: 0,
487            js_mem_max: -1,
488            js_native_regex_enabled: true,
489            js_offthread_compilation_enabled: true,
490            js_timers_minimum_duration: 1000,
491            js_wasm_baseline_enabled: true,
492            js_wasm_enabled: true,
493            js_wasm_ion_enabled: true,
494            largest_contentful_paint_enabled: false,
495            layout_animations_test_enabled: false,
496            layout_columns_enabled: false,
497            layout_container_queries_enabled: false,
498            layout_css_attr_enabled: false,
499            layout_grid_enabled: false,
500            layout_style_sharing_cache_enabled: true,
501            // TODO(mrobinson): This should likely be based on the number of processors.
502            layout_threads: 3,
503            layout_unimplemented: false,
504            layout_variable_fonts_enabled: false,
505            layout_writing_mode_enabled: false,
506            media_glvideo_enabled: false,
507            media_testing_enabled: false,
508            network_connection_timeout: 15,
509            network_enforce_tls_enabled: false,
510            network_enforce_tls_localhost: false,
511            network_enforce_tls_onion: false,
512            network_http_cache_disabled: false,
513            network_http_proxy_uri: String::new(),
514            network_https_proxy_uri: String::new(),
515            network_http_no_proxy: String::new(),
516            network_http_cache_size: 5000,
517            network_local_directory_listing_enabled: true,
518            network_use_webpki_roots: false,
519            session_history_max_length: 20,
520            shell_background_color_rgba: [1.0, 1.0, 1.0, 1.0],
521            log_filter: String::new(),
522            thread_pool_workers_max: 4,
523            thread_pool_async_runtime_workers_max: 6,
524            thread_pool_fallback_workers: 3,
525            thread_pool_webrender_workers_max: 4,
526            webgl_testing_context_creation_error: false,
527            user_agent: String::new(),
528            viewport_meta_enabled: false,
529        }
530    }
531
532    /// The amount of time that a half cycle of a text caret blink takes. If blinking is disabled
533    /// this returns `None`.
534    pub fn editing_caret_blink_time(&self) -> Option<Duration> {
535        if self.editing_caret_blink_time > 0 {
536            Some(Duration::from_millis(self.editing_caret_blink_time as u64))
537        } else {
538            None
539        }
540    }
541}
542
543impl Default for Preferences {
544    fn default() -> Self {
545        let mut preferences = Self::const_default();
546        preferences.user_agent = UserAgentPlatform::default().to_user_agent_string();
547        if let Ok(proxy_uri) = std::env::var("http_proxy").or_else(|_| std::env::var("HTTP_PROXY"))
548        {
549            preferences.network_http_proxy_uri = proxy_uri;
550        }
551        if let Ok(proxy_uri) =
552            std::env::var("https_proxy").or_else(|_| std::env::var("HTTPS_PROXY"))
553        {
554            preferences.network_https_proxy_uri = proxy_uri;
555        }
556        if let Ok(no_proxy) = std::env::var("no_proxy").or_else(|_| std::env::var("NO_PROXY")) {
557            preferences.network_http_no_proxy = no_proxy
558        }
559
560        preferences
561    }
562}
563
564pub enum UserAgentPlatform {
565    Desktop,
566    Android,
567    OpenHarmony,
568    Ios,
569}
570
571impl UserAgentPlatform {
572    /// Return the default `UserAgentPlatform` for this platform. This is
573    /// not an implementation of `Default` so that it can be `const`.
574    pub const fn default() -> Self {
575        if cfg!(target_os = "android") {
576            Self::Android
577        } else if cfg!(target_env = "ohos") {
578            Self::OpenHarmony
579        } else if cfg!(target_os = "ios") {
580            Self::Ios
581        } else {
582            Self::Desktop
583        }
584    }
585}
586
587impl UserAgentPlatform {
588    /// Convert this [`UserAgentPlatform`] into its corresponding `String` value, ie the
589    /// default user-agent to use for this platform.
590    pub fn to_user_agent_string(&self) -> String {
591        const SERVO_VERSION: &str = env!("CARGO_PKG_VERSION");
592        match self {
593            UserAgentPlatform::Desktop
594                if cfg!(all(target_os = "windows", target_arch = "x86_64")) =>
595            {
596                format!(
597                    "Mozilla/5.0 (Windows NT 10.0; Win64; {ARCH}rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
598                )
599            },
600            UserAgentPlatform::Desktop if cfg!(target_os = "macos") => {
601                format!(
602                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
603                )
604            },
605            UserAgentPlatform::Desktop => {
606                format!(
607                    "Mozilla/5.0 (X11; Linux {ARCH}; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
608                )
609            },
610            UserAgentPlatform::Android => {
611                format!(
612                    "Mozilla/5.0 (Android 10; Mobile; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
613                )
614            },
615            UserAgentPlatform::OpenHarmony => format!(
616                "Mozilla/5.0 (OpenHarmony; Mobile; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
617            ),
618            UserAgentPlatform::Ios => format!(
619                "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X; rv:140.0) Servo/{SERVO_VERSION} Firefox/140.0"
620            ),
621        }
622    }
623}