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