fonts_traits/
system_font_service_proxy.rs1use std::collections::HashMap;
6
7use ipc_channel::ipc::{self, IpcSender};
8use log::debug;
9use malloc_size_of_derive::MallocSizeOf;
10use parking_lot::{Mutex, RwLock};
11use profile_traits::mem::ReportsChan;
12use serde::{Deserialize, Serialize};
13use style::values::computed::font::SingleFontFamily;
14use webrender_api::units::Au;
15use webrender_api::{FontInstanceFlags, FontInstanceKey, FontKey, FontVariation};
16
17use crate::{FontDescriptor, FontIdentifier, FontTemplate, FontTemplateRef};
18
19#[derive(Debug, Deserialize, Serialize)]
21pub enum SystemFontServiceMessage {
22 GetFontTemplates(
23 Option<FontDescriptor>,
24 SingleFontFamily,
25 IpcSender<Vec<FontTemplate>>,
26 ),
27 GetFontInstance(
28 FontIdentifier,
29 Au,
30 FontInstanceFlags,
31 Vec<FontVariation>,
32 IpcSender<FontInstanceKey>,
33 ),
34 GetFontKey(IpcSender<FontKey>),
35 GetFontInstanceKey(IpcSender<FontInstanceKey>),
36 CollectMemoryReport(ReportsChan),
37 Exit(IpcSender<()>),
38 Ping,
39}
40
41#[derive(Clone, Deserialize, Serialize)]
42pub struct SystemFontServiceProxySender(pub IpcSender<SystemFontServiceMessage>);
43
44impl SystemFontServiceProxySender {
45 pub fn to_proxy(&self) -> SystemFontServiceProxy {
46 SystemFontServiceProxy {
47 sender: Mutex::new(self.0.clone()),
48 templates: Default::default(),
49 }
50 }
51}
52
53#[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)]
54struct FontTemplateCacheKey {
55 font_descriptor: Option<FontDescriptor>,
56 family_descriptor: SingleFontFamily,
57}
58
59#[derive(Debug, MallocSizeOf)]
62pub struct SystemFontServiceProxy {
63 sender: Mutex<IpcSender<SystemFontServiceMessage>>,
64 templates: RwLock<HashMap<FontTemplateCacheKey, Vec<FontTemplateRef>>>,
65}
66
67impl SystemFontServiceProxy {
68 pub fn exit(&self) {
69 let (response_chan, response_port) = ipc::channel().unwrap();
70 self.sender
71 .lock()
72 .send(SystemFontServiceMessage::Exit(response_chan))
73 .expect("Couldn't send SystemFontService exit message");
74 response_port
75 .recv()
76 .expect("Couldn't receive SystemFontService reply");
77 }
78
79 pub fn to_sender(&self) -> SystemFontServiceProxySender {
80 SystemFontServiceProxySender(self.sender.lock().clone())
81 }
82
83 pub fn get_system_font_instance(
84 &self,
85 identifier: FontIdentifier,
86 size: Au,
87 flags: FontInstanceFlags,
88 variations: Vec<FontVariation>,
89 ) -> FontInstanceKey {
90 let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel");
91 self.sender
92 .lock()
93 .send(SystemFontServiceMessage::GetFontInstance(
94 identifier,
95 size,
96 flags,
97 variations,
98 response_chan,
99 ))
100 .expect("failed to send message to system font service");
101
102 let instance_key = response_port.recv();
103 if instance_key.is_err() {
104 let font_thread_has_closed = self
105 .sender
106 .lock()
107 .send(SystemFontServiceMessage::Ping)
108 .is_err();
109 assert!(
110 font_thread_has_closed,
111 "Failed to receive a response from live font cache"
112 );
113 panic!("SystemFontService has already exited.");
114 }
115 instance_key.unwrap()
116 }
117
118 pub fn find_matching_font_templates(
119 &self,
120 descriptor_to_match: Option<&FontDescriptor>,
121 family_descriptor: &SingleFontFamily,
122 ) -> Vec<FontTemplateRef> {
123 let cache_key = FontTemplateCacheKey {
124 font_descriptor: descriptor_to_match.cloned(),
125 family_descriptor: family_descriptor.clone(),
126 };
127 if let Some(templates) = self.templates.read().get(&cache_key).cloned() {
128 return templates;
129 }
130
131 debug!(
132 "SystemFontServiceProxy: cache miss for template_descriptor={:?} family_descriptor={:?}",
133 descriptor_to_match, family_descriptor
134 );
135
136 let (response_chan, response_port) = ipc::channel().expect("failed to create IPC channel");
137 self.sender
138 .lock()
139 .send(SystemFontServiceMessage::GetFontTemplates(
140 descriptor_to_match.cloned(),
141 family_descriptor.clone(),
142 response_chan,
143 ))
144 .expect("failed to send message to system font service");
145
146 let Ok(templates) = response_port.recv() else {
147 let font_thread_has_closed = self
148 .sender
149 .lock()
150 .send(SystemFontServiceMessage::Ping)
151 .is_err();
152 assert!(
153 font_thread_has_closed,
154 "Failed to receive a response from live font cache"
155 );
156 panic!("SystemFontService has already exited.");
157 };
158
159 let templates: Vec<_> = templates.into_iter().map(FontTemplateRef::new).collect();
160 self.templates.write().insert(cache_key, templates.clone());
161
162 templates
163 }
164
165 pub fn generate_font_key(&self) -> FontKey {
166 let (result_sender, result_receiver) =
167 ipc::channel().expect("failed to create IPC channel");
168 self.sender
169 .lock()
170 .send(SystemFontServiceMessage::GetFontKey(result_sender))
171 .expect("failed to send message to system font service");
172 result_receiver
173 .recv()
174 .expect("Failed to communicate with system font service.")
175 }
176
177 pub fn generate_font_instance_key(&self) -> FontInstanceKey {
178 let (result_sender, result_receiver) =
179 ipc::channel().expect("failed to create IPC channel");
180 self.sender
181 .lock()
182 .send(SystemFontServiceMessage::GetFontInstanceKey(result_sender))
183 .expect("failed to send message to system font service");
184 result_receiver
185 .recv()
186 .expect("Failed to communicate with system font service.")
187 }
188}