1use std::cell::{Cell, Ref, RefCell, RefMut};
6use std::cmp::max;
7use std::rc::{Rc, Weak};
8use std::sync::Arc;
9use std::time::Duration;
10
11use background_hang_monitor::HangMonitorRegister;
12use base::generic_channel::{GenericCallback, GenericSender, RoutedReceiver};
13pub use base::id::WebViewId;
14use base::id::{PipelineNamespace, PipelineNamespaceId};
15#[cfg(feature = "bluetooth")]
16use bluetooth::BluetoothThreadFactory;
17#[cfg(feature = "bluetooth")]
18use bluetooth_traits::BluetoothRequest;
19#[cfg(all(
20 not(target_os = "windows"),
21 not(target_os = "ios"),
22 not(target_os = "android"),
23 not(target_arch = "arm"),
24 not(target_arch = "aarch64"),
25 not(target_env = "ohos"),
26))]
27use constellation::content_process_sandbox_profile;
28use constellation::{
29 Constellation, FromEmbedderLogger, FromScriptLogger, InitialConstellationState,
30 NewScriptEventLoopProcessInfo, UnprivilegedContent,
31};
32use constellation_traits::{EmbedderToConstellationMessage, ScriptToConstellationSender};
33use crossbeam_channel::{Receiver, Sender, unbounded};
34pub use embedder_traits::*;
35use env_logger::Builder as EnvLoggerBuilder;
36use fonts::SystemFontService;
37#[cfg(all(
38 not(target_os = "windows"),
39 not(target_os = "ios"),
40 not(target_os = "android"),
41 not(target_arch = "arm"),
42 not(target_arch = "aarch64"),
43 not(target_env = "ohos"),
44))]
45use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
46use ipc_channel::ipc::{self, IpcSender};
47use layout::LayoutFactoryImpl;
48use layout_api::ScriptThreadFactory;
49use log::{Log, Metadata, Record, debug, warn};
50use media::{GlApi, NativeDisplay, WindowGLContext};
51use net::embedder::NetToEmbedderMsg;
52use net::image_cache::ImageCacheFactoryImpl;
53use net::protocols::ProtocolRegistry;
54use net::resource_thread::new_resource_threads;
55use net_traits::{ResourceThreads, exit_fetch_thread, start_fetch_thread};
56use paint::{InitialPaintState, Paint};
57pub use paint_api::rendering_context::RenderingContext;
58use paint_api::{CrossProcessPaintApi, PaintMessage, PaintProxy};
59use profile::{mem as profile_mem, system_reporter, time as profile_time};
60use profile_traits::mem::{MemoryReportResult, ProfilerMsg, Reporter};
61use profile_traits::{mem, time};
62use rustc_hash::FxHashMap;
63use script::{JSEngineSetup, ServiceWorkerManager};
64use servo_config::opts::Opts;
65use servo_config::prefs::{PrefValue, Preferences};
66use servo_config::{opts, pref, prefs};
67use servo_geometry::{
68 DeviceIndependentIntRect, convert_rect_to_css_pixel, convert_size_to_css_pixel,
69};
70use servo_media::ServoMedia;
71use servo_media::player::context::GlContext;
72use storage::new_storage_threads;
73use storage_traits::StorageThreads;
74use style::global_style_data::StyleThreadPool;
75
76use crate::clipboard_delegate::StringRequest;
77use crate::javascript_evaluator::JavaScriptEvaluator;
78use crate::network_manager::NetworkManager;
79use crate::proxies::ConstellationProxy;
80use crate::responders::ServoErrorChannel;
81use crate::servo_delegate::{DefaultServoDelegate, ServoDelegate, ServoError};
82use crate::site_data_manager::SiteDataManager;
83use crate::webview::{MINIMUM_WEBVIEW_SIZE, WebView, WebViewInner};
84use crate::webview_delegate::{
85 AllowOrDenyRequest, AuthenticationRequest, EmbedderControl, FilePicker, NavigationRequest,
86 PermissionRequest, ProtocolHandlerRegistration, WebResourceLoad,
87};
88
89#[cfg(feature = "media-gstreamer")]
90mod media_platform {
91 #[cfg(any(windows, target_os = "macos"))]
92 mod gstreamer_plugins {
93 include!(concat!(env!("OUT_DIR"), "/gstreamer_plugins.rs"));
94 }
95
96 use servo_media_gstreamer::GStreamerBackend;
97
98 use super::ServoMedia;
99
100 #[cfg(any(windows, target_os = "macos"))]
101 pub fn init() {
102 ServoMedia::init_with_backend(|| {
103 let mut plugin_dir = std::env::current_exe().unwrap();
104 plugin_dir.pop();
105
106 if cfg!(target_os = "macos") {
107 plugin_dir.push("lib");
108 }
109
110 match GStreamerBackend::init_with_plugins(
111 plugin_dir,
112 gstreamer_plugins::GSTREAMER_PLUGINS,
113 ) {
114 Ok(b) => b,
115 Err(e) => {
116 log::error!("Error initializing GStreamer: {:?}", e);
117 std::process::exit(1);
118 },
119 }
120 });
121 }
122
123 #[cfg(not(any(windows, target_os = "macos")))]
124 pub fn init() {
125 ServoMedia::init::<GStreamerBackend>();
126 }
127}
128
129#[cfg(not(feature = "media-gstreamer"))]
130mod media_platform {
131 use super::ServoMedia;
132 pub fn init() {
133 ServoMedia::init::<servo_media_dummy::DummyBackend>();
134 }
135}
136
137enum Message {
138 FromNet(NetToEmbedderMsg),
139 FromUnknown(EmbedderMsg),
140}
141
142struct ServoInner {
143 delegate: RefCell<Rc<dyn ServoDelegate>>,
144 paint: Rc<RefCell<Paint>>,
145 constellation_proxy: ConstellationProxy,
146 embedder_receiver: Receiver<EmbedderMsg>,
147 net_embedder_receiver: Receiver<NetToEmbedderMsg>,
148 network_manager: Rc<RefCell<NetworkManager>>,
149 site_data_manager: Rc<RefCell<SiteDataManager>>,
150 javascript_evaluator: Rc<RefCell<JavaScriptEvaluator>>,
153 shutdown_state: Rc<Cell<ShutdownState>>,
156 webviews: RefCell<FxHashMap<WebViewId, Weak<RefCell<WebViewInner>>>>,
161 servo_errors: ServoErrorChannel,
162 _js_engine_setup: Option<JSEngineSetup>,
166}
167
168impl ServoInner {
169 fn get_webview_handle(&self, id: WebViewId) -> Option<WebView> {
170 self.webviews
171 .borrow()
172 .get(&id)
173 .and_then(WebView::from_weak_handle)
174 }
175
176 fn spin_event_loop(&self) -> bool {
177 if self.shutdown_state.get() == ShutdownState::FinishedShuttingDown {
178 return false;
179 }
180
181 {
182 let paint = self.paint.borrow();
183 let mut messages = Vec::new();
184 while let Ok(message) = paint.receiver().try_recv() {
185 match message {
186 Ok(message) => messages.push(message),
187 Err(error) => {
188 warn!("Router deserialization error: {error}. Ignoring this PaintMessage.")
189 },
190 }
191 }
192 paint.handle_messages(messages);
193 }
194
195 while let Some(message) = self.receive_one_message() {
197 match message {
198 Message::FromUnknown(message) => self.handle_embedder_message(message),
199 Message::FromNet(message) => self.handle_net_embedder_message(message),
200 }
201 if self.shutdown_state.get() == ShutdownState::FinishedShuttingDown {
202 break;
203 }
204 }
205
206 if self.constellation_proxy.disconnected() {
207 self.delegate
208 .borrow()
209 .notify_error(ServoError::LostConnectionWithBackend);
210 }
211
212 self.paint.borrow_mut().perform_updates();
213 self.send_new_frame_ready_messages();
214 self.handle_delegate_errors();
215 self.clean_up_destroyed_webview_handles();
216
217 if self.shutdown_state.get() == ShutdownState::FinishedShuttingDown {
218 return false;
219 }
220
221 true
222 }
223
224 fn receive_one_message(&self) -> Option<Message> {
225 let mut select = crossbeam_channel::Select::new();
226 let embedder_receiver_index = select.recv(&self.embedder_receiver);
227 let net_embedder_receiver_index = select.recv(&self.net_embedder_receiver);
228 let Ok(operation) = select.try_select() else {
229 return None;
230 };
231 let index = operation.index();
232 if index == embedder_receiver_index {
233 let Ok(message) = operation.recv(&self.embedder_receiver) else {
234 return None;
235 };
236 Some(Message::FromUnknown(message))
237 } else if index == net_embedder_receiver_index {
238 let Ok(message) = operation.recv(&self.net_embedder_receiver) else {
239 return None;
240 };
241 Some(Message::FromNet(message))
242 } else {
243 log::error!("No select operation registered for {index:?}");
244 None
245 }
246 }
247
248 fn send_new_frame_ready_messages(&self) {
249 let webviews_needing_repaint = self.paint.borrow().webviews_needing_repaint();
250
251 for webview in webviews_needing_repaint
252 .iter()
253 .filter_map(|webview_id| self.get_webview_handle(*webview_id))
254 {
255 webview.delegate().notify_new_frame_ready(webview);
256 }
257 }
258
259 fn handle_delegate_errors(&self) {
260 while let Some(error) = self.servo_errors.try_recv() {
261 self.delegate.borrow().notify_error(error);
262 }
263 }
264
265 fn clean_up_destroyed_webview_handles(&self) {
266 self.webviews
271 .borrow_mut()
272 .retain(|_webview_id, webview| webview.strong_count() > 0);
273 }
274
275 fn finish_shutting_down(&self) {
276 debug!("Servo received message that Constellation shutdown is complete");
277 self.shutdown_state.set(ShutdownState::FinishedShuttingDown);
278 self.paint.borrow_mut().finish_shutting_down();
279 }
280
281 fn handle_net_embedder_message(&self, message: NetToEmbedderMsg) {
282 match message {
283 NetToEmbedderMsg::SelectFiles(control_id, file_picker_request, response_sender) => {
284 if file_picker_request.accept_current_paths_for_testing {
285 let _ = response_sender.send(Some(file_picker_request.current_paths));
286 return;
287 }
288 if let Some(webview) = self.get_webview_handle(control_id.webview_id) {
289 webview.delegate().show_embedder_control(
290 webview,
291 EmbedderControl::FilePicker(FilePicker {
292 id: control_id,
293 file_picker_request,
294 response_sender: Some(response_sender),
295 }),
296 );
297 }
298 },
299 NetToEmbedderMsg::WebResourceRequested(
300 webview_id,
301 web_resource_request,
302 response_sender,
303 ) => {
304 if let Some(webview) =
305 webview_id.and_then(|webview_id| self.get_webview_handle(webview_id))
306 {
307 let web_resource_load = WebResourceLoad::new(
308 web_resource_request,
309 response_sender,
310 self.servo_errors.sender(),
311 );
312 webview
313 .delegate()
314 .load_web_resource(webview, web_resource_load);
315 } else {
316 let web_resource_load = WebResourceLoad::new(
317 web_resource_request,
318 response_sender,
319 self.servo_errors.sender(),
320 );
321 self.delegate.borrow().load_web_resource(web_resource_load);
322 }
323 },
324 NetToEmbedderMsg::RequestAuthentication(
325 webview_id,
326 url,
327 for_proxy,
328 response_sender,
329 ) => {
330 if let Some(webview) = self.get_webview_handle(webview_id) {
331 let authentication_request = AuthenticationRequest::new(
332 url.into_url(),
333 for_proxy,
334 response_sender,
335 self.servo_errors.sender(),
336 );
337 webview
338 .delegate()
339 .request_authentication(webview, authentication_request);
340 }
341 },
342 }
343 }
344
345 fn handle_embedder_message(&self, message: EmbedderMsg) {
346 match message {
347 EmbedderMsg::ShutdownComplete => self.finish_shutting_down(),
348 EmbedderMsg::Status(webview_id, status_text) => {
349 if let Some(webview) = self.get_webview_handle(webview_id) {
350 webview.set_status_text(status_text);
351 }
352 },
353 EmbedderMsg::ChangePageTitle(webview_id, title) => {
354 if let Some(webview) = self.get_webview_handle(webview_id) {
355 webview.set_page_title(title);
356 }
357 },
358 EmbedderMsg::MoveTo(webview_id, position) => {
359 if let Some(webview) = self.get_webview_handle(webview_id) {
360 webview.delegate().request_move_to(webview, position);
361 }
362 },
363 EmbedderMsg::ResizeTo(webview_id, size) => {
364 if let Some(webview) = self.get_webview_handle(webview_id) {
365 webview
366 .delegate()
367 .request_resize_to(webview, size.max(MINIMUM_WEBVIEW_SIZE));
368 }
369 },
370 EmbedderMsg::ShowSimpleDialog(webview_id, simple_dialog) => {
371 if let Some(webview) = self.get_webview_handle(webview_id) {
372 webview.delegate().show_embedder_control(
373 webview,
374 EmbedderControl::SimpleDialog(simple_dialog.into()),
375 );
376 }
377 },
378 EmbedderMsg::AllowNavigationRequest(webview_id, pipeline_id, servo_url) => {
379 if let Some(webview) = self.get_webview_handle(webview_id) {
380 let request = NavigationRequest {
381 url: servo_url.into_url(),
382 pipeline_id,
383 constellation_proxy: self.constellation_proxy.clone(),
384 response_sent: false,
385 };
386 webview.delegate().request_navigation(webview, request);
387 }
388 },
389 EmbedderMsg::AllowProtocolHandlerRequest(
390 webview_id,
391 registration_update,
392 response_sender,
393 ) => {
394 if let Some(webview) = self.get_webview_handle(webview_id) {
395 let ProtocolHandlerUpdateRegistration {
396 scheme,
397 url,
398 register_or_unregister,
399 } = registration_update;
400 let protocol_handler_registration = ProtocolHandlerRegistration {
401 scheme,
402 url: url.into_url(),
403 register_or_unregister,
404 };
405 let allow_deny_request = AllowOrDenyRequest::new(
406 response_sender,
407 AllowOrDeny::Deny,
408 self.servo_errors.sender(),
409 );
410 webview.delegate().request_protocol_handler(
411 webview,
412 protocol_handler_registration,
413 allow_deny_request,
414 );
415 }
416 },
417 EmbedderMsg::AllowOpeningWebView(webview_id, response_sender) => {
418 if let Some(webview) = self.get_webview_handle(webview_id) {
419 webview.request_create_new(response_sender);
420 }
421 },
422 EmbedderMsg::WebViewClosed(webview_id) => {
423 if let Some(webview) = self.get_webview_handle(webview_id) {
424 webview.delegate().notify_closed(webview);
425 }
426 },
427 EmbedderMsg::WebViewFocused(webview_id, focus_result) => {
428 if focus_result {
429 for id in self.webviews.borrow().keys() {
430 if let Some(webview) = self.get_webview_handle(*id) {
431 let focused = webview.id() == webview_id;
432 webview.set_focused(focused);
433 }
434 }
435 }
436 },
437 EmbedderMsg::WebViewBlurred => {
438 for id in self.webviews.borrow().keys() {
439 if let Some(webview) = self.get_webview_handle(*id) {
440 webview.set_focused(false);
441 }
442 }
443 },
444 EmbedderMsg::AllowUnload(webview_id, response_sender) => {
445 if let Some(webview) = self.get_webview_handle(webview_id) {
446 let request = AllowOrDenyRequest::new(
447 response_sender,
448 AllowOrDeny::Allow,
449 self.servo_errors.sender(),
450 );
451 webview.delegate().request_unload(webview, request);
452 }
453 },
454 EmbedderMsg::FinishJavaScriptEvaluation(evaluation_id, result) => {
455 self.javascript_evaluator
456 .borrow_mut()
457 .finish_evaluation(evaluation_id, result);
458 },
459 EmbedderMsg::InputEventHandled(webview_id, input_event_id, result) => {
460 self.paint.borrow_mut().notify_input_event_handled(
461 webview_id,
462 input_event_id,
463 result,
464 );
465
466 if let Some(webview) = self.get_webview_handle(webview_id) {
467 webview
468 .delegate()
469 .notify_input_event_handled(webview, input_event_id, result);
470 }
471 },
472 EmbedderMsg::ClearClipboard(webview_id) => {
473 if let Some(webview) = self.get_webview_handle(webview_id) {
474 webview.clipboard_delegate().clear(webview);
475 }
476 },
477 EmbedderMsg::GetClipboardText(webview_id, result_sender) => {
478 if let Some(webview) = self.get_webview_handle(webview_id) {
479 webview
480 .clipboard_delegate()
481 .get_text(webview, StringRequest::from(result_sender));
482 }
483 },
484 EmbedderMsg::SetClipboardText(webview_id, string) => {
485 if let Some(webview) = self.get_webview_handle(webview_id) {
486 webview.clipboard_delegate().set_text(webview, string);
487 }
488 },
489 EmbedderMsg::SetCursor(webview_id, cursor) => {
490 if let Some(webview) = self.get_webview_handle(webview_id) {
491 webview.set_cursor(cursor);
492 }
493 },
494 EmbedderMsg::NewFavicon(webview_id, image) => {
495 if let Some(webview) = self.get_webview_handle(webview_id) {
496 webview.set_favicon(image);
497 }
498 },
499 EmbedderMsg::NotifyLoadStatusChanged(webview_id, load_status) => {
500 if let Some(webview) = self.get_webview_handle(webview_id) {
501 webview.set_load_status(load_status);
502 }
503 },
504 EmbedderMsg::HistoryTraversalComplete(webview_id, traversal_id) => {
505 if let Some(webview) = self.get_webview_handle(webview_id) {
506 webview
507 .delegate()
508 .notify_traversal_complete(webview.clone(), traversal_id);
509 }
510 },
511 EmbedderMsg::HistoryChanged(webview_id, new_back_forward_list, current_list_index) => {
512 if let Some(webview) = self.get_webview_handle(webview_id) {
513 webview.set_history(new_back_forward_list, current_list_index);
514 }
515 },
516 EmbedderMsg::NotifyFullscreenStateChanged(webview_id, fullscreen) => {
517 if let Some(webview) = self.get_webview_handle(webview_id) {
518 webview
519 .delegate()
520 .notify_fullscreen_state_changed(webview, fullscreen);
521 }
522 },
523 EmbedderMsg::Panic(webview_id, reason, backtrace) => {
524 if let Some(webview) = self.get_webview_handle(webview_id) {
525 webview
526 .delegate()
527 .notify_crashed(webview, reason, backtrace);
528 }
529 },
530 EmbedderMsg::GetSelectedBluetoothDevice(webview_id, items, response_sender) => {
531 if let Some(webview) = self.get_webview_handle(webview_id) {
532 webview.delegate().show_bluetooth_device_dialog(
533 webview,
534 items,
535 response_sender,
536 );
537 }
538 },
539 EmbedderMsg::PromptPermission(webview_id, requested_feature, response_sender) => {
540 if let Some(webview) = self.get_webview_handle(webview_id) {
541 let permission_request = PermissionRequest {
542 requested_feature,
543 allow_deny_request: AllowOrDenyRequest::new(
544 response_sender,
545 AllowOrDeny::Deny,
546 self.servo_errors.sender(),
547 ),
548 };
549 webview
550 .delegate()
551 .request_permission(webview, permission_request);
552 }
553 },
554 EmbedderMsg::ReportProfile(_items) => {},
555 EmbedderMsg::MediaSessionEvent(webview_id, media_session_event) => {
556 if let Some(webview) = self.get_webview_handle(webview_id) {
557 webview
558 .delegate()
559 .notify_media_session_event(webview, media_session_event);
560 }
561 },
562 EmbedderMsg::OnDevtoolsStarted(port, token) => match port {
563 Ok(port) => self
564 .delegate
565 .borrow()
566 .notify_devtools_server_started(port, token),
567 Err(()) => self
568 .delegate
569 .borrow()
570 .notify_error(ServoError::DevtoolsFailedToStart),
571 },
572 EmbedderMsg::RequestDevtoolsConnection(response_sender) => {
573 self.delegate
574 .borrow()
575 .request_devtools_connection(AllowOrDenyRequest::new(
576 response_sender,
577 AllowOrDeny::Deny,
578 self.servo_errors.sender(),
579 ));
580 },
581 #[cfg(feature = "gamepad")]
582 EmbedderMsg::PlayGamepadHapticEffect(
583 webview_id,
584 gamepad_index,
585 gamepad_haptic_effect_type,
586 callback,
587 ) => {
588 if let Some(webview) = self.get_webview_handle(webview_id) {
589 webview.delegate().play_gamepad_haptic_effect(
590 webview,
591 gamepad_index,
592 gamepad_haptic_effect_type,
593 Box::new(move |success| {
594 callback
595 .send(success)
596 .expect("Could not send message via callback")
597 }),
598 );
599 }
600 },
601 #[cfg(feature = "gamepad")]
602 EmbedderMsg::StopGamepadHapticEffect(webview_id, gamepad_index, callback) => {
603 if let Some(webview) = self.get_webview_handle(webview_id) {
604 webview.delegate().stop_gamepad_haptic_effect(
605 webview,
606 gamepad_index,
607 Box::new(move |success| {
608 callback
609 .send(success)
610 .expect("Could not send message via callback")
611 }),
612 );
613 }
614 },
615 EmbedderMsg::ShowNotification(webview_id, notification) => {
616 match webview_id.and_then(|webview_id| self.get_webview_handle(webview_id)) {
617 Some(webview) => webview.delegate().show_notification(webview, notification),
618 None => self.delegate.borrow().show_notification(notification),
619 }
620 },
621 EmbedderMsg::ShowConsoleApiMessage(webview_id, level, message) => {
622 match webview_id.and_then(|webview_id| self.get_webview_handle(webview_id)) {
623 Some(webview) => webview
624 .delegate()
625 .show_console_message(webview, level, message),
626 None => self.delegate.borrow().show_console_message(level, message),
627 }
628 },
629 EmbedderMsg::ShowEmbedderControl(control_id, position, embedder_control_request) => {
630 if let Some(webview) = self.get_webview_handle(control_id.webview_id) {
631 webview.show_embedder_control(control_id, position, embedder_control_request);
632 }
633 },
634 EmbedderMsg::HideEmbedderControl(control_id) => {
635 if let Some(webview) = self.get_webview_handle(control_id.webview_id) {
636 webview
637 .delegate()
638 .hide_embedder_control(webview, control_id);
639 }
640 },
641 EmbedderMsg::GetWindowRect(webview_id, response_sender) => {
642 let window_rect = || {
643 let Some(webview) = self.get_webview_handle(webview_id) else {
644 return DeviceIndependentIntRect::default();
645 };
646 let hidpi_scale_factor = webview.hidpi_scale_factor();
647 let Some(screen_geometry) = webview.delegate().screen_geometry(webview) else {
648 return DeviceIndependentIntRect::default();
649 };
650
651 convert_rect_to_css_pixel(screen_geometry.window_rect, hidpi_scale_factor)
652 };
653
654 if let Err(error) = response_sender.send(window_rect()) {
655 warn!("Failed to respond to GetWindowRect: {error}");
656 }
657 },
658 EmbedderMsg::GetScreenMetrics(webview_id, response_sender) => {
659 let screen_metrics = || {
660 let Some(webview) = self.get_webview_handle(webview_id) else {
661 return ScreenMetrics::default();
662 };
663 let hidpi_scale_factor = webview.hidpi_scale_factor();
664 let Some(screen_geometry) = webview.delegate().screen_geometry(webview) else {
665 return ScreenMetrics::default();
666 };
667
668 ScreenMetrics {
669 screen_size: convert_size_to_css_pixel(
670 screen_geometry.size,
671 hidpi_scale_factor,
672 ),
673 available_size: convert_size_to_css_pixel(
674 screen_geometry.available_size,
675 hidpi_scale_factor,
676 ),
677 }
678 };
679 if let Err(error) = response_sender.send(screen_metrics()) {
680 warn!("Failed to respond to GetScreenMetrics: {error}");
681 }
682 },
683 EmbedderMsg::AccessibilityTreeUpdate(webview_id, tree_update) => {
684 if let Some(webview) = self.get_webview_handle(webview_id) {
685 webview
686 .delegate()
687 .notify_accessibility_tree_update(webview, tree_update);
688 }
689 },
690 }
691 }
692}
693
694impl Drop for ServoInner {
695 fn drop(&mut self) {
696 self.constellation_proxy
697 .send(EmbedderToConstellationMessage::Exit);
698 self.shutdown_state.set(ShutdownState::ShuttingDown);
699 while self.spin_event_loop() {
700 std::thread::sleep(Duration::from_micros(500));
701 }
702 }
703}
704
705#[derive(Clone)]
714pub struct Servo(Rc<ServoInner>);
715
716impl Servo {
717 #[servo_tracing::instrument(skip(builder))]
718 fn new(builder: ServoBuilder) -> Self {
719 let opts = builder.opts.map(|opts| *opts);
721 opts::initialize_options(opts.unwrap_or_default());
722 let opts = opts::get();
723
724 let preferences = builder.preferences.map(|opts| *opts);
727 servo_config::prefs::set(preferences.unwrap_or_default());
728
729 use std::sync::atomic::Ordering;
730
731 style::context::DEFAULT_DISABLE_STYLE_SHARING_CACHE.store(
732 !pref!(layout_style_sharing_cache_enabled),
733 Ordering::Relaxed,
734 );
735 style::context::DEFAULT_DUMP_STYLE_STATISTICS
736 .store(opts.debug.style_statistics, Ordering::Relaxed);
737 style::traversal::IS_SERVO_NONINCREMENTAL_LAYOUT
738 .store(opts.nonincremental_layout, Ordering::Relaxed);
739
740 if !opts.multiprocess {
741 media_platform::init();
742 }
743
744 PipelineNamespace::install(PipelineNamespaceId(0));
746
747 let event_loop_waker = builder.event_loop_waker;
752 let (paint_proxy, paint_receiver) = create_paint_channel(event_loop_waker.clone());
753 let (constellation_proxy, embedder_to_constellation_receiver) = ConstellationProxy::new();
754 let (embedder_proxy, embedder_receiver) = create_embedder_channel(event_loop_waker.clone());
755 let (net_embedder_proxy, net_embedder_receiver) =
756 create_generic_embedder_channel::<NetToEmbedderMsg>(event_loop_waker.clone());
757 let time_profiler_chan = profile_time::Profiler::create(
758 &opts.time_profiling,
759 opts.time_profiler_trace_path.clone(),
760 );
761 let mem_profiler_chan = profile_mem::Profiler::create();
762
763 let devtools_sender = if pref!(devtools_server_enabled) {
764 Some(devtools::start_server(
765 pref!(devtools_server_port) as u16,
766 embedder_proxy.clone(),
767 ))
768 } else {
769 None
770 };
771
772 let js_engine_setup = if !opts.multiprocess {
775 Some(script::init())
776 } else {
777 None
778 };
779
780 let mut protocols = ProtocolRegistry::with_internal_protocols();
783 protocols.merge(builder.protocol_registry);
784
785 let shutdown_state = Rc::new(Cell::new(ShutdownState::NotShuttingDown));
788 let paint = Paint::new(InitialPaintState {
789 paint_proxy: paint_proxy.clone(),
790 receiver: paint_receiver,
791 embedder_to_constellation_sender: constellation_proxy.sender().clone(),
792 time_profiler_chan: time_profiler_chan.clone(),
793 mem_profiler_chan: mem_profiler_chan.clone(),
794 shutdown_state: shutdown_state.clone(),
795 event_loop_waker,
796 #[cfg(feature = "webxr")]
797 webxr_registry: builder.webxr_registry,
798 });
799
800 let protocols = Arc::new(protocols);
801 let (public_resource_threads, private_resource_threads, async_runtime) =
802 new_resource_threads(
803 devtools_sender.clone(),
804 time_profiler_chan.clone(),
805 mem_profiler_chan.clone(),
806 net_embedder_proxy,
807 opts.config_dir.clone(),
808 opts.certificate_path.clone(),
809 opts.ignore_certificate_errors,
810 protocols.clone(),
811 );
812
813 let (private_storage_threads, public_storage_threads) =
814 new_storage_threads(mem_profiler_chan.clone(), opts.config_dir.clone());
815
816 create_constellation(
817 embedder_to_constellation_receiver,
818 &paint.borrow(),
819 embedder_proxy,
820 paint_proxy.clone(),
821 time_profiler_chan,
822 mem_profiler_chan,
823 devtools_sender,
824 protocols,
825 public_resource_threads.clone(),
826 private_resource_threads.clone(),
827 async_runtime,
828 public_storage_threads.clone(),
829 private_storage_threads.clone(),
830 );
831
832 if opts::get().multiprocess {
833 prefs::add_observer(Box::new(constellation_proxy.clone()));
834 }
835
836 Servo(Rc::new(ServoInner {
837 delegate: RefCell::new(Rc::new(DefaultServoDelegate)),
838 paint,
839 network_manager: Rc::new(RefCell::new(NetworkManager::new(
840 public_resource_threads.clone(),
841 private_resource_threads.clone(),
842 ))),
843 site_data_manager: Rc::new(RefCell::new(SiteDataManager::new(
844 public_resource_threads,
845 private_resource_threads,
846 public_storage_threads,
847 private_storage_threads,
848 ))),
849 javascript_evaluator: Rc::new(RefCell::new(JavaScriptEvaluator::new(
850 constellation_proxy.clone(),
851 ))),
852 constellation_proxy,
853 embedder_receiver,
854 net_embedder_receiver,
855 shutdown_state,
856 webviews: Default::default(),
857 servo_errors: ServoErrorChannel::default(),
858 _js_engine_setup: js_engine_setup,
859 }))
860 }
861
862 pub fn delegate(&self) -> Rc<dyn ServoDelegate> {
863 self.0.delegate.borrow().clone()
864 }
865
866 pub fn set_delegate(&self, delegate: Rc<dyn ServoDelegate>) {
867 *self.0.delegate.borrow_mut() = delegate;
868 }
869
870 pub fn initialize_gl_accelerated_media(display: NativeDisplay, api: GlApi, context: GlContext) {
873 WindowGLContext::initialize(display, api, context)
874 }
875
876 pub fn spin_event_loop(&self) {
882 self.0.spin_event_loop();
883 }
884
885 pub fn setup_logging(&self) {
886 let constellation_chan = self.0.constellation_proxy.sender();
887 let env = env_logger::Env::default();
888 let env_logger = EnvLoggerBuilder::from_env(env).build();
889 let con_logger = FromEmbedderLogger::new(constellation_chan);
890
891 let filter = max(env_logger.filter(), con_logger.filter());
892 let logger = BothLogger(env_logger, con_logger);
893
894 log::set_boxed_logger(Box::new(logger)).expect("Failed to set logger.");
895 log::set_max_level(filter);
896 }
897
898 pub fn create_memory_report(&self, snd: GenericCallback<MemoryReportResult>) {
899 self.0
900 .constellation_proxy
901 .send(EmbedderToConstellationMessage::CreateMemoryReport(snd));
902 }
903
904 pub fn constellation_sender(&self) -> Sender<EmbedderToConstellationMessage> {
905 self.0.constellation_proxy.sender()
906 }
907
908 pub fn execute_webdriver_command(&self, command: WebDriverCommandMsg) {
909 self.0
910 .constellation_proxy
911 .send(EmbedderToConstellationMessage::WebDriverCommand(command));
912 }
913
914 pub fn set_preference(&self, name: &str, value: PrefValue) {
915 let mut preferences = prefs::get().clone();
916 preferences.set_value(name, value);
917 prefs::set(preferences);
918 }
919
920 pub fn network_manager<'a>(&'a self) -> Ref<'a, NetworkManager> {
921 self.0.network_manager.borrow()
922 }
923
924 pub fn site_data_manager<'a>(&'a self) -> Ref<'a, SiteDataManager> {
925 self.0.site_data_manager.borrow()
926 }
927
928 pub(crate) fn paint<'a>(&'a self) -> Ref<'a, Paint> {
929 self.0.paint.borrow()
930 }
931
932 pub(crate) fn paint_mut<'a>(&'a self) -> RefMut<'a, Paint> {
933 self.0.paint.borrow_mut()
934 }
935
936 pub(crate) fn webviews_mut<'a>(
937 &'a self,
938 ) -> RefMut<'a, FxHashMap<WebViewId, Weak<RefCell<WebViewInner>>>> {
939 self.0.webviews.borrow_mut()
940 }
941
942 pub(crate) fn constellation_proxy(&self) -> &ConstellationProxy {
943 &self.0.constellation_proxy
944 }
945
946 pub(crate) fn javascript_evaluator_mut<'a>(&'a self) -> RefMut<'a, JavaScriptEvaluator> {
947 self.0.javascript_evaluator.borrow_mut()
948 }
949}
950
951fn create_embedder_channel(
952 event_loop_waker: Box<dyn EventLoopWaker>,
953) -> (EmbedderProxy, Receiver<EmbedderMsg>) {
954 let (sender, receiver) = unbounded();
955 (
956 EmbedderProxy {
957 sender,
958 event_loop_waker,
959 },
960 receiver,
961 )
962}
963
964fn create_generic_embedder_channel<T>(
965 event_loop_waker: Box<dyn EventLoopWaker>,
966) -> (GenericEmbedderProxy<T>, Receiver<T>) {
967 let (sender, receiver) = unbounded();
968 (
969 GenericEmbedderProxy {
970 sender,
971 event_loop_waker,
972 },
973 receiver,
974 )
975}
976
977fn create_paint_channel(
978 event_loop_waker: Box<dyn EventLoopWaker>,
979) -> (PaintProxy, RoutedReceiver<PaintMessage>) {
980 let (sender, receiver) = unbounded();
981 let sender_clone = sender.clone();
982 let event_loop_waker_clone = event_loop_waker.clone();
983 let result_callback = move |msg: Result<PaintMessage, ipc_channel::Error>| {
985 if let Err(err) = sender_clone.send(msg) {
986 warn!("Failed to send response ({:?}).", err);
987 }
988 event_loop_waker_clone.wake();
989 };
990
991 let generic_callback =
992 GenericCallback::new(result_callback).expect("Failed to create callback");
993 let cross_process_paint_api = CrossProcessPaintApi::new(generic_callback);
994 let paint_proxy = PaintProxy {
995 sender,
996 cross_process_paint_api,
997 event_loop_waker,
998 };
999
1000 (paint_proxy, receiver)
1001}
1002
1003#[expect(clippy::too_many_arguments)]
1004fn create_constellation(
1005 embedder_to_constellation_receiver: Receiver<EmbedderToConstellationMessage>,
1006 paint: &Paint,
1007 embedder_proxy: EmbedderProxy,
1008 paint_proxy: PaintProxy,
1009 time_profiler_chan: time::ProfilerChan,
1010 mem_profiler_chan: mem::ProfilerChan,
1011 devtools_sender: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
1012 protocols: Arc<ProtocolRegistry>,
1013 public_resource_threads: ResourceThreads,
1014 private_resource_threads: ResourceThreads,
1015 async_runtime: Box<dyn net_traits::AsyncRuntime>,
1016 public_storage_threads: StorageThreads,
1017 private_storage_threads: StorageThreads,
1018) {
1019 let opts = opts::get();
1021
1022 #[cfg(feature = "bluetooth")]
1023 let bluetooth_thread: GenericSender<BluetoothRequest> =
1024 BluetoothThreadFactory::new(embedder_proxy.clone());
1025
1026 let privileged_urls = protocols.privileged_urls();
1027
1028 let system_font_service = Arc::new(
1029 SystemFontService::spawn(
1030 paint_proxy.cross_process_paint_api.clone(),
1031 mem_profiler_chan.clone(),
1032 )
1033 .to_proxy(),
1034 );
1035
1036 let initial_state = InitialConstellationState {
1037 paint_proxy,
1038 embedder_proxy,
1039 devtools_sender,
1040 #[cfg(feature = "bluetooth")]
1041 bluetooth_thread,
1042 system_font_service,
1043 public_resource_threads,
1044 private_resource_threads,
1045 public_storage_threads,
1046 private_storage_threads,
1047 time_profiler_chan,
1048 mem_profiler_chan,
1049 #[cfg(feature = "webxr")]
1050 webxr_registry: Some(paint.webxr_main_thread_registry()),
1051 #[cfg(not(feature = "webxr"))]
1052 webxr_registry: None,
1053 webgl_threads: Some(paint.webgl_threads()),
1054 webrender_external_image_id_manager: paint.webrender_external_image_id_manager(),
1055 #[cfg(feature = "webgpu")]
1056 wgpu_image_map: paint.webgpu_image_map(),
1057 async_runtime,
1058 privileged_urls,
1059 };
1060
1061 let layout_factory = Arc::new(LayoutFactoryImpl());
1062
1063 Constellation::<script::ScriptThread, script::ServiceWorkerManager>::start(
1064 embedder_to_constellation_receiver,
1065 initial_state,
1066 layout_factory,
1067 opts.random_pipeline_closure_probability,
1068 opts.random_pipeline_closure_seed,
1069 opts.hard_fail,
1070 );
1071}
1072
1073struct BothLogger<Log1, Log2>(Log1, Log2);
1076
1077impl<Log1, Log2> Log for BothLogger<Log1, Log2>
1078where
1079 Log1: Log,
1080 Log2: Log,
1081{
1082 fn enabled(&self, metadata: &Metadata) -> bool {
1083 self.0.enabled(metadata) || self.1.enabled(metadata)
1084 }
1085
1086 fn log(&self, record: &Record) {
1087 self.0.log(record);
1088 self.1.log(record);
1089 }
1090
1091 fn flush(&self) {
1092 self.0.flush();
1093 self.1.flush();
1094 }
1095}
1096
1097fn set_logger(script_to_constellation_sender: ScriptToConstellationSender) {
1098 let con_logger = FromScriptLogger::new(script_to_constellation_sender);
1099 let env = env_logger::Env::default();
1100 let env_logger = EnvLoggerBuilder::from_env(env).build();
1101
1102 let filter = max(env_logger.filter(), con_logger.filter());
1103 let logger = BothLogger(env_logger, con_logger);
1104
1105 log::set_boxed_logger(Box::new(logger)).expect("Failed to set logger.");
1106 log::set_max_level(filter);
1107}
1108
1109pub fn run_content_process(token: String) {
1111 let (unprivileged_content_sender, unprivileged_content_receiver) =
1112 ipc::channel::<UnprivilegedContent>().unwrap();
1113 let connection_bootstrap: IpcSender<IpcSender<UnprivilegedContent>> =
1114 IpcSender::connect(token).unwrap();
1115 connection_bootstrap
1116 .send(unprivileged_content_sender)
1117 .unwrap();
1118
1119 let unprivileged_content = unprivileged_content_receiver.recv().unwrap();
1120 opts::initialize_options(unprivileged_content.opts());
1121 prefs::set(unprivileged_content.prefs().clone());
1122
1123 if opts::get().sandbox {
1125 create_sandbox();
1126 }
1127
1128 let _js_engine_setup = script::init();
1129
1130 match unprivileged_content {
1131 UnprivilegedContent::ScriptEventLoop(new_event_loop_info) => {
1132 media_platform::init();
1133
1134 let fetch_thread_join_handle = start_fetch_thread();
1136
1137 set_logger(
1138 new_event_loop_info
1139 .initial_script_state
1140 .script_to_constellation_sender
1141 .clone(),
1142 );
1143
1144 register_system_memory_reporter_for_event_loop(&new_event_loop_info);
1145
1146 let (background_hang_monitor_register, background_hang_monitor_join_handle) =
1147 HangMonitorRegister::init(
1148 new_event_loop_info.bhm_to_constellation_sender.clone(),
1149 new_event_loop_info.constellation_to_bhm_receiver,
1150 opts::get().background_hang_monitor,
1151 );
1152
1153 let layout_factory = Arc::new(LayoutFactoryImpl());
1154 let script_join_handle = script::ScriptThread::create(
1155 new_event_loop_info.initial_script_state,
1156 layout_factory,
1157 Arc::new(ImageCacheFactoryImpl::new(
1158 new_event_loop_info.broken_image_icon_data,
1159 )),
1160 background_hang_monitor_register,
1161 );
1162
1163 script_join_handle
1164 .join()
1165 .expect("Failed to join on the script thread.");
1166 background_hang_monitor_join_handle
1167 .join()
1168 .expect("Failed to join on the BHM background thread.");
1169
1170 StyleThreadPool::shutdown();
1171
1172 exit_fetch_thread();
1174 fetch_thread_join_handle
1175 .join()
1176 .expect("Failed to join on the fetch thread in the constellation");
1177 },
1178 UnprivilegedContent::ServiceWorker(content) => {
1179 content.start::<ServiceWorkerManager>();
1180 },
1181 }
1182}
1183
1184#[cfg(all(
1185 not(target_os = "windows"),
1186 not(target_os = "ios"),
1187 not(target_os = "android"),
1188 not(target_arch = "arm"),
1189 not(target_arch = "aarch64"),
1190 not(target_env = "ohos"),
1191))]
1192fn create_sandbox() {
1193 ChildSandbox::new(content_process_sandbox_profile())
1194 .activate()
1195 .expect("Failed to activate sandbox!");
1196}
1197
1198#[cfg(any(
1199 target_os = "windows",
1200 target_os = "ios",
1201 target_os = "android",
1202 target_arch = "arm",
1203 target_arch = "aarch64",
1204 target_env = "ohos",
1205))]
1206fn create_sandbox() {
1207 panic!("Sandboxing is not supported on Windows, iOS, ARM targets and android.");
1208}
1209
1210struct DefaultEventLoopWaker;
1211
1212impl EventLoopWaker for DefaultEventLoopWaker {
1213 fn clone_box(&self) -> Box<dyn EventLoopWaker> {
1214 Box::new(DefaultEventLoopWaker)
1215 }
1216}
1217
1218#[cfg(feature = "webxr")]
1219struct DefaultWebXrRegistry;
1220#[cfg(feature = "webxr")]
1221impl webxr::WebXrRegistry for DefaultWebXrRegistry {}
1222
1223pub struct ServoBuilder {
1224 opts: Option<Box<Opts>>,
1225 preferences: Option<Box<Preferences>>,
1226 event_loop_waker: Box<dyn EventLoopWaker>,
1227 protocol_registry: ProtocolRegistry,
1228 #[cfg(feature = "webxr")]
1229 webxr_registry: Box<dyn webxr::WebXrRegistry>,
1230}
1231
1232impl Default for ServoBuilder {
1233 fn default() -> Self {
1234 Self {
1235 opts: Default::default(),
1236 preferences: Default::default(),
1237 event_loop_waker: Box::new(DefaultEventLoopWaker),
1238 protocol_registry: Default::default(),
1239 #[cfg(feature = "webxr")]
1240 webxr_registry: Box::new(DefaultWebXrRegistry),
1241 }
1242 }
1243}
1244
1245impl ServoBuilder {
1246 pub fn build(self) -> Servo {
1247 Servo::new(self)
1248 }
1249
1250 pub fn opts(mut self, opts: Opts) -> Self {
1251 self.opts = Some(Box::new(opts));
1252 self
1253 }
1254
1255 pub fn preferences(mut self, preferences: Preferences) -> Self {
1256 self.preferences = Some(Box::new(preferences));
1257 self
1258 }
1259
1260 pub fn event_loop_waker(mut self, event_loop_waker: Box<dyn EventLoopWaker>) -> Self {
1261 self.event_loop_waker = event_loop_waker;
1262 self
1263 }
1264
1265 pub fn protocol_registry(mut self, protocol_registry: ProtocolRegistry) -> Self {
1266 self.protocol_registry = protocol_registry;
1267 self
1268 }
1269
1270 #[cfg(feature = "webxr")]
1271 pub fn webxr_registry(mut self, webxr_registry: Box<dyn webxr::WebXrRegistry>) -> Self {
1272 self.webxr_registry = webxr_registry;
1273 self
1274 }
1275}
1276
1277fn register_system_memory_reporter_for_event_loop(
1278 new_event_loop_info: &NewScriptEventLoopProcessInfo,
1279) {
1280 let callback = GenericCallback::new(|message| {
1284 if let Ok(request) = message {
1285 system_reporter::collect_reports(request);
1286 }
1287 })
1288 .expect("Could not create memory reporter callback");
1289 new_event_loop_info
1290 .initial_script_state
1291 .memory_profiler_sender
1292 .send(ProfilerMsg::RegisterReporter(
1293 format!("system-content-{}", std::process::id()),
1294 Reporter(callback),
1295 ));
1296}