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.
50    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/// A convenience macro for accessing a preference value using its static path.
84/// Passing an invalid path is a compile-time error.
85#[macro_export]
86macro_rules! pref {
87    ($name: ident) => {
88        $crate::prefs::get().$name.clone()
89    };
90}
91
92/// The set of global preferences supported by Servo.
93///
94/// Each preference has a default value that determines its initial state. These defaults
95/// fall into roughly three categories:
96/// - **Stable**: enabled by default.
97/// - **Experimental**: disabled by default, but intended to be enabled for experimental use.
98/// - **Unstable**: disabled by default.
99///
100/// For a full overview of which preferences are experimental, see the
101/// [experimental features documentation](https://book.servo.org/design-documentation/experimental-features.html).
102#[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    /// The amount of time that a half cycle of a text caret blink takes in milliseconds.
111    /// If this value is less than or equal to zero, then caret blink is disabled.
112    pub editing_caret_blink_time: i64,
113    pub css_animations_testing_enabled: bool,
114    /// Start the devtools server at startup
115    pub devtools_server_enabled: bool,
116    /// The address:port the devtools server listens to, default to 127.0.0.1:7000.
117    pub devtools_server_listen_address: String,
118    // feature: WebGPU | #24706 | Web/API/WebGPU_API
119    pub dom_webgpu_enabled: bool,
120    /// List of comma-separated backends to be used by wgpu.
121    pub dom_webgpu_wgpu_backend: String,
122    // feature: Adopted Stylesheet | #38132 | Web/API/Document/adoptedStyleSheets
123    pub dom_adoptedstylesheet_enabled: bool,
124    pub dom_allow_preloading_module_descendants: bool,
125    // feature: Clipboard API | #36084 | Web/API/Clipboard_API
126    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    // feature: Media Capture and Streams API | #26861 | Web/API/Media_Capture_and_Streams_API
131    pub dom_canvas_capture_enabled: bool,
132    pub dom_canvas_text_enabled: bool,
133    /// Selects canvas backend
134    ///
135    /// Available values:
136    /// - vello
137    /// - Everything else selects vello_cpu
138    pub dom_canvas_backend: String,
139    /// Maximum number of buffered canvas commands before an automatic flush is triggered.
140    ///
141    /// A lower value keeps the paint thread fed with work (better parallelism),
142    /// while a higher value improves batching efficiency (fewer channel operations, lower power).
143    ///
144    /// See <https://github.com/servo/servo/pull/45301> for measurements.
145    pub dom_canvas_msg_buffer_size: u64,
146    pub dom_composition_event_enabled: bool,
147    // feature: CookieStore | #37674 | Web/API/CookieStore
148    pub dom_cookiestore_enabled: bool,
149    // feature: Credential Management API | #38788 | Web/API/Credential_Management_API
150    pub dom_credential_management_enabled: bool,
151    // feature: WebCrypto API | #40687 | Web/API/Web_Crypto_API
152    pub dom_crypto_subtle_enabled: bool,
153    pub dom_document_dblclick_timeout: i64,
154    pub dom_document_dblclick_dist: i64,
155    // feature: File and Directory Entries API | #45653 | Web/API/File_and_Directory_Entries_API
156    pub dom_entries_api_enabled: bool,
157    // feature: Document.execCommand | #25005 | Web/API/Document/execCommand
158    pub dom_exec_command_enabled: bool,
159    // feature: CSS Font Loading API | #29376 | Web/API/CSS_Font_Loading_API
160    pub dom_fontface_enabled: bool,
161    pub dom_fullscreen_test: bool,
162    // feature: Gamepad API | #10977 | Web/API/Gamepad_API
163    pub dom_gamepad_enabled: bool,
164    // feature: Geolocation API | #38903 | Web/API/Geolocation_API
165    pub dom_geolocation_enabled: bool,
166    /// Make the built-in geolocation backend report a fixed position instead of reporting that
167    /// no position is available for testing purposes.
168    pub dom_geolocation_test_position_enabled: bool,
169    /// The accuracy, in meters, reported when `dom_geolocation_test_position_enabled` is set.
170    pub dom_geolocation_test_accuracy: f64,
171    /// The heading, in degrees, reported when `dom_geolocation_test_position_enabled` is set.
172    pub dom_geolocation_test_heading: f64,
173    /// The latitude, in degrees, reported when `dom_geolocation_test_position_enabled` is set.
174    pub dom_geolocation_test_latitude: f64,
175    /// The longitude, in degrees, reported when `dom_geolocation_test_position_enabled` is set.
176    pub dom_geolocation_test_longitude: f64,
177    /// The speed, in meters per second, reported when `dom_geolocation_test_position_enabled`
178    /// is set.
179    pub dom_geolocation_test_speed: f64,
180    // feature: Screen Wake Lock API | #43615 | Web/API/Screen_Wake_Lock_API
181    pub dom_wakelock_enabled: bool,
182    // feature: IndexedDB | #6963 | Web/API/IndexedDB_API
183    pub dom_indexeddb_enabled: bool,
184    // feature: IntersectionObserver | #35767 | Web/API/Intersection_Observer_API
185    pub dom_intersection_observer_enabled: bool,
186    pub dom_microdata_testing_enabled: bool,
187    // feature: Navigator.registerProtocolHandler() | #40615 | Web/API/Navigator/registerProtocolHandler
188    pub dom_navigator_protocol_handlers_enabled: bool,
189    // feature: Notification API | #34841 | Web/API/Notifications_API
190    pub dom_notification_enabled: bool,
191    // feature: OffscreenCanvas | #34111 | Web/API/OffscreenCanvas
192    pub dom_offscreen_canvas_enabled: bool,
193    pub dom_parallel_css_parsing_enabled: bool,
194    // feature: Permissions API | #31235 | Web/API/Permissions_API
195    pub dom_permissions_enabled: bool,
196    pub dom_permissions_testing_allowed_in_nonsecure_contexts: bool,
197    // feature: ResizeObserver | #39790 | Web/API/ResizeObserver
198    pub dom_resize_observer_enabled: bool,
199    // feature: Sanitizer API | #43948 | Web/API/HTML_Sanitizer_API
200    pub dom_sanitizer_enabled: bool,
201    pub dom_script_asynch: bool,
202    // feature: Storage API | #43976 | Web/API/Storage_API
203    pub dom_storage_manager_api_enabled: bool,
204    // feature: ServiceWorker | #36538 | Web/API/Service_Worker_API
205    pub dom_serviceworker_enabled: bool,
206    pub dom_serviceworker_timeout_seconds: i64,
207    // feature: SharedWorker | #7458 | Web/API/SharedWorker
208    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    // https://testutils.spec.whatwg.org#availability
224    pub dom_testutils_enabled: bool,
225    /// <https://w3c.github.io/touch-events/#conditionally-exposing-legacy-touch-event-apis>
226    pub dom_touch_events_legacy_apis_enabled: bool,
227    /// <https://html.spec.whatwg.org/multipage/#transient-activation-duration>
228    pub dom_transient_activation_duration_ms: i64,
229    // feature: Web Animations | #36950 | Web/API/Web_Animations_API
230    pub dom_web_animations_enabled: bool,
231    /// Enable WebGL2 APIs.
232    // feature: WebGL2 | #41394 | Web/API/WebGL2RenderingContext
233    pub dom_webgl2_enabled: bool,
234    // feature: WebRTC | #41396 | Web/API/WebRTC_API
235    pub dom_webrtc_enabled: bool,
236    // feature: WebRTC Transceiver | #41396 | Web/API/RTCRtpTransceiver
237    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    // feature: WebXR Layers | #27468 | Web/API/XRCompositionLayer
248    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    /// <https://drafts.csswg.org/cssom-view/#the-visualviewport-interface>
257    // feature: VisualViewport | #41341 | Web/API/VisualViewport
258    pub dom_visual_viewport_enabled: bool,
259    /// True to compile all WebRender shaders when Servo initializes. This is mostly
260    /// useful when modifying the shaders, to ensure they all compile after each change is
261    /// made.
262    pub gfx_precache_shaders: bool,
263    /// Whether or not antialiasing is enabled for text rendering.
264    pub gfx_text_antialiasing_enabled: bool,
265    /// Whether or not subpixel antialiasing is enabled for text rendering.
266    pub gfx_subpixel_text_antialiasing_enabled: bool,
267    pub gfx_texture_swizzling_enabled: bool,
268    /// The amount of image keys we request per batch for the image cache.
269    pub image_key_batch_size: i64,
270    /// Whether or not the DOM inspector should show shadow roots of user-agent shadow trees
271    pub inspector_show_servo_internal_shadow_roots: bool,
272    /// A locale tag (eg. es-ES) to use for language negotiation instead of the system locale.
273    /// An empty string represents no override.
274    /// TODO: Option<> support in PrefValue
275    pub intl_locale_override: String,
276    pub js_asmjs_enabled: bool,
277    pub js_baseline_interpreter_enabled: bool,
278    /// Whether to disable the jit within SpiderMonkey
279    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    /// Whether or not incremental garbage collection is turned on. This is currently
292    /// turned off by default as pre-barriers are not implemented yet. If turned on, it
293    /// will likely lead to memory corruption.
294    ///
295    /// See <https://github.com/servo/servo/issues/7621>.
296    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    // feature: Container Timing| #48490 | Web/API/ContainerTiming
312    pub container_timing_enabled: bool,
313    // feature: Largest Contentful Paint | #42000 | Web/API/LargestContentfulPaint
314    pub largest_contentful_paint_enabled: bool,
315    pub layout_animations_test_enabled: bool,
316    pub layout_css_backdrop_filter_enabled: bool,
317    // feature: CSS Multicol | #22397 | Web/CSS/Guides/Multicol_layout
318    pub layout_css_columns_enabled: bool,
319    pub layout_css_container_queries_enabled: bool,
320    pub layout_css_ellipse_corners_enabled: bool,
321    // feature: Variable fonts | #38800 | Web/CSS/Guides/Fonts/Variable_fonts
322    pub layout_css_font_variations_enabled: bool,
323    // feature: CSS writing modes | #2560 | Web/CSS/Guides/Writing_modes
324    pub layout_css_writing_mode_enabled: bool,
325    pub layout_style_sharing_cache_enabled: bool,
326    pub layout_threads: i64,
327    /// The minimum number of parallelizable jobs required before turning on parallelism
328    /// for a set of jobs.
329    ///
330    /// When deciding whether or not to parallelize layout, this is the minimum number of
331    /// jobs that must be larger than [`Self::layout_parallelism_job_size_minimum`] to
332    /// turn on parallelism. An exception is when doing box tree layout, where Servo does
333    /// not know the depth of the tree. In that case any task that has more jobs than this
334    /// value will be parallelized.
335    ///
336    /// The goal of these two values is to allow tuning Servo's parallelism for both wide
337    /// and deep trees.
338    pub layout_parallelism_job_count_minimum: u64,
339    /// The minimum size of a layout job to be considered for parallelization.
340    ///
341    /// When deciding whether or not to parallelize layout, jobs greater than this size
342    /// are counted when considering the [`Self::layout_parallelism_job_count_minimum`]
343    /// threshold for turning on parallelism. Generally the size of the job is based on
344    /// the number of tasks to process in the subtree. For instance, this might be the
345    /// number of boxes to process in a box tree subtree.
346    ///
347    /// The goal of these two values is to allow tuning Servo's parallelism for both wide
348    /// and deep trees.
349    pub layout_parallelism_job_size_minimum: u64,
350    /// feature: MathML | #49078 | Web/MathML
351    pub mathml_core_enabled: bool,
352    /// Enable hardware acceleration for video playback.
353    pub media_glvideo_enabled: bool,
354    /// Enable a non-standard event handler for verifying behavior of media elements during tests.
355    pub media_testing_enabled: bool,
356    /// The default timeout set for establishing a network connection in seconds. This amount
357    /// if for the entire process of connecting to an address. For instance, if a particular host is
358    /// associated with multiple IP addresses, this timeout will be divided equally among
359    /// each IP address.
360    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    /// The path to a disk cache file. Empty string disables the disk cache.
366    pub network_http_disk_cache: String,
367    /// Maximum size of the disk cache file in bytes.
368    pub network_http_disk_cache_size: u64,
369    /// A url for a http proxy. We treat an empty string as no proxy.
370    pub network_http_proxy_uri: String,
371    /// A url for a https proxy. We treat an empty string as no proxy.
372    pub network_https_proxy_uri: String,
373    /// The domains for which we will not have a proxy. No effect if `network_http_proxy_uri` is not set.
374    /// The exact behavior is given by
375    /// <https://docs.rs/hyper-util/latest/hyper_util/client/proxy/matcher/struct.Builder.html#method.no>
376    pub network_http_no_proxy: String,
377    /// The weight of the http memory cache
378    /// Notice that this is not equal to the number of different urls in the cache.
379    pub network_http_cache_size: u64,
380    pub network_local_directory_listing_enabled: bool,
381    /// Force the use of `rust-webpki` verification for CA roots. If this is false (the
382    /// default), then `rustls-platform-verifier` will be used, except on Android where
383    /// `rust-webpki` is always used.
384    pub network_use_webpki_roots: bool,
385    /// The maximum content size we will forward for preallocation, defaults to 5MB
386    pub network_max_content_length: u64,
387    /// Experimental option. If enabled servo will attempt to optimize thread placement
388    /// and/or priority of critical servo threads to optimize performance.
389    #[doc(hidden)]
390    pub perf_thread_boost_enabled: bool,
391    /// The length of the session history, in navigations, for each `WebView. Back-forward
392    /// cache entries that are more than `session_history_max_length` steps in the future or
393    /// `session_history_max_length` steps in the past will be discarded. Navigating forward
394    /// or backward to that entry will cause the entire page to be reloaded.
395    pub session_history_max_length: i64,
396    /// The background color of shell's viewport. This will be used by OpenGL's `glClearColor`.
397    pub shell_background_color_rgba: [f64; 4],
398    pub webgl_testing_context_creation_error: bool,
399    /// Maximum number of workers for the main thread pool
400    pub thread_pool_workers_max: u64,
401    /// Number of workers per thread pool, if we fail to detect how much
402    /// parallelism is available at runtime.
403    pub thread_pool_fallback_workers: u64,
404    /// Maximum number of workers for the asynchronous networking runtime thread pool
405    pub thread_pool_async_runtime_workers_max: u64,
406    /// Number of worker threads used to rasterize a canvas.
407    /// This preference currently only affects the vello_cpu backend.
408    /// Setting this pref to `0` uses the single-threaded backend and
409    /// avoids creating a threadpool.
410    /// For small canvas sizes this pref is ignored and no threadpool is created.
411    pub thread_pool_canvas_workers: u64,
412    /// Maximum number of workers for WebRender
413    pub thread_pool_webrender_workers_max: u64,
414    /// The user-agent to use for Servo. This can also be set via [`UserAgentPlatform`] in
415    /// order to set the value to the default value for the given platform.
416    pub user_agent: String,
417    /// Whether or not the viewport meta tag is enabled.
418    pub viewport_meta_enabled: bool,
419    pub log_filter: String,
420    /// Whether the accessibility code is enabled.
421    pub accessibility_enabled: bool,
422    /// Whether to run accessibility tree integrity checks, and any other expensive checks.
423    /// This should only be true in tests.
424    pub expensive_accessibility_test_assertions_enabled: bool,
425    /// Exposes internal JS API functions that are usually restricted to `about:...` pages
426    /// Useful if you want to get memory report or force GC in a test page
427    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            // Following Firefox and Chrome, we are enabling the touch events legacy APIs for android.
498            // Additionally, enabling it in ohos for compatibility as well.
499            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            // The layout system currently does not work with compacting GC, so it is disabled by default.
549            // See https://github.com/servo/servo/issues/47577
550            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            // TODO(mrobinson): This should likely be based on the number of processors.
583            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, // Roughtly 100MB
596            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            // <https://github.com/linebender/vello/blob/c95b228e1cf73bf96338e8c8ae0d145553f8f99c/sparse_strips/vello_cpu/examples/basic.rs#L51>
611            // According to this example 2-4 give the best results.
612            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    /// The amount of time that a half cycle of a text caret blink takes. If blinking is disabled
622    /// this returns `None`.
623    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    /// Return the default `UserAgentPlatform` for this platform. This is
662    /// not an implementation of `Default` so that it can be `const`.
663    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    /// Convert this [`UserAgentPlatform`] into its corresponding `String` value, ie the
678    /// default user-agent to use for this platform.
679    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}