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 accesskit::ActionRequest;
12use crossbeam_channel::{Receiver, Sender, unbounded};
13pub use embedder_traits::*;
14use env_logger::Builder as EnvLoggerBuilder;
15use fonts::SystemFontService;
16#[cfg(all(
17 feature = "multiprocess",
18 not(target_os = "windows"),
19 not(target_os = "ios"),
20 not(target_os = "android"),
21 not(target_arch = "arm"),
22 not(target_arch = "aarch64"),
23 not(target_arch = "riscv32"),
24 not(target_arch = "riscv64"),
25 not(target_env = "ohos"),
26))]
27use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
28#[cfg(feature = "multiprocess")]
29use ipc_channel::ipc::{self, IpcSender};
30use layout::LayoutFactoryImpl;
31#[cfg(feature = "multiprocess")]
32use layout_api::ScriptThreadFactory;
33use log::{Log, Metadata, Record, debug, warn};
34use media::{GlApi, NativeDisplay, WindowGLContext};
35use net::embedder::NetToEmbedderMsg;
36#[cfg(feature = "multiprocess")]
37use net::image_cache::ImageCacheFactoryImpl;
38use net::protocols::ProtocolRegistry;
39use net::resource_thread::new_resource_threads;
40#[cfg(feature = "multiprocess")]
41use net_traits::FetchThread;
42use net_traits::ResourceThreads;
43use paint::{InitialPaintState, Paint};
44pub use paint_api::rendering_context::RenderingContext;
45use paint_api::{CrossProcessPaintApi, PaintMessage, PaintProxy};
46use profile::{mem as profile_mem, time as profile_time};
47use profile_traits::mem::MemoryReportResult;
48#[cfg(feature = "multiprocess")]
49use profile_traits::mem::{ProfilerMsg, Reporter};
50use profile_traits::{mem, time};
51use rustc_hash::FxHashMap;
52use script::JSEngineSetup;
53#[cfg(feature = "multiprocess")]
54use script::ServiceWorkerManager;
55#[cfg(feature = "multiprocess")]
56use servo_background_hang_monitor::HangMonitorRegister;
57use servo_base::generic_channel::{GenericCallback, GenericSender, RoutedReceiver, SendError};
58pub use servo_base::id::WebViewId;
59use servo_base::id::{EMBEDDER_PIPELINE_NAMESPACE_ID, PipelineId, PipelineNamespace};
60#[cfg(feature = "bluetooth")]
61use servo_bluetooth::BluetoothThreadFactory;
62#[cfg(feature = "bluetooth")]
63use servo_bluetooth_traits::BluetoothRequest;
64use servo_config::opts::{DiagnosticsLoggingOption, Opts};
65use servo_config::prefs::{PrefValue, Preferences};
66use servo_config::{opts, pref, prefs};
67#[cfg(feature = "multiprocess")]
68use servo_constellation::UnprivilegedContent;
69#[cfg(all(
70 feature = "multiprocess",
71 not(target_os = "windows"),
72 not(target_os = "ios"),
73 not(target_os = "android"),
74 not(target_arch = "arm"),
75 not(target_arch = "aarch64"),
76 not(target_arch = "riscv32"),
77 not(target_arch = "riscv64"),
78 not(target_env = "ohos"),
79))]
80use servo_constellation::content_process_sandbox_profile;
81use servo_constellation::{
82 Constellation, ConstellationToEmbedderMsg, FromEmbedderLogger, InitialConstellationState,
83};
84#[cfg(feature = "multiprocess")]
85use servo_constellation::{FromScriptLogger, NewScriptEventLoopProcessInfo};
86use servo_constellation_traits::EmbedderToConstellationMessage;
87#[cfg(feature = "multiprocess")]
88use servo_constellation_traits::ScriptToConstellationSender;
89use servo_geometry::{
90 DeviceIndependentIntRect, convert_rect_to_css_pixel, convert_size_to_css_pixel,
91};
92use servo_media::ServoMedia;
93use servo_media::player::context::GlContext;
94use servo_wakelock::DefaultWakeLockDelegate;
95use storage::new_storage_threads;
96use storage_traits::StorageThreads;
97#[cfg(feature = "multiprocess")]
98use style::global_style_data::StyleThreadPool;
99#[cfg(feature = "webxr")]
100use webxr::WebXrRegistry;
101
102use crate::clipboard_delegate::StringRequest;
103#[cfg(feature = "gamepad")]
104use crate::gamepad_delegate::{GamepadHapticEffectRequest, GamepadHapticEffectRequestType};
105use crate::geolocation_delegate::{PositionRequest, PositionWatch};
106use crate::javascript_evaluator::JavaScriptEvaluator;
107use crate::network_manager::NetworkManager;
108use crate::proxies::ConstellationProxy;
109use crate::responders::ServoErrorChannel;
110use crate::servo_delegate::{DefaultServoDelegate, ServoDelegate, ServoError};
111use crate::site_data_manager::{CookieOperationResponse, SiteDataManager};
112use crate::webview::{MINIMUM_WEBVIEW_SIZE, WebView, WebViewInner};
113use crate::webview_delegate::{
114 AllowOrDenyRequest, AuthenticationRequest, BluetoothDeviceSelectionRequest, EmbedderControl,
115 FilePicker, NavigationRequest, PermissionRequest, ProtocolHandlerRegistration, WebResourceLoad,
116};
117
118#[cfg(all(
119 feature = "media-gstreamer",
120 not(any(target_os = "android", target_env = "ohos"))
121))]
122mod media_platform {
123 use servo_media_gstreamer::GStreamerBackend;
124
125 use super::ServoMedia;
126
127 #[cfg(any(windows, target_os = "macos"))]
128 pub fn init() {
129 ServoMedia::init_with_backend(|| {
130 use servo_media::BackendInit;
131
132 let mut plugin_dir = std::env::current_exe().unwrap();
133 plugin_dir.pop();
134
135 if cfg!(target_os = "macos") {
136 plugin_dir.push("lib");
137 }
138
139 let plugin_list = crate::gstreamer_plugins::gstreamer_plugins();
140 match GStreamerBackend::init_with_plugins(plugin_dir, &plugin_list) {
141 Ok(backend) => return backend,
142 Err(error) => {
143 log::warn!(
144 "Error initializing GStreamer: {error:?}. \
145 Trying fallback initialization."
146 );
147 },
148 }
149
150 GStreamerBackend::init()
151 });
152 }
153
154 #[cfg(not(any(windows, target_os = "macos")))]
155 pub fn init() {
156 ServoMedia::init::<GStreamerBackend>();
157 }
158}
159
160#[cfg(target_env = "ohos")]
161mod media_platform {
162 use servo_media_ohos::OhosBackend;
163
164 use super::ServoMedia;
165 pub fn init() {
166 ServoMedia::init::<OhosBackend>();
167 }
168}
169
170#[cfg(all(
171 not(target_env = "ohos"),
172 not(all(feature = "media-gstreamer", not(target_os = "android")))
173))]
174mod media_platform {
175 use super::ServoMedia;
176 pub fn init() {
177 ServoMedia::init::<servo_media_dummy::DummyBackend>();
178 }
179}
180
181#[allow(clippy::enum_variant_names)]
182enum Message {
183 FromNet(NetToEmbedderMsg),
184 FromConstellation(ConstellationToEmbedderMsg),
185 FromUnknown(EmbedderMsg),
186}
187
188struct EmbedderMessageSelector<'a> {
194 select: crossbeam_channel::Select<'a>,
195 receivers: (
196 &'a Receiver<EmbedderMsg>,
197 &'a Receiver<NetToEmbedderMsg>,
198 &'a Receiver<ConstellationToEmbedderMsg>,
199 ),
200}
201
202impl<'a> EmbedderMessageSelector<'a> {
203 fn new(
204 embedder_receiver: &'a Receiver<EmbedderMsg>,
205 net_embedder_receiver: &'a Receiver<NetToEmbedderMsg>,
206 constellation_embedder_receiver: &'a Receiver<ConstellationToEmbedderMsg>,
207 ) -> Self {
208 let mut select = crossbeam_channel::Select::new();
209 let embedder_index = select.recv(embedder_receiver);
212 debug_assert_eq!(embedder_index, 0);
213 let net_embedder_index = select.recv(net_embedder_receiver);
214 debug_assert_eq!(net_embedder_index, 1);
215 let constellation_embedder_index = select.recv(constellation_embedder_receiver);
216 debug_assert_eq!(constellation_embedder_index, 2);
217 Self {
218 select,
219 receivers: (
220 embedder_receiver,
221 net_embedder_receiver,
222 constellation_embedder_receiver,
223 ),
224 }
225 }
226
227 #[servo_tracing::instrument(
228 level = "debug",
229 name = "EmbedderMessageSelector::try_recv_one_message",
230 skip_all
231 )]
232 fn try_recv_one_message(&mut self) -> Option<Message> {
233 let operation = self.select.try_select().ok()?;
234 let index = operation.index();
235 if index == 0 {
236 let message = operation.recv(self.receivers.0).ok()?;
237 Some(Message::FromUnknown(message))
238 } else if index == 1 {
239 let message = operation.recv(self.receivers.1).ok()?;
240 Some(Message::FromNet(message))
241 } else if index == 2 {
242 let message = operation.recv(self.receivers.2).ok()?;
243 Some(Message::FromConstellation(message))
244 } else {
245 log::error!("No select operation registered for {index:?}");
246 None
247 }
248 }
249}
250
251pub struct PendingHandledInputEvent {
252 pub event_id: InputEventId,
253 pub webview_id: WebViewId,
254}
255
256struct ServoInner {
257 delegate: RefCell<Rc<dyn ServoDelegate>>,
258 paint: Rc<RefCell<Paint>>,
259 constellation_proxy: ConstellationProxy,
260 embedder_receiver: Receiver<EmbedderMsg>,
261 net_embedder_receiver: Receiver<NetToEmbedderMsg>,
262 constellation_embedder_receiver: Receiver<ConstellationToEmbedderMsg>,
263 network_manager: Rc<RefCell<NetworkManager>>,
264 site_data_manager: SiteDataManager,
265 javascript_evaluator: Rc<RefCell<JavaScriptEvaluator>>,
268 shutdown_state: Rc<Cell<ShutdownState>>,
271 webviews: RefCell<FxHashMap<WebViewId, Weak<RefCell<WebViewInner>>>>,
276 servo_errors: ServoErrorChannel,
277 _js_engine_setup: Option<JSEngineSetup>,
281 pending_handled_input_events: RefCell<Vec<PendingHandledInputEvent>>,
284 event_loop_waker: Box<dyn EventLoopWaker>,
286 geolocation_watches: RefCell<FxHashMap<PipelineId, Vec<GeolocationWatchId>>>,
289}
290
291impl ServoInner {
292 fn get_webview_handle(&self, id: WebViewId) -> Option<WebView> {
293 self.webviews
294 .borrow()
295 .get(&id)
296 .and_then(WebView::from_weak_handle)
297 }
298
299 fn untrack_geolocation_watch(&self, watch_id: &GeolocationWatchId) -> bool {
301 let mut watches = self.geolocation_watches.borrow_mut();
302 let Some(pipeline_watches) = watches.get_mut(&watch_id.pipeline_id) else {
303 return false;
304 };
305 let Some(index) = pipeline_watches.iter().position(|id| id == watch_id) else {
306 return false;
307 };
308 pipeline_watches.swap_remove(index);
309 if pipeline_watches.is_empty() {
310 watches.remove(&watch_id.pipeline_id);
311 }
312 true
313 }
314
315 fn stop_geolocation_watch(&self, watch_id: &GeolocationWatchId) {
317 if !self.untrack_geolocation_watch(watch_id) {
318 return;
319 }
320 if let Some(webview) = self.get_webview_handle(watch_id.webview_id) {
321 webview
322 .geolocation_delegate()
323 .stop_watch(webview.clone(), watch_id);
324 }
325 }
326
327 #[servo_tracing::instrument(level = "debug", skip_all)]
328 fn spin_event_loop(&self) -> bool {
329 if self.shutdown_state.get() == ShutdownState::FinishedShuttingDown {
330 return false;
331 }
332
333 {
334 let paint = self.paint.borrow();
335 let mut messages = Vec::new();
336 while let Ok(message) = paint.receiver().try_recv() {
337 match message {
338 Ok(message) => messages.push(message),
339 Err(error) => {
340 warn!("Router deserialization error: {error}. Ignoring this PaintMessage.")
341 },
342 }
343 }
344 paint.handle_messages(messages);
345 }
346
347 let mut selector = EmbedderMessageSelector::new(
348 &self.embedder_receiver,
349 &self.net_embedder_receiver,
350 &self.constellation_embedder_receiver,
351 );
352 while let Some(message) = selector.try_recv_one_message() {
354 match message {
355 Message::FromUnknown(message) => self.handle_embedder_message(message),
356 Message::FromNet(message) => self.handle_net_embedder_message(message),
357 Message::FromConstellation(message) => {
358 self.handle_constellation_embedder_message(message)
359 },
360 }
361 if self.shutdown_state.get() == ShutdownState::FinishedShuttingDown {
362 break;
363 }
364 }
365 let pending_handled_input_events =
366 std::mem::take(&mut *self.pending_handled_input_events.borrow_mut());
367 for PendingHandledInputEvent {
368 event_id,
369 webview_id,
370 } in pending_handled_input_events
371 {
372 self.paint.borrow_mut().notify_input_event_handled(
373 webview_id,
374 event_id,
375 InputEventResult::DispatchFailed,
376 );
377 if let Some(webview) = self.get_webview_handle(webview_id) {
378 webview.delegate().notify_input_event_handled(
379 webview,
380 event_id,
381 InputEventResult::DispatchFailed,
382 );
383 }
384 }
385
386 if self.constellation_proxy.disconnected() {
387 self.delegate
388 .borrow()
389 .notify_error(ServoError::LostConnectionWithBackend);
390 }
391
392 self.paint.borrow_mut().perform_updates();
393 self.resend_accessibility_root_nodes_for_viewport_changes();
394 self.send_new_frame_ready_messages();
395 self.handle_delegate_errors();
396 self.clean_up_destroyed_webview_handles();
397
398 if self.shutdown_state.get() == ShutdownState::FinishedShuttingDown {
399 return false;
400 }
401
402 true
403 }
404
405 fn resend_accessibility_root_nodes_for_viewport_changes(&self) {
411 let webviews: Vec<WebView> = self
414 .webviews
415 .borrow()
416 .values()
417 .filter_map(WebView::from_weak_handle)
418 .collect();
419 for webview in webviews {
420 if webview.take_accessibility_viewport_changed() {
421 webview.send_accessibility_root_node();
422 }
423 }
424 }
425
426 fn send_new_frame_ready_messages(&self) {
427 let webviews_needing_repaint = self.paint.borrow().webviews_needing_repaint();
428
429 for webview in webviews_needing_repaint
430 .iter()
431 .filter_map(|webview_id| self.get_webview_handle(*webview_id))
432 {
433 webview.delegate().notify_new_frame_ready(webview);
434 }
435 }
436
437 fn handle_delegate_errors(&self) {
438 while let Some(error) = self.servo_errors.try_recv() {
439 self.delegate.borrow().notify_error(error);
440 }
441 }
442
443 fn clean_up_destroyed_webview_handles(&self) {
444 self.webviews
449 .borrow_mut()
450 .retain(|_webview_id, webview| webview.strong_count() > 0);
451 }
452
453 fn finish_shutting_down(&self) {
454 debug!("Servo received message that Constellation shutdown is complete");
455 self.shutdown_state.set(ShutdownState::FinishedShuttingDown);
456 self.paint.borrow_mut().finish_shutting_down();
457 }
458
459 fn handle_net_embedder_message(&self, message: NetToEmbedderMsg) {
460 match message {
461 NetToEmbedderMsg::SelectFiles(control_id, file_picker_request, response_sender) => {
462 if file_picker_request.accept_current_paths_for_testing {
463 let _ = response_sender.send(Some(file_picker_request.current_paths));
464 return;
465 }
466 if let Some(webview) = self.get_webview_handle(control_id.webview_id) {
467 webview.delegate().show_embedder_control(
468 webview,
469 EmbedderControl::FilePicker(FilePicker {
470 id: control_id,
471 file_picker_request,
472 response_sender: Some(response_sender),
473 }),
474 );
475 }
476 },
477 NetToEmbedderMsg::WebResourceRequested(
478 webview_id,
479 web_resource_request,
480 response_sender,
481 ) => {
482 if let Some(webview) =
483 webview_id.and_then(|webview_id| self.get_webview_handle(webview_id))
484 {
485 let web_resource_load = WebResourceLoad::new(
486 web_resource_request,
487 response_sender,
488 self.servo_errors.sender(),
489 );
490 webview
491 .delegate()
492 .load_web_resource(webview, web_resource_load);
493 } else {
494 let web_resource_load = WebResourceLoad::new(
495 web_resource_request,
496 response_sender,
497 self.servo_errors.sender(),
498 );
499 self.delegate.borrow().load_web_resource(web_resource_load);
500 }
501 },
502 NetToEmbedderMsg::RequestAuthentication(
503 webview_id,
504 url,
505 for_proxy,
506 response_sender,
507 ) => {
508 if let Some(webview) = self.get_webview_handle(webview_id) {
509 let authentication_request = AuthenticationRequest::new(
510 url.into_url(),
511 for_proxy,
512 response_sender,
513 self.servo_errors.sender(),
514 );
515 webview
516 .delegate()
517 .request_authentication(webview, authentication_request);
518 }
519 },
520 NetToEmbedderMsg::EmbedderCookieOperationResponseWithCookies(operation_id, cookies) => {
521 self.site_data_manager.handle_cookie_response(
522 operation_id,
523 CookieOperationResponse::Cookies(cookies),
524 );
525 },
526 NetToEmbedderMsg::EmbedderCookieOperationResponse(operation_id) => {
527 self.site_data_manager
528 .handle_cookie_response(operation_id, CookieOperationResponse::Done);
529 },
530 }
531 }
532
533 fn handle_embedder_message(&self, message: EmbedderMsg) {
534 match message {
535 EmbedderMsg::Status(webview_id, status_text) => {
536 if let Some(webview) = self.get_webview_handle(webview_id) {
537 webview.set_status_text(status_text);
538 }
539 },
540 EmbedderMsg::ChangePageTitle(webview_id, title) => {
541 if let Some(webview) = self.get_webview_handle(webview_id) {
542 webview.set_page_title(title);
543 }
544 },
545 EmbedderMsg::MoveTo(webview_id, position) => {
546 if let Some(webview) = self.get_webview_handle(webview_id) {
547 webview.delegate().request_move_to(webview, position);
548 }
549 },
550 EmbedderMsg::ResizeTo(webview_id, size) => {
551 if let Some(webview) = self.get_webview_handle(webview_id) {
552 webview
553 .delegate()
554 .request_resize_to(webview, size.max(MINIMUM_WEBVIEW_SIZE));
555 }
556 },
557 EmbedderMsg::ShowSimpleDialog(webview_id, simple_dialog) => {
558 if let Some(webview) = self.get_webview_handle(webview_id) {
559 webview.delegate().show_embedder_control(
560 webview,
561 EmbedderControl::SimpleDialog(simple_dialog.into()),
562 );
563 }
564 },
565 EmbedderMsg::AllowProtocolHandlerRequest(
566 webview_id,
567 registration_update,
568 response_sender,
569 ) => {
570 if let Some(webview) = self.get_webview_handle(webview_id) {
571 let ProtocolHandlerUpdateRegistration {
572 scheme,
573 url,
574 register_or_unregister,
575 } = registration_update;
576 let protocol_handler_registration = ProtocolHandlerRegistration {
577 scheme,
578 url: url.into_url(),
579 register_or_unregister,
580 };
581 let allow_deny_request = AllowOrDenyRequest::new(
582 response_sender,
583 AllowOrDeny::Deny,
584 self.servo_errors.sender(),
585 );
586 webview.delegate().request_protocol_handler(
587 webview,
588 protocol_handler_registration,
589 allow_deny_request,
590 );
591 }
592 },
593 EmbedderMsg::AllowUnload(webview_id, response_sender) => {
594 if let Some(webview) = self.get_webview_handle(webview_id) {
595 let request = AllowOrDenyRequest::new(
596 response_sender,
597 AllowOrDeny::Allow,
598 self.servo_errors.sender(),
599 );
600 webview.delegate().request_unload(webview, request);
601 }
602 },
603 EmbedderMsg::InputEventsHandled(webview_id, event_outcomes) => {
604 let webview = self.get_webview_handle(webview_id);
605 for InputEventOutcome {
606 id: input_event_id,
607 result,
608 } in event_outcomes
609 {
610 self.paint.borrow_mut().notify_input_event_handled(
611 webview_id,
612 input_event_id,
613 result,
614 );
615 if let Some(ref webview) = webview {
616 webview.delegate().notify_input_event_handled(
617 webview.clone(),
618 input_event_id,
619 result,
620 );
621 }
622 }
623 },
624 EmbedderMsg::ClearClipboard(webview_id) => {
625 if let Some(webview) = self.get_webview_handle(webview_id) {
626 webview.clipboard_delegate().clear(webview);
627 }
628 },
629 EmbedderMsg::GetClipboardText(webview_id, result_sender) => {
630 if let Some(webview) = self.get_webview_handle(webview_id) {
631 webview
632 .clipboard_delegate()
633 .get_text(webview, StringRequest::from(result_sender));
634 }
635 },
636 EmbedderMsg::SetClipboardText(webview_id, string) => {
637 if let Some(webview) = self.get_webview_handle(webview_id) {
638 webview.clipboard_delegate().set_text(webview, string);
639 }
640 },
641 EmbedderMsg::SetCursor(webview_id, cursor) => {
642 if let Some(webview) = self.get_webview_handle(webview_id) {
643 webview.set_cursor(cursor);
644 }
645 },
646 EmbedderMsg::NewFavicon(webview_id, image) => {
647 if let Some(webview) = self.get_webview_handle(webview_id) {
648 webview.set_favicon(image);
649 }
650 },
651 EmbedderMsg::NotifyLoadStatusChanged(webview_id, load_status) => {
652 if let Some(webview) = self.get_webview_handle(webview_id) {
653 webview.set_load_status(load_status);
654 }
655 },
656 EmbedderMsg::NotifyFullscreenStateChanged(webview_id, fullscreen) => {
657 if let Some(webview) = self.get_webview_handle(webview_id) {
658 webview
659 .delegate()
660 .notify_fullscreen_state_changed(webview, fullscreen);
661 }
662 },
663 EmbedderMsg::GetSelectedBluetoothDevice(webview_id, items, response_sender) => {
664 if let Some(webview) = self.get_webview_handle(webview_id) {
665 webview.delegate().show_bluetooth_device_dialog(
666 webview,
667 BluetoothDeviceSelectionRequest::new(items, response_sender),
668 );
669 }
670 },
671 EmbedderMsg::PromptPermission(webview_id, requested_feature, response_sender) => {
672 if let Some(webview) = self.get_webview_handle(webview_id) {
673 let permission_request = PermissionRequest {
674 requested_feature,
675 allow_deny_request: AllowOrDenyRequest::new(
676 response_sender,
677 AllowOrDeny::Deny,
678 self.servo_errors.sender(),
679 ),
680 };
681 webview
682 .delegate()
683 .request_permission(webview, permission_request);
684 }
685 },
686 EmbedderMsg::RequestPermission(webview_id, requested_feature, callback) => {
687 if let Some(webview) = self.get_webview_handle(webview_id) {
688 let permission_request = PermissionRequest {
689 requested_feature,
690 allow_deny_request: AllowOrDenyRequest::new_from_callback(
691 callback,
692 AllowOrDeny::Deny,
693 self.servo_errors.sender(),
694 ),
695 };
696 webview
697 .delegate()
698 .request_permission(webview, permission_request);
699 }
700 },
701 EmbedderMsg::RequestGeolocationPosition(webview_id, options, result_sender) => {
702 if let Some(webview) = self.get_webview_handle(webview_id) {
703 webview.geolocation_delegate().request_position(
704 webview.clone(),
705 PositionRequest::new(result_sender, options),
706 );
707 }
708 },
709 EmbedderMsg::StartGeolocationWatch(watch_id, options, result_sender) => {
710 if let Some(webview) = self.get_webview_handle(watch_id.webview_id) {
711 self.geolocation_watches
712 .borrow_mut()
713 .entry(watch_id.pipeline_id)
714 .or_default()
715 .push(watch_id.clone());
716 webview.geolocation_delegate().start_watch(
717 webview.clone(),
718 PositionWatch::new(watch_id, result_sender, options),
719 );
720 }
721 },
722 EmbedderMsg::StopGeolocationWatch(watch_id) => {
723 self.stop_geolocation_watch(&watch_id);
724 },
725 EmbedderMsg::OnDevtoolsStarted(port, token) => match port {
726 Ok(port) => self
727 .delegate
728 .borrow()
729 .notify_devtools_server_started(port, token),
730 Err(()) => self
731 .delegate
732 .borrow()
733 .notify_error(ServoError::DevtoolsFailedToStart),
734 },
735 EmbedderMsg::RequestDevtoolsConnection(response_sender) => {
736 self.delegate
737 .borrow()
738 .request_devtools_connection(AllowOrDenyRequest::new(
739 response_sender,
740 AllowOrDeny::Deny,
741 self.servo_errors.sender(),
742 ));
743 },
744 #[cfg(feature = "gamepad")]
745 EmbedderMsg::PlayGamepadHapticEffect(
746 webview_id,
747 gamepad_index,
748 gamepad_haptic_effect_type,
749 callback,
750 ) => {
751 if let Some(webview) = self.get_webview_handle(webview_id) {
752 let request = GamepadHapticEffectRequest::new(
753 gamepad_index,
754 GamepadHapticEffectRequestType::Play(gamepad_haptic_effect_type),
755 Box::new(move |success| {
756 callback
757 .send(success)
758 .expect("Could not send message via callback")
759 }),
760 );
761 webview
762 .gamepad_delegate()
763 .handle_haptic_effect_request(request);
764 }
765 },
766 #[cfg(feature = "gamepad")]
767 EmbedderMsg::StopGamepadHapticEffect(webview_id, gamepad_index, callback) => {
768 if let Some(webview) = self.get_webview_handle(webview_id) {
769 let request = GamepadHapticEffectRequest::new(
770 gamepad_index,
771 GamepadHapticEffectRequestType::Stop,
772 Box::new(move |success| {
773 callback
774 .send(success)
775 .expect("Could not send message via callback")
776 }),
777 );
778 webview
779 .gamepad_delegate()
780 .handle_haptic_effect_request(request);
781 }
782 },
783 EmbedderMsg::ShowNotification(webview_id, notification) => {
784 match webview_id.and_then(|webview_id| self.get_webview_handle(webview_id)) {
785 Some(webview) => webview.delegate().show_notification(webview, notification),
786 None => self.delegate.borrow().show_notification(notification),
787 }
788 },
789 EmbedderMsg::ShowConsoleApiMessage(webview_id, level, message) => {
790 match webview_id.and_then(|webview_id| self.get_webview_handle(webview_id)) {
791 Some(webview) => webview
792 .delegate()
793 .show_console_message(webview, level, message),
794 None => self.delegate.borrow().show_console_message(level, message),
795 }
796 },
797 EmbedderMsg::ShowEmbedderControl(control_id, position, embedder_control_request) => {
798 if let Some(webview) = self.get_webview_handle(control_id.webview_id) {
799 webview.show_embedder_control(control_id, position, embedder_control_request);
800 }
801 },
802 EmbedderMsg::HideEmbedderControl(control_id) => {
803 if let Some(webview) = self.get_webview_handle(control_id.webview_id) {
804 webview
805 .delegate()
806 .hide_embedder_control(webview, control_id);
807 }
808 },
809 EmbedderMsg::GetWindowRect(webview_id, response_sender) => {
810 let window_rect = || {
811 let Some(webview) = self.get_webview_handle(webview_id) else {
812 return DeviceIndependentIntRect::default();
813 };
814 let hidpi_scale_factor = webview.hidpi_scale_factor();
815 let Some(screen_geometry) = webview.delegate().screen_geometry(webview) else {
816 return DeviceIndependentIntRect::default();
817 };
818
819 convert_rect_to_css_pixel(screen_geometry.window_rect, hidpi_scale_factor)
820 };
821
822 if let Err(error) = response_sender.send(window_rect()) {
823 warn!("Failed to respond to GetWindowRect: {error}");
824 }
825 },
826 EmbedderMsg::GetScreenMetrics(webview_id, response_sender) => {
827 let screen_metrics = || {
828 let Some(webview) = self.get_webview_handle(webview_id) else {
829 return ScreenMetrics::default();
830 };
831 let hidpi_scale_factor = webview.hidpi_scale_factor();
832 let Some(screen_geometry) = webview.delegate().screen_geometry(webview) else {
833 return ScreenMetrics::default();
834 };
835
836 ScreenMetrics {
837 screen_size: convert_size_to_css_pixel(
838 screen_geometry.size,
839 hidpi_scale_factor,
840 ),
841 available_size: convert_size_to_css_pixel(
842 screen_geometry.available_size,
843 hidpi_scale_factor,
844 ),
845 }
846 };
847 if let Err(error) = response_sender.send(screen_metrics()) {
848 warn!("Failed to respond to GetScreenMetrics: {error}");
849 }
850 },
851 EmbedderMsg::AccessibilityTreeUpdate(webview_id, tree_update, epoch) => {
852 if let Some(webview) = self.get_webview_handle(webview_id) {
853 webview.process_accessibility_tree_update(tree_update, epoch);
854 }
855 },
856 }
857 }
858
859 fn handle_constellation_embedder_message(&self, message: ConstellationToEmbedderMsg) {
860 match message {
861 ConstellationToEmbedderMsg::ShutdownComplete => self.finish_shutting_down(),
862 ConstellationToEmbedderMsg::AllowNavigationRequest(
863 webview_id,
864 pipeline_id,
865 servo_url,
866 ) => {
867 if let Some(webview) = self.get_webview_handle(webview_id) {
868 let request = NavigationRequest {
869 url: servo_url.into_url(),
870 pipeline_id,
871 constellation_proxy: self.constellation_proxy.clone(),
872 response_sent: false,
873 };
874 webview.delegate().request_navigation(webview, request);
875 }
876 },
877 ConstellationToEmbedderMsg::AllowOpeningWebView(webview_id, response_sender) => {
878 if let Some(webview) = self.get_webview_handle(webview_id) {
879 webview.request_create_new(response_sender);
880 }
881 },
882 ConstellationToEmbedderMsg::WebViewClosed(webview_id) => {
883 if let Some(webview) = self.get_webview_handle(webview_id) {
884 webview.delegate().notify_closed(webview);
885 }
886 },
887 ConstellationToEmbedderMsg::FinishJavaScriptEvaluation(evaluation_id, result) => {
888 self.javascript_evaluator
889 .borrow_mut()
890 .finish_evaluation(evaluation_id, result);
891 },
892 ConstellationToEmbedderMsg::InputEventsHandled(webview_id, event_outcomes) => {
893 let webview = self.get_webview_handle(webview_id);
894 for InputEventOutcome {
895 id: input_event_id,
896 result,
897 } in event_outcomes
898 {
899 self.paint.borrow_mut().notify_input_event_handled(
900 webview_id,
901 input_event_id,
902 result,
903 );
904 if let Some(ref webview) = webview {
905 webview.delegate().notify_input_event_handled(
906 webview.clone(),
907 input_event_id,
908 result,
909 );
910 }
911 }
912 },
913 ConstellationToEmbedderMsg::HistoryTraversalComplete(webview_id, traversal_id) => {
914 if let Some(webview) = self.get_webview_handle(webview_id) {
915 webview
916 .delegate()
917 .notify_traversal_complete(webview.clone(), traversal_id);
918 }
919 },
920 ConstellationToEmbedderMsg::HistoryChanged(
921 webview_id,
922 new_back_forward_list,
923 current_list_index,
924 ) => {
925 if let Some(webview) = self.get_webview_handle(webview_id) {
926 webview.set_history(new_back_forward_list, current_list_index);
927 }
928 },
929 ConstellationToEmbedderMsg::Panic(webview_id, reason, backtrace) => {
930 if let Some(webview) = self.get_webview_handle(webview_id) {
931 webview
932 .delegate()
933 .notify_crashed(webview, reason, backtrace);
934 }
935 },
936 ConstellationToEmbedderMsg::PipelineExited(pipeline_id) => {
937 let orphaned = self
938 .geolocation_watches
939 .borrow()
940 .get(&pipeline_id)
941 .cloned()
942 .unwrap_or_default();
943 for watch_id in orphaned {
944 self.stop_geolocation_watch(&watch_id);
945 }
946 },
947 ConstellationToEmbedderMsg::MediaSessionEvent(webview_id, media_session_event) => {
948 if let Some(webview) = self.get_webview_handle(webview_id) {
949 webview
950 .delegate()
951 .notify_media_session_event(webview, media_session_event);
952 }
953 },
954 }
955 }
956}
957
958impl Drop for ServoInner {
959 fn drop(&mut self) {
960 self.constellation_proxy
961 .send(EmbedderToConstellationMessage::Exit);
962 self.shutdown_state.set(ShutdownState::ShuttingDown);
963 while self.spin_event_loop() {
964 std::thread::sleep(Duration::from_micros(500));
965 }
966 }
967}
968
969#[cfg(feature = "devtools")]
970type DevtoolsMessage = devtools_traits::DevtoolsControlMsg;
971
972#[cfg(not(feature = "devtools"))]
973type DevtoolsMessage = ();
974
975#[derive(Clone)]
984pub struct Servo(Rc<ServoInner>);
985
986impl Servo {
987 #[servo_tracing::instrument(name = "Servo::new", skip(builder))]
988 fn new(builder: ServoBuilder) -> Self {
989 let opts = builder.opts.map(|opts| *opts).unwrap_or_default();
991 opts::initialize_options(opts);
992 let opts = opts::get();
993
994 let preferences = builder.preferences.map(|opts| *opts);
997 servo_config::prefs::set(preferences.unwrap_or_default());
998
999 use std::sync::atomic::Ordering;
1000
1001 style::context::DEFAULT_DISABLE_STYLE_SHARING_CACHE.store(
1002 !pref!(layout_style_sharing_cache_enabled),
1003 Ordering::Relaxed,
1004 );
1005 style::context::DEFAULT_DUMP_STYLE_STATISTICS.store(
1006 opts.debug
1007 .is_enabled(DiagnosticsLoggingOption::StyleStatistics),
1008 Ordering::Relaxed,
1009 );
1010
1011 if !opts.multiprocess {
1012 media_platform::init();
1013 }
1014
1015 PipelineNamespace::install(EMBEDDER_PIPELINE_NAMESPACE_ID);
1017
1018 let event_loop_waker = builder.event_loop_waker;
1023 let (paint_proxy, paint_receiver) = create_paint_channel(event_loop_waker.clone());
1024 let (constellation_proxy, embedder_to_constellation_receiver) = ConstellationProxy::new();
1025 let (embedder_proxy, embedder_receiver) = create_embedder_channel(event_loop_waker.clone());
1026 let (net_embedder_proxy, net_embedder_receiver) =
1027 create_generic_embedder_channel::<NetToEmbedderMsg>(event_loop_waker.clone());
1028 let (constellation_embedder_proxy, constellation_embedder_receiver) =
1029 create_generic_embedder_channel::<ConstellationToEmbedderMsg>(event_loop_waker.clone());
1030 let time_profiler_chan = profile_time::Profiler::create(
1031 &opts.time_profiling,
1032 opts.time_profiler_trace_path.clone(),
1033 );
1034 let mem_profiler_chan = profile_mem::Profiler::create();
1035
1036 let mut devtools_sender: Option<Sender<DevtoolsMessage>> = None;
1037 #[cfg(feature = "devtools")]
1038 if pref!(devtools_server_enabled) {
1039 devtools_sender = Some(devtools::start_server(
1040 embedder_proxy.clone(),
1041 mem_profiler_chan.clone(),
1042 ))
1043 }
1044
1045 let js_engine_setup = if !opts.multiprocess {
1048 Some(script::init())
1049 } else {
1050 None
1051 };
1052
1053 let mut protocols = ProtocolRegistry::with_internal_protocols();
1056 protocols.merge(builder.protocol_registry);
1057
1058 let shutdown_state = Rc::new(Cell::new(ShutdownState::NotShuttingDown));
1061 let paint = Paint::new(InitialPaintState {
1062 paint_proxy: paint_proxy.clone(),
1063 receiver: paint_receiver,
1064 embedder_to_constellation_sender: constellation_proxy.sender(),
1065 time_profiler_chan: time_profiler_chan.clone(),
1066 mem_profiler_chan: mem_profiler_chan.clone(),
1067 shutdown_state: shutdown_state.clone(),
1068 event_loop_waker: event_loop_waker.clone(),
1069 });
1070
1071 let protocols = Arc::new(protocols);
1072 let (public_resource_threads, private_resource_threads, async_runtime) =
1073 new_resource_threads(
1074 devtools_sender.clone(),
1075 time_profiler_chan.clone(),
1076 mem_profiler_chan.clone(),
1077 net_embedder_proxy,
1078 opts.config_dir.clone(),
1079 opts.certificate_path.clone(),
1080 opts.ignore_certificate_errors,
1081 protocols.clone(),
1082 );
1083
1084 let (private_storage_threads, public_storage_threads) = new_storage_threads(
1085 mem_profiler_chan.clone(),
1086 opts.config_dir.clone(),
1087 opts.temporary_storage,
1088 );
1089
1090 create_constellation(
1091 embedder_to_constellation_receiver,
1092 &paint.borrow(),
1093 embedder_proxy,
1094 constellation_embedder_proxy,
1095 paint_proxy,
1096 time_profiler_chan,
1097 mem_profiler_chan,
1098 #[cfg(feature = "devtools")]
1099 devtools_sender,
1100 protocols,
1101 public_resource_threads.clone(),
1102 private_resource_threads.clone(),
1103 async_runtime,
1104 public_storage_threads.clone(),
1105 private_storage_threads.clone(),
1106 );
1107
1108 net::connector::prewarm_tls();
1109
1110 #[cfg(feature = "multiprocess")]
1111 if opts::get().multiprocess {
1112 prefs::add_observer(Box::new(constellation_proxy.clone()));
1113 }
1114
1115 Servo(Rc::new(ServoInner {
1116 delegate: RefCell::new(Rc::new(DefaultServoDelegate)),
1117 paint,
1118 network_manager: Rc::new(RefCell::new(NetworkManager::new(
1119 public_resource_threads.clone(),
1120 private_resource_threads.clone(),
1121 constellation_proxy.clone(),
1122 ))),
1123 site_data_manager: SiteDataManager::new(
1124 public_resource_threads,
1125 private_resource_threads,
1126 public_storage_threads,
1127 private_storage_threads,
1128 ),
1129 javascript_evaluator: Rc::new(RefCell::new(JavaScriptEvaluator::new(
1130 constellation_proxy.clone(),
1131 ))),
1132 constellation_proxy,
1133 embedder_receiver,
1134 net_embedder_receiver,
1135 constellation_embedder_receiver,
1136 shutdown_state,
1137 webviews: Default::default(),
1138 servo_errors: ServoErrorChannel::default(),
1139 _js_engine_setup: js_engine_setup,
1140 pending_handled_input_events: Default::default(),
1141 event_loop_waker,
1142 geolocation_watches: Default::default(),
1143 }))
1144 }
1145
1146 pub fn delegate(&self) -> Rc<dyn ServoDelegate> {
1147 self.0.delegate.borrow().clone()
1148 }
1149
1150 pub fn set_delegate(&self, delegate: Rc<dyn ServoDelegate>) {
1151 *self.0.delegate.borrow_mut() = delegate;
1152 }
1153
1154 pub fn initialize_gl_accelerated_media(display: NativeDisplay, api: GlApi, context: GlContext) {
1157 WindowGLContext::initialize(display, api, context)
1158 }
1159
1160 pub fn spin_event_loop(&self) {
1166 self.0.spin_event_loop();
1167 }
1168
1169 pub fn setup_logging(&self) {
1170 let constellation_chan = self.0.constellation_proxy.sender();
1171 let env = env_logger::Env::default();
1172 let env_logger = EnvLoggerBuilder::from_env(env).build();
1173 let con_logger = FromEmbedderLogger::new(constellation_chan);
1174
1175 let filter = max(env_logger.filter(), con_logger.filter());
1176 let logger = BothLogger(env_logger, con_logger);
1177
1178 log::set_boxed_logger(Box::new(logger)).expect("Failed to set logger.");
1179 log::set_max_level(filter);
1180 }
1181
1182 pub fn create_memory_report(&self, snd: GenericCallback<MemoryReportResult>) {
1183 self.0
1184 .constellation_proxy
1185 .send(EmbedderToConstellationMessage::CreateMemoryReport(snd));
1186 }
1187
1188 pub fn execute_webdriver_command(&self, command: WebDriverCommandMsg) {
1189 self.0
1190 .constellation_proxy
1191 .send(EmbedderToConstellationMessage::WebDriverCommand(command));
1192 }
1193
1194 pub fn set_preference(&self, name: &str, value: PrefValue) {
1195 let mut preferences = prefs::get().clone();
1196 preferences.set_value(name, value);
1197 prefs::set(preferences);
1198 }
1199
1200 pub fn network_manager<'a>(&'a self) -> Ref<'a, NetworkManager> {
1201 self.0.network_manager.borrow()
1202 }
1203
1204 pub fn site_data_manager(&self) -> &SiteDataManager {
1205 &self.0.site_data_manager
1206 }
1207
1208 pub fn forward_accessibility_action(&self, action_request: ActionRequest) {
1216 self.0.constellation_proxy.send(
1217 EmbedderToConstellationMessage::ForwardAccessibilityAction(action_request),
1218 );
1219 }
1220
1221 pub(crate) fn paint<'a>(&'a self) -> Ref<'a, Paint> {
1222 self.0.paint.borrow()
1223 }
1224
1225 pub(crate) fn paint_mut<'a>(&'a self) -> RefMut<'a, Paint> {
1226 self.0.paint.borrow_mut()
1227 }
1228
1229 pub(crate) fn event_loop_waker(&self) -> &dyn EventLoopWaker {
1230 &*self.0.event_loop_waker
1231 }
1232
1233 pub(crate) fn webviews_mut<'a>(
1234 &'a self,
1235 ) -> RefMut<'a, FxHashMap<WebViewId, Weak<RefCell<WebViewInner>>>> {
1236 self.0.webviews.borrow_mut()
1237 }
1238
1239 pub(crate) fn constellation_proxy(&self) -> &ConstellationProxy {
1240 &self.0.constellation_proxy
1241 }
1242
1243 pub(crate) fn javascript_evaluator_mut<'a>(&'a self) -> RefMut<'a, JavaScriptEvaluator> {
1244 self.0.javascript_evaluator.borrow_mut()
1245 }
1246
1247 pub(crate) fn add_pending_handled_input_event(&self, residue_event: PendingHandledInputEvent) {
1248 self.0
1249 .pending_handled_input_events
1250 .borrow_mut()
1251 .push(residue_event);
1252 }
1253
1254 #[cfg(feature = "webxr")]
1255 pub fn register_webxr_registry(&self, registry: Box<dyn WebXrRegistry>) {
1257 self.0.paint.borrow().register_webxr_registry(registry);
1258 }
1259}
1260
1261fn create_embedder_channel(
1262 event_loop_waker: Box<dyn EventLoopWaker>,
1263) -> (EmbedderProxy, Receiver<EmbedderMsg>) {
1264 let (sender, receiver) = unbounded();
1265 (
1266 EmbedderProxy {
1267 sender,
1268 event_loop_waker,
1269 },
1270 receiver,
1271 )
1272}
1273
1274fn create_generic_embedder_channel<T>(
1275 event_loop_waker: Box<dyn EventLoopWaker>,
1276) -> (GenericEmbedderProxy<T>, Receiver<T>) {
1277 let (sender, receiver) = unbounded();
1278 (
1279 GenericEmbedderProxy {
1280 sender,
1281 event_loop_waker,
1282 },
1283 receiver,
1284 )
1285}
1286
1287fn create_paint_channel(
1288 event_loop_waker: Box<dyn EventLoopWaker>,
1289) -> (PaintProxy, RoutedReceiver<PaintMessage>) {
1290 let (sender, receiver) = unbounded();
1291 let sender_clone = sender.clone();
1292 let event_loop_waker_clone = event_loop_waker.clone();
1293 let result_callback = move |msg: Result<PaintMessage, SendError>| {
1295 if let Err(err) = sender_clone.send(msg) {
1296 warn!("Failed to send response ({:?}).", err);
1297 }
1298 event_loop_waker_clone.wake();
1299 };
1300
1301 let generic_callback =
1302 GenericCallback::new(result_callback).expect("Failed to create callback");
1303 let cross_process_paint_api = CrossProcessPaintApi::new(generic_callback);
1304 let paint_proxy = PaintProxy {
1305 sender,
1306 cross_process_paint_api,
1307 event_loop_waker,
1308 };
1309
1310 (paint_proxy, receiver)
1311}
1312
1313#[expect(clippy::too_many_arguments)]
1314fn create_constellation(
1315 embedder_to_constellation_receiver: Receiver<EmbedderToConstellationMessage>,
1316 paint: &Paint,
1317 embedder_proxy: EmbedderProxy,
1318 constellation_to_embedder_proxy: GenericEmbedderProxy<ConstellationToEmbedderMsg>,
1319 paint_proxy: PaintProxy,
1320 time_profiler_chan: time::ProfilerChan,
1321 mem_profiler_chan: mem::ProfilerChan,
1322 #[cfg(feature = "devtools")] devtools_sender: Option<
1323 Sender<devtools_traits::DevtoolsControlMsg>,
1324 >,
1325 protocols: Arc<ProtocolRegistry>,
1326 public_resource_threads: ResourceThreads,
1327 private_resource_threads: ResourceThreads,
1328 async_runtime: Box<dyn net_traits::AsyncRuntime>,
1329 public_storage_threads: StorageThreads,
1330 private_storage_threads: StorageThreads,
1331) {
1332 let opts = opts::get();
1334
1335 #[cfg(feature = "bluetooth")]
1336 let bluetooth_thread: GenericSender<BluetoothRequest> =
1337 BluetoothThreadFactory::new(embedder_proxy.clone());
1338
1339 let privileged_urls = protocols.privileged_urls();
1340
1341 let system_font_service = Arc::new(
1342 SystemFontService::spawn(
1343 paint_proxy.cross_process_paint_api.clone(),
1344 mem_profiler_chan.clone(),
1345 )
1346 .to_proxy(),
1347 );
1348
1349 let initial_state = InitialConstellationState {
1350 paint_proxy,
1351 embedder_proxy,
1352 constellation_to_embedder_proxy,
1353 #[cfg(feature = "devtools")]
1354 devtools_sender,
1355 #[cfg(feature = "bluetooth")]
1356 bluetooth_thread,
1357 system_font_service,
1358 public_resource_threads,
1359 private_resource_threads,
1360 public_storage_threads,
1361 private_storage_threads,
1362 time_profiler_chan,
1363 mem_profiler_chan,
1364 #[cfg(feature = "webxr")]
1365 webxr_registry: Some(paint.webxr_main_thread_registry()),
1366 #[cfg(not(feature = "webxr"))]
1367 webxr_registry: None,
1368 #[cfg(feature = "webgl")]
1369 webgl_threads: Some(paint.webgl_threads()),
1370 webrender_external_image_id_manager: paint.webrender_external_image_id_manager(),
1371 #[cfg(feature = "webgpu")]
1372 wgpu_image_map: paint.webgpu_image_map(),
1373 async_runtime,
1374 privileged_urls,
1375 wake_lock_provider: Box::new(DefaultWakeLockDelegate),
1376 };
1377
1378 let layout_factory = Arc::new(LayoutFactoryImpl());
1379
1380 Constellation::<script::ScriptThread, script::ServiceWorkerManager>::start(
1381 embedder_to_constellation_receiver,
1382 initial_state,
1383 layout_factory,
1384 opts.random_pipeline_closure_probability,
1385 opts.random_pipeline_closure_seed,
1386 opts.hard_fail,
1387 );
1388}
1389
1390struct BothLogger<Log1, Log2>(Log1, Log2);
1393
1394impl<Log1, Log2> Log for BothLogger<Log1, Log2>
1395where
1396 Log1: Log,
1397 Log2: Log,
1398{
1399 fn enabled(&self, metadata: &Metadata) -> bool {
1400 self.0.enabled(metadata) || self.1.enabled(metadata)
1401 }
1402
1403 fn log(&self, record: &Record) {
1404 self.0.log(record);
1405 self.1.log(record);
1406 }
1407
1408 fn flush(&self) {
1409 self.0.flush();
1410 self.1.flush();
1411 }
1412}
1413
1414#[cfg(feature = "multiprocess")]
1415fn set_logger(script_to_constellation_sender: ScriptToConstellationSender) {
1416 let con_logger = FromScriptLogger::new(script_to_constellation_sender);
1417 let env = env_logger::Env::default();
1418 let env_logger = EnvLoggerBuilder::from_env(env).build();
1419
1420 let filter = max(env_logger.filter(), con_logger.filter());
1421 let logger = BothLogger(env_logger, con_logger);
1422
1423 log::set_boxed_logger(Box::new(logger)).expect("Failed to set logger.");
1424 log::set_max_level(filter);
1425}
1426
1427#[cfg(feature = "multiprocess")]
1429pub fn run_content_process(token: String) {
1430 let (unprivileged_content_sender, unprivileged_content_receiver) =
1431 ipc::channel::<UnprivilegedContent>().unwrap();
1432 let connection_bootstrap: IpcSender<IpcSender<UnprivilegedContent>> =
1433 IpcSender::connect(token).unwrap();
1434 connection_bootstrap
1435 .send(unprivileged_content_sender)
1436 .unwrap();
1437
1438 let unprivileged_content = unprivileged_content_receiver.recv().unwrap();
1439 opts::initialize_options(unprivileged_content.opts());
1440 prefs::set(unprivileged_content.prefs().clone());
1441
1442 if opts::get().sandbox {
1444 create_sandbox();
1445 }
1446
1447 let _js_engine_setup = script::init();
1448
1449 match unprivileged_content {
1450 UnprivilegedContent::ScriptEventLoop(new_event_loop_info) => {
1451 media_platform::init();
1452
1453 set_logger(
1454 new_event_loop_info
1455 .initial_script_state
1456 .script_to_constellation_sender
1457 .clone(),
1458 );
1459
1460 register_system_memory_reporter_for_event_loop(&new_event_loop_info);
1461
1462 let (background_hang_monitor_register, background_hang_monitor_join_handle) =
1463 HangMonitorRegister::init(
1464 new_event_loop_info.bhm_to_constellation_sender.clone(),
1465 new_event_loop_info.constellation_to_bhm_receiver,
1466 opts::get().background_hang_monitor,
1467 );
1468
1469 let layout_factory = Arc::new(LayoutFactoryImpl());
1470 let script_join_handle = script::ScriptThread::create(
1471 new_event_loop_info.initial_script_state,
1472 layout_factory,
1473 Arc::new(ImageCacheFactoryImpl::new(
1474 new_event_loop_info.broken_image_icon_data,
1475 )),
1476 background_hang_monitor_register,
1477 );
1478
1479 script_join_handle
1480 .join()
1481 .expect("Failed to join on the script thread.");
1482 background_hang_monitor_join_handle
1483 .join()
1484 .expect("Failed to join on the BHM background thread.");
1485
1486 StyleThreadPool::shutdown();
1487
1488 FetchThread::exit();
1490 },
1491 UnprivilegedContent::ServiceWorker(content) => {
1492 content.start::<ServiceWorkerManager>();
1493 },
1494 }
1495}
1496
1497#[cfg(all(
1498 feature = "multiprocess",
1499 not(target_os = "windows"),
1500 not(target_os = "ios"),
1501 not(target_os = "android"),
1502 not(target_arch = "arm"),
1503 not(target_arch = "aarch64"),
1504 not(target_arch = "riscv32"),
1505 not(target_arch = "riscv64"),
1506 not(target_env = "ohos"),
1507))]
1508fn create_sandbox() {
1509 ChildSandbox::new(content_process_sandbox_profile())
1510 .activate()
1511 .expect("Failed to activate sandbox!");
1512}
1513
1514#[cfg(any(
1515 target_os = "windows",
1516 target_os = "ios",
1517 target_os = "android",
1518 target_arch = "arm",
1519 target_arch = "aarch64",
1520 target_arch = "riscv32",
1521 target_arch = "riscv64",
1522 target_env = "ohos",
1523))]
1524fn create_sandbox() {
1525 panic!("Sandboxing is not supported on Windows, iOS, ARM, RISC-V targets and android.");
1526}
1527
1528struct DefaultEventLoopWaker;
1529
1530impl EventLoopWaker for DefaultEventLoopWaker {
1531 fn clone_box(&self) -> Box<dyn EventLoopWaker> {
1532 Box::new(DefaultEventLoopWaker)
1533 }
1534
1535 fn wake(&self) {}
1536}
1537
1538pub struct ServoBuilder {
1540 opts: Option<Box<Opts>>,
1541 preferences: Option<Box<Preferences>>,
1542 event_loop_waker: Box<dyn EventLoopWaker>,
1543 protocol_registry: ProtocolRegistry,
1544}
1545
1546impl Default for ServoBuilder {
1547 fn default() -> Self {
1548 Self {
1549 opts: Default::default(),
1550 preferences: Default::default(),
1551 event_loop_waker: Box::new(DefaultEventLoopWaker),
1552 protocol_registry: Default::default(),
1553 }
1554 }
1555}
1556
1557impl ServoBuilder {
1558 pub fn build(self) -> Servo {
1559 Servo::new(self)
1560 }
1561
1562 pub fn opts(mut self, opts: Opts) -> Self {
1563 self.opts = Some(Box::new(opts));
1564 self
1565 }
1566
1567 pub fn preferences(mut self, preferences: Preferences) -> Self {
1568 self.preferences = Some(Box::new(preferences));
1569 self
1570 }
1571
1572 pub fn event_loop_waker(mut self, event_loop_waker: Box<dyn EventLoopWaker>) -> Self {
1573 self.event_loop_waker = event_loop_waker;
1574 self
1575 }
1576
1577 pub fn protocol_registry(mut self, protocol_registry: ProtocolRegistry) -> Self {
1578 self.protocol_registry = protocol_registry;
1579 self
1580 }
1581}
1582
1583#[cfg(feature = "multiprocess")]
1584fn register_system_memory_reporter_for_event_loop(
1585 new_event_loop_info: &NewScriptEventLoopProcessInfo,
1586) {
1587 let callback = GenericCallback::new(|message| {
1591 if let Ok(request) = message {
1592 profile::system_reporter::collect_reports(request);
1593 }
1594 })
1595 .expect("Could not create memory reporter callback");
1596 new_event_loop_info
1597 .initial_script_state
1598 .memory_profiler_sender
1599 .send(ProfilerMsg::RegisterReporter(
1600 format!("system-content-{}", std::process::id()),
1601 Reporter(callback),
1602 ));
1603}