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