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