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