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