diff --git a/Cargo.lock b/Cargo.lock index 32b8d709533..11466398098 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1530,9 +1530,11 @@ version = "0.0.1" dependencies = [ "base", "canvas_traits", + "compositing_traits", "devtools_traits", "embedder_traits", "euclid", + "fonts_traits", "http 1.3.1", "hyper_serde", "ipc-channel", @@ -2720,6 +2722,8 @@ dependencies = [ "log", "malloc_size_of_derive", "memmap2", + "parking_lot", + "profile_traits", "range", "read-fonts", "serde", diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 0b5358805dd..958d163fec4 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -2443,9 +2443,11 @@ where let sw_senders = SWManagerSenders { swmanager_sender: self.swmanager_ipc_sender.clone(), - resource_sender: self.public_resource_threads.sender(), + resource_threads: self.public_resource_threads.clone(), own_sender: own_sender.clone(), receiver, + compositor_api: self.compositor_proxy.cross_process_compositor_api.clone(), + system_font_service_sender: self.system_font_service.to_sender(), }; if opts::get().multiprocess { diff --git a/components/fonts/system_font_service.rs b/components/fonts/system_font_service.rs index 8f88d761648..eaaa0bb52db 100644 --- a/components/fonts/system_font_service.rs +++ b/components/fonts/system_font_service.rs @@ -11,17 +11,15 @@ use app_units::Au; use compositing_traits::CrossProcessCompositorApi; use fonts_traits::{ FontDescriptor, FontIdentifier, FontTemplate, FontTemplateRef, LowercaseFontFamilyName, + SystemFontServiceMessage, SystemFontServiceProxySender, }; -use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; -use log::debug; +use ipc_channel::ipc::{self, IpcReceiver}; use malloc_size_of::MallocSizeOf as MallocSizeOfTrait; use malloc_size_of_derive::MallocSizeOf; -use parking_lot::{Mutex, RwLock}; use profile_traits::mem::{ ProcessReports, ProfilerChan, Report, ReportKind, ReportsChan, perform_memory_report, }; use profile_traits::path; -use serde::{Deserialize, Serialize}; use servo_config::pref; use style::values::computed::font::{GenericFontFamily, SingleFontFamily}; use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey, FontVariation}; @@ -31,28 +29,6 @@ use crate::platform::font_list::{ default_system_generic_font_family, for_each_available_family, for_each_variation, }; -/// Commands that the `FontContext` sends to the `SystemFontService`. -#[derive(Debug, Deserialize, Serialize)] -pub enum SystemFontServiceMessage { - GetFontTemplates( - Option, - SingleFontFamily, - IpcSender>, - ), - GetFontInstance( - FontIdentifier, - Au, - FontInstanceFlags, - Vec, - IpcSender, - ), - GetFontKey(IpcSender), - GetFontInstanceKey(IpcSender), - CollectMemoryReport(ReportsChan), - Exit(IpcSender<()>), - Ping, -} - #[derive(Default, MallocSizeOf)] struct ResolvedGenericFontFamilies { default: OnceCell, @@ -89,18 +65,6 @@ pub struct SystemFontService { free_font_instance_keys: Vec, } -#[derive(Clone, Deserialize, Serialize)] -pub struct SystemFontServiceProxySender(pub IpcSender); - -impl SystemFontServiceProxySender { - pub fn to_proxy(&self) -> SystemFontServiceProxy { - SystemFontServiceProxy { - sender: Mutex::new(self.0.clone()), - templates: Default::default(), - } - } -} - impl SystemFontService { pub fn spawn( compositor_api: CrossProcessCompositorApi, @@ -342,140 +306,3 @@ impl SystemFontService { .clone() } } - -#[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)] -struct FontTemplateCacheKey { - font_descriptor: Option, - family_descriptor: SingleFontFamily, -} - -/// The public interface to the [`SystemFontService`], used by per-Document -/// `FontContext` instances. -#[derive(Debug, MallocSizeOf)] -pub struct SystemFontServiceProxy { - sender: Mutex>, - templates: RwLock>>, -} - -impl SystemFontServiceProxy { - pub fn exit(&self) { - let (response_chan, response_port) = ipc::channel().unwrap(); - self.sender - .lock() - .send(SystemFontServiceMessage::Exit(response_chan)) - .expect("Couldn't send SystemFontService exit message"); - response_port - .recv() - .expect("Couldn't receive SystemFontService reply"); - } - - pub fn to_sender(&self) -> SystemFontServiceProxySender { - SystemFontServiceProxySender(self.sender.lock().clone()) - } - - pub(crate) fn get_system_font_instance( - &self, - identifier: FontIdentifier, - size: Au, - flags: FontInstanceFlags, - variations: Vec, - ) -> FontInstanceKey { - let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel"); - self.sender - .lock() - .send(SystemFontServiceMessage::GetFontInstance( - identifier, - size, - flags, - variations, - response_chan, - )) - .expect("failed to send message to system font service"); - - let instance_key = response_port.recv(); - if instance_key.is_err() { - let font_thread_has_closed = self - .sender - .lock() - .send(SystemFontServiceMessage::Ping) - .is_err(); - assert!( - font_thread_has_closed, - "Failed to receive a response from live font cache" - ); - panic!("SystemFontService has already exited."); - } - instance_key.unwrap() - } - - pub(crate) fn find_matching_font_templates( - &self, - descriptor_to_match: Option<&FontDescriptor>, - family_descriptor: &SingleFontFamily, - ) -> Vec { - let cache_key = FontTemplateCacheKey { - font_descriptor: descriptor_to_match.cloned(), - family_descriptor: family_descriptor.clone(), - }; - if let Some(templates) = self.templates.read().get(&cache_key).cloned() { - return templates; - } - - debug!( - "SystemFontServiceProxy: cache miss for template_descriptor={:?} family_descriptor={:?}", - descriptor_to_match, family_descriptor - ); - - let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel"); - self.sender - .lock() - .send(SystemFontServiceMessage::GetFontTemplates( - descriptor_to_match.cloned(), - family_descriptor.clone(), - response_chan, - )) - .expect("failed to send message to system font service"); - - let Ok(templates) = response_port.recv() else { - let font_thread_has_closed = self - .sender - .lock() - .send(SystemFontServiceMessage::Ping) - .is_err(); - assert!( - font_thread_has_closed, - "Failed to receive a response from live font cache" - ); - panic!("SystemFontService has already exited."); - }; - - let templates: Vec<_> = templates.into_iter().map(FontTemplateRef::new).collect(); - self.templates.write().insert(cache_key, templates.clone()); - - templates - } - - pub(crate) fn generate_font_key(&self) -> FontKey { - let (result_sender, result_receiver) = - ipc::channel().expect("failed to create IPC channel"); - self.sender - .lock() - .send(SystemFontServiceMessage::GetFontKey(result_sender)) - .expect("failed to send message to system font service"); - result_receiver - .recv() - .expect("Failed to communicate with system font service.") - } - - pub(crate) fn generate_font_instance_key(&self) -> FontInstanceKey { - let (result_sender, result_receiver) = - ipc::channel().expect("failed to create IPC channel"); - self.sender - .lock() - .send(SystemFontServiceMessage::GetFontInstanceKey(result_sender)) - .expect("failed to send message to system font service"); - result_receiver - .recv() - .expect("Failed to communicate with system font service.") - } -} diff --git a/components/script/dom/debuggerglobalscope.rs b/components/script/dom/debuggerglobalscope.rs index 3833b24889b..ca5c3090b06 100644 --- a/components/script/dom/debuggerglobalscope.rs +++ b/components/script/dom/debuggerglobalscope.rs @@ -87,6 +87,7 @@ impl DebuggerGlobalScope { gpu_id_hub, None, false, + None, // font_context ), devtools_to_script_sender, get_possible_breakpoints_result_sender: RefCell::new(None), diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index 423d33d9f5c..5c85312413a 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -11,6 +11,7 @@ use constellation_traits::{WorkerGlobalScopeInit, WorkerScriptLoadOrigin}; use crossbeam_channel::{Receiver, Sender, unbounded}; use devtools_traits::DevtoolScriptControlMsg; use dom_struct::dom_struct; +use fonts::FontContext; use headers::{HeaderMapExt, ReferrerPolicy as ReferrerPolicyHeader}; use ipc_channel::ipc::IpcReceiver; use ipc_channel::router::ROUTER; @@ -283,6 +284,7 @@ impl DedicatedWorkerGlobalScope { #[cfg(feature = "webgpu")] gpu_id_hub: Arc, control_receiver: Receiver, insecure_requests_policy: InsecureRequestsPolicy, + font_context: Option>, ) -> DedicatedWorkerGlobalScope { DedicatedWorkerGlobalScope { workerglobalscope: WorkerGlobalScope::new_inherited( @@ -296,6 +298,7 @@ impl DedicatedWorkerGlobalScope { #[cfg(feature = "webgpu")] gpu_id_hub, insecure_requests_policy, + font_context, ), task_queue: TaskQueue::new(receiver, own_sender.clone()), own_sender, @@ -324,6 +327,7 @@ impl DedicatedWorkerGlobalScope { #[cfg(feature = "webgpu")] gpu_id_hub: Arc, control_receiver: Receiver, insecure_requests_policy: InsecureRequestsPolicy, + font_context: Option>, ) -> DomRoot { let scope = Box::new(DedicatedWorkerGlobalScope::new_inherited( init, @@ -342,6 +346,7 @@ impl DedicatedWorkerGlobalScope { gpu_id_hub, control_receiver, insecure_requests_policy, + font_context, )); DedicatedWorkerGlobalScopeBinding::Wrap::( GlobalScope::get_cx(), @@ -370,6 +375,7 @@ impl DedicatedWorkerGlobalScope { context_sender: Sender, insecure_requests_policy: InsecureRequestsPolicy, policy_container: PolicyContainer, + font_context: Option>, ) -> JoinHandle<()> { let serialized_worker_url = worker_url.to_string(); let webview_id = WebViewId::installed(); @@ -485,6 +491,7 @@ impl DedicatedWorkerGlobalScope { gpu_id_hub, control_receiver, insecure_requests_policy, + font_context, ); debugger_global.fire_add_debuggee( CanGc::note(), diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs index 23ebd2e90f6..7988f226563 100644 --- a/components/script/dom/dissimilaroriginwindow.rs +++ b/components/script/dom/dissimilaroriginwindow.rs @@ -69,6 +69,7 @@ impl DissimilarOriginWindow { global_to_clone_from.wgpu_id_hub(), Some(global_to_clone_from.is_secure_context()), false, + global_to_clone_from.font_context().cloned(), ), window_proxy: Dom::from_ref(window_proxy), location: Default::default(), diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 3d6d05f65c7..a5ddceeee38 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -27,6 +27,7 @@ use crossbeam_channel::Sender; use devtools_traits::{PageError, ScriptToDevtoolsControlMsg}; use dom_struct::dom_struct; use embedder_traits::{EmbedderMsg, JavaScriptEvaluationError}; +use fonts::FontContext; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; use js::glue::{IsWrapper, UnwrapObjectDynamic}; @@ -383,6 +384,13 @@ pub(crate) struct GlobalScope { /// resolved_module_set: DomRefCell>, + + /// The [`FontContext`] for this [`GlobalScope`] if it has one. This is used for + /// canvas and layout, so if this [`GlobalScope`] doesn't need to use either, this + /// might be `None`. + #[conditional_malloc_size_of] + #[no_trace] + font_context: Option>, } /// A wrapper for glue-code between the ipc router and the event-loop. @@ -741,6 +749,7 @@ impl GlobalScope { #[cfg(feature = "webgpu")] gpu_id_hub: Arc, inherited_secure_context: Option, unminify_js: bool, + font_context: Option>, ) -> Self { Self { task_manager: Default::default(), @@ -789,6 +798,7 @@ impl GlobalScope { notification_permission_request_callback_map: Default::default(), import_map: Default::default(), resolved_module_set: Default::default(), + font_context, } } @@ -815,6 +825,10 @@ impl GlobalScope { self.timers.get_or_init(|| OneshotTimers::new(self)) } + pub(crate) fn font_context(&self) -> Option<&Arc> { + self.font_context.as_ref() + } + /// #[allow(clippy::too_many_arguments)] pub(crate) fn get_serviceworker_registration( diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index 51cf1d7a07c..283740d87da 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -14,6 +14,7 @@ use constellation_traits::{ use crossbeam_channel::{Receiver, Sender, after, unbounded}; use devtools_traits::DevtoolScriptControlMsg; use dom_struct::dom_struct; +use fonts::FontContext; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; use js::jsapi::{JS_AddInterruptCallback, JSContext}; @@ -227,6 +228,7 @@ impl ServiceWorkerGlobalScope { scope_url: ServoUrl, control_receiver: Receiver, closing: Arc, + font_context: Arc, ) -> ServiceWorkerGlobalScope { ServiceWorkerGlobalScope { workerglobalscope: WorkerGlobalScope::new_inherited( @@ -239,8 +241,9 @@ impl ServiceWorkerGlobalScope { closing, #[cfg(feature = "webgpu")] Arc::new(IdentityHub::default()), - InsecureRequestsPolicy::DoNotUpgrade, // FIXME: investigate what environment this value comes from for - // service workers. + // FIXME: investigate what environment this value comes from for service workers. + InsecureRequestsPolicy::DoNotUpgrade, + Some(font_context), ), task_queue: TaskQueue::new(receiver, own_sender.clone()), own_sender, @@ -264,6 +267,7 @@ impl ServiceWorkerGlobalScope { scope_url: ServoUrl, control_receiver: Receiver, closing: Arc, + font_context: Arc, ) -> DomRoot { let scope = Box::new(ServiceWorkerGlobalScope::new_inherited( init, @@ -277,6 +281,7 @@ impl ServiceWorkerGlobalScope { scope_url, control_receiver, closing, + font_context, )); ServiceWorkerGlobalScopeBinding::Wrap::(GlobalScope::get_cx(), scope) } @@ -293,6 +298,7 @@ impl ServiceWorkerGlobalScope { control_receiver: Receiver, context_sender: Sender, closing: Arc, + font_context: Arc, ) -> JoinHandle<()> { let ScopeThings { script_url, @@ -342,6 +348,7 @@ impl ServiceWorkerGlobalScope { scope_url, control_receiver, closing, + font_context, ); let scope = global.upcast::(); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 9adb5a022bc..49464f46ad7 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -246,11 +246,6 @@ pub(crate) struct Window { #[no_trace] #[ignore_malloc_size_of = "TODO: Add MallocSizeOf support to layout"] layout: RefCell>, - /// A [`FontContext`] which is used to store and match against fonts for this `Window` and to - /// trigger the download of web fonts. - #[no_trace] - #[conditional_malloc_size_of] - font_context: Arc, navigator: MutNullableDom, #[ignore_malloc_size_of = "Arc"] #[no_trace] @@ -722,7 +717,9 @@ impl Window { } pub(crate) fn font_context(&self) -> &Arc { - &self.font_context + self.as_global_scope() + .font_context() + .expect("A `Window` should always have a `FontContext`") } pub(crate) fn ongoing_navigation(&self) -> OngoingNavigation { @@ -2275,7 +2272,7 @@ impl Window { return; } - if self.font_context.web_fonts_still_loading() != 0 { + if self.font_context().web_fonts_still_loading() != 0 { return; } @@ -3136,11 +3133,11 @@ impl Window { gpu_id_hub, inherited_secure_context, unminify_js, + Some(font_context.clone()), ), ongoing_navigation: Default::default(), script_chan, layout: RefCell::new(layout), - font_context, image_cache_sender, image_cache, navigator: Default::default(), diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index 9f555283a82..ce95e834e39 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -255,6 +255,7 @@ impl WorkerMethods for Worker { context_sender, global.insecure_requests_policy(), global.policy_container(), + global.font_context().cloned(), ); let context = context_receiver diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 178b1166c97..6b212319be3 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -16,6 +16,7 @@ use content_security_policy::CspList; use crossbeam_channel::Receiver; use devtools_traits::{DevtoolScriptControlMsg, WorkerId}; use dom_struct::dom_struct; +use fonts::FontContext; use ipc_channel::ipc::IpcSender; use js::jsval::UndefinedValue; use js::panic::maybe_resume_unwind; @@ -167,6 +168,7 @@ impl WorkerGlobalScope { closing: Arc, #[cfg(feature = "webgpu")] gpu_id_hub: Arc, insecure_requests_policy: InsecureRequestsPolicy, + font_context: Option>, ) -> Self { // Install a pipeline-namespace in the current thread. PipelineNamespace::auto_install(); @@ -192,6 +194,7 @@ impl WorkerGlobalScope { gpu_id_hub, init.inherited_secure_context, false, + font_context, ), worker_id: init.worker_id, worker_name, diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs index a083a38f1da..e4d35b2f17d 100644 --- a/components/script/dom/workletglobalscope.rs +++ b/components/script/dom/workletglobalscope.rs @@ -108,6 +108,7 @@ impl WorkletGlobalScope { init.gpu_id_hub.clone(), init.inherited_secure_context, false, + None, // font_context ), base_url, to_script_thread_sender: init.to_script_thread_sender.clone(), diff --git a/components/script/serviceworker_manager.rs b/components/script/serviceworker_manager.rs index a2ac034f662..30a589641b1 100644 --- a/components/script/serviceworker_manager.rs +++ b/components/script/serviceworker_manager.rs @@ -18,6 +18,7 @@ use constellation_traits::{ ScopeThings, ServiceWorkerManagerFactory, ServiceWorkerMsg, }; use crossbeam_channel::{Receiver, RecvError, Sender, select, unbounded}; +use fonts::FontContext; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; use net_traits::{CoreResourceMsg, CustomResponseMediator}; @@ -223,6 +224,8 @@ pub struct ServiceWorkerManager { own_port: Receiver, // to receive resource messages resource_receiver: Receiver, + /// A shared [`FontContext`] to use for all service workers spawned by this [`ServiceWorkerManager`]. + font_context: Arc, } impl ServiceWorkerManager { @@ -231,6 +234,7 @@ impl ServiceWorkerManager { from_constellation_receiver: Receiver, resource_port: Receiver, constellation_sender: IpcSender, + font_context: Arc, ) -> ServiceWorkerManager { // Install a pipeline-namespace in the current thread. PipelineNamespace::auto_install(); @@ -241,6 +245,7 @@ impl ServiceWorkerManager { own_port: from_constellation_receiver, resource_receiver: resource_port, _constellation_sender: constellation_sender, + font_context, } } @@ -406,8 +411,12 @@ impl ServiceWorkerManager { // Very roughly steps 5 to 18. // TODO: implement all steps precisely. - let (new_worker, join_handle, control_sender, context, closing) = - update_serviceworker(self.own_sender.clone(), job.scope_url.clone(), scope_things); + let (new_worker, join_handle, control_sender, context, closing) = update_serviceworker( + self.own_sender.clone(), + job.scope_url.clone(), + scope_things, + self.font_context.clone(), + ); // Since we've just started the worker thread, ensure we can shut it down later. registration.note_worker_thread(join_handle, control_sender, context, closing); @@ -446,6 +455,7 @@ fn update_serviceworker( own_sender: IpcSender, scope_url: ServoUrl, scope_things: ScopeThings, + font_context: Arc, ) -> ( ServiceWorker, JoinHandle<()>, @@ -471,6 +481,7 @@ fn update_serviceworker( control_receiver, context_sender, closing.clone(), + font_context, ); let context = context_receiver @@ -491,21 +502,33 @@ impl ServiceWorkerManagerFactory for ServiceWorkerManager { let (resource_chan, resource_port) = ipc::channel().unwrap(); let SWManagerSenders { - resource_sender, + resource_threads, own_sender, receiver, swmanager_sender: constellation_sender, + system_font_service_sender, + compositor_api, } = sw_senders; let from_constellation = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(receiver); let resource_port = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(resource_port); - let _ = resource_sender.send(CoreResourceMsg::NetworkMediator(resource_chan, origin)); + let _ = resource_threads + .core_thread + .send(CoreResourceMsg::NetworkMediator(resource_chan, origin)); + + let font_context = Arc::new(FontContext::new( + Arc::new(system_font_service_sender.to_proxy()), + compositor_api, + resource_threads, + )); + let swmanager_thread = move || { ServiceWorkerManager::new( own_sender, from_constellation, resource_port, constellation_sender, + font_context, ) .handle_message() }; diff --git a/components/shared/constellation/Cargo.toml b/components/shared/constellation/Cargo.toml index d3b1d25882b..beee88ba3c4 100644 --- a/components/shared/constellation/Cargo.toml +++ b/components/shared/constellation/Cargo.toml @@ -18,9 +18,11 @@ webgpu = ["wgpu-core"] [dependencies] base = { workspace = true } canvas_traits = { workspace = true } +compositing_traits = { workspace = true } devtools_traits = { workspace = true } embedder_traits = { workspace = true } euclid = { workspace = true } +fonts_traits = { workspace = true } http = { workspace = true } hyper_serde = { workspace = true } ipc-channel = { workspace = true } diff --git a/components/shared/constellation/from_script_message.rs b/components/shared/constellation/from_script_message.rs index 1f96d933a93..b71a23e2561 100644 --- a/components/shared/constellation/from_script_message.rs +++ b/components/shared/constellation/from_script_message.rs @@ -13,6 +13,7 @@ use base::id::{ MessagePortRouterId, PipelineId, ServiceWorkerId, ServiceWorkerRegistrationId, WebViewId, }; use canvas_traits::canvas::{CanvasId, CanvasMsg}; +use compositing_traits::CrossProcessCompositorApi; use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId}; use embedder_traits::{ AnimationState, EmbedderMsg, FocusSequenceNumber, JSValue, JavaScriptEvaluationError, @@ -20,6 +21,7 @@ use embedder_traits::{ WebDriverMessageId, }; use euclid::default::Size2D as UntypedSize2D; +use fonts_traits::SystemFontServiceProxySender; use http::{HeaderMap, Method}; use ipc_channel::Error as IpcError; use ipc_channel::ipc::{IpcReceiver, IpcSender}; @@ -27,7 +29,7 @@ use malloc_size_of_derive::MallocSizeOf; use net_traits::policy_container::PolicyContainer; use net_traits::request::{Destination, InsecureRequestsPolicy, Referrer, RequestBody}; use net_traits::storage_thread::StorageType; -use net_traits::{CoreResourceMsg, ReferrerPolicy, ResourceThreads}; +use net_traits::{ReferrerPolicy, ResourceThreads}; use profile_traits::mem::MemoryReportResult; use profile_traits::{mem, time as profile_time}; use serde::{Deserialize, Serialize}; @@ -205,8 +207,12 @@ pub struct DOMMessage { pub struct SWManagerSenders { /// Sender of messages to the constellation. pub swmanager_sender: IpcSender, - /// Sender for communicating with resource thread. - pub resource_sender: IpcSender, + /// [`ResourceThreads`] for initating fetches or using i/o. + pub resource_threads: ResourceThreads, + /// [`CrossProcessCompositorApi`] for communicating with the compositor. + pub compositor_api: CrossProcessCompositorApi, + /// The [`SystemFontServiceProxy`] used to communicate with the `SystemFontService`. + pub system_font_service_sender: SystemFontServiceProxySender, /// Sender of messages to the manager. pub own_sender: IpcSender, /// Receiver of messages from the constellation. diff --git a/components/shared/fonts/Cargo.toml b/components/shared/fonts/Cargo.toml index 3e51d3ce200..be02bf7b7e9 100644 --- a/components/shared/fonts/Cargo.toml +++ b/components/shared/fonts/Cargo.toml @@ -18,6 +18,8 @@ log = { workspace = true } malloc_size_of = { workspace = true } malloc_size_of_derive = { workspace = true } memmap2 = { workspace = true } +parking_lot = { workspace = true } +profile_traits = { workspace = true } range = { path = "../../range" } read-fonts = { workspace = true } serde = { workspace = true } diff --git a/components/shared/fonts/lib.rs b/components/shared/fonts/lib.rs index 9370a3eddda..eb0b9cbee68 100644 --- a/components/shared/fonts/lib.rs +++ b/components/shared/fonts/lib.rs @@ -7,6 +7,7 @@ mod font_descriptor; mod font_identifier; mod font_template; +mod system_font_service_proxy; use std::sync::Arc; @@ -17,6 +18,7 @@ use ipc_channel::ipc::IpcSharedMemory; use malloc_size_of_derive::MallocSizeOf; use range::{RangeIndex, int_range_index}; use serde::{Deserialize, Serialize}; +pub use system_font_service_proxy::*; int_range_index! { #[derive(Deserialize, MallocSizeOf, Serialize)] diff --git a/components/shared/fonts/system_font_service_proxy.rs b/components/shared/fonts/system_font_service_proxy.rs new file mode 100644 index 00000000000..fa5a5e7c730 --- /dev/null +++ b/components/shared/fonts/system_font_service_proxy.rs @@ -0,0 +1,188 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use std::collections::HashMap; + +use ipc_channel::ipc::{self, IpcSender}; +use log::debug; +use malloc_size_of_derive::MallocSizeOf; +use parking_lot::{Mutex, RwLock}; +use profile_traits::mem::ReportsChan; +use serde::{Deserialize, Serialize}; +use style::values::computed::font::SingleFontFamily; +use webrender_api::units::Au; +use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey, FontVariation}; + +use crate::{FontDescriptor, FontIdentifier, FontTemplate, FontTemplateRef}; + +/// Commands that the `FontContext` sends to the `SystemFontService`. +#[derive(Debug, Deserialize, Serialize)] +pub enum SystemFontServiceMessage { + GetFontTemplates( + Option, + SingleFontFamily, + IpcSender>, + ), + GetFontInstance( + FontIdentifier, + Au, + FontInstanceFlags, + Vec, + IpcSender, + ), + GetFontKey(IpcSender), + GetFontInstanceKey(IpcSender), + CollectMemoryReport(ReportsChan), + Exit(IpcSender<()>), + Ping, +} + +#[derive(Clone, Deserialize, Serialize)] +pub struct SystemFontServiceProxySender(pub IpcSender); + +impl SystemFontServiceProxySender { + pub fn to_proxy(&self) -> SystemFontServiceProxy { + SystemFontServiceProxy { + sender: Mutex::new(self.0.clone()), + templates: Default::default(), + } + } +} + +#[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)] +struct FontTemplateCacheKey { + font_descriptor: Option, + family_descriptor: SingleFontFamily, +} + +/// The public interface to the [`SystemFontService`], used by per-Document +/// `FontContext` instances. +#[derive(Debug, MallocSizeOf)] +pub struct SystemFontServiceProxy { + sender: Mutex>, + templates: RwLock>>, +} + +impl SystemFontServiceProxy { + pub fn exit(&self) { + let (response_chan, response_port) = ipc::channel().unwrap(); + self.sender + .lock() + .send(SystemFontServiceMessage::Exit(response_chan)) + .expect("Couldn't send SystemFontService exit message"); + response_port + .recv() + .expect("Couldn't receive SystemFontService reply"); + } + + pub fn to_sender(&self) -> SystemFontServiceProxySender { + SystemFontServiceProxySender(self.sender.lock().clone()) + } + + pub fn get_system_font_instance( + &self, + identifier: FontIdentifier, + size: Au, + flags: FontInstanceFlags, + variations: Vec, + ) -> FontInstanceKey { + let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel"); + self.sender + .lock() + .send(SystemFontServiceMessage::GetFontInstance( + identifier, + size, + flags, + variations, + response_chan, + )) + .expect("failed to send message to system font service"); + + let instance_key = response_port.recv(); + if instance_key.is_err() { + let font_thread_has_closed = self + .sender + .lock() + .send(SystemFontServiceMessage::Ping) + .is_err(); + assert!( + font_thread_has_closed, + "Failed to receive a response from live font cache" + ); + panic!("SystemFontService has already exited."); + } + instance_key.unwrap() + } + + pub fn find_matching_font_templates( + &self, + descriptor_to_match: Option<&FontDescriptor>, + family_descriptor: &SingleFontFamily, + ) -> Vec { + let cache_key = FontTemplateCacheKey { + font_descriptor: descriptor_to_match.cloned(), + family_descriptor: family_descriptor.clone(), + }; + if let Some(templates) = self.templates.read().get(&cache_key).cloned() { + return templates; + } + + debug!( + "SystemFontServiceProxy: cache miss for template_descriptor={:?} family_descriptor={:?}", + descriptor_to_match, family_descriptor + ); + + let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel"); + self.sender + .lock() + .send(SystemFontServiceMessage::GetFontTemplates( + descriptor_to_match.cloned(), + family_descriptor.clone(), + response_chan, + )) + .expect("failed to send message to system font service"); + + let Ok(templates) = response_port.recv() else { + let font_thread_has_closed = self + .sender + .lock() + .send(SystemFontServiceMessage::Ping) + .is_err(); + assert!( + font_thread_has_closed, + "Failed to receive a response from live font cache" + ); + panic!("SystemFontService has already exited."); + }; + + let templates: Vec<_> = templates.into_iter().map(FontTemplateRef::new).collect(); + self.templates.write().insert(cache_key, templates.clone()); + + templates + } + + pub fn generate_font_key(&self) -> FontKey { + let (result_sender, result_receiver) = + ipc::channel().expect("failed to create IPC channel"); + self.sender + .lock() + .send(SystemFontServiceMessage::GetFontKey(result_sender)) + .expect("failed to send message to system font service"); + result_receiver + .recv() + .expect("Failed to communicate with system font service.") + } + + pub fn generate_font_instance_key(&self) -> FontInstanceKey { + let (result_sender, result_receiver) = + ipc::channel().expect("failed to create IPC channel"); + self.sender + .lock() + .send(SystemFontServiceMessage::GetFontInstanceKey(result_sender)) + .expect("failed to send message to system font service"); + result_receiver + .recv() + .expect("Failed to communicate with system font service.") + } +}