fonts_traits/
system_font_service_proxy.rs1use std::collections::HashMap;
6
7use base::generic_channel::{self, GenericSender};
8use base::id::PainterId;
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, MallocSizeOf, Serialize)]
22pub enum SystemFontServiceMessage {
23 GetFontTemplates(
24 Option<FontDescriptor>,
25 SingleFontFamily,
26 GenericSender<Vec<FontTemplate>>,
27 ),
28 GetFontInstance(
29 PainterId,
30 FontIdentifier,
31 Au,
32 FontInstanceFlags,
33 Vec<FontVariation>,
34 GenericSender<FontInstanceKey>,
35 ),
36 PrefetchFontKeys(PainterId),
37 GetFontKey(PainterId, GenericSender<FontKey>),
38 GetFontInstanceKey(PainterId, GenericSender<FontInstanceKey>),
39 CollectMemoryReport(ReportsChan),
40 Exit(GenericSender<()>),
41 Ping,
42}
43
44#[derive(Clone, Deserialize, Serialize)]
45pub struct SystemFontServiceProxySender(pub GenericSender<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: GenericSender<SystemFontServiceMessage>,
67 templates: RwLock<HashMap<FontTemplateCacheKey, Vec<FontTemplateRef>>>,
68}
69
70impl SystemFontServiceProxy {
71 pub fn exit(&self) {
72 let (response_chan, response_port) = generic_channel::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) =
94 generic_channel::channel().expect("failed to create IPC channel");
95 self.sender
96 .send(SystemFontServiceMessage::GetFontInstance(
97 painter_id,
98 identifier,
99 size,
100 flags,
101 variations,
102 response_chan,
103 ))
104 .expect("failed to send message to system font service");
105
106 let instance_key = response_port.recv();
107 if instance_key.is_err() {
108 let font_thread_has_closed = self.sender.send(SystemFontServiceMessage::Ping).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) =
137 generic_channel::channel().expect("failed to create IPC channel");
138 self.sender
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.sender.send(SystemFontServiceMessage::Ping).is_err();
148 assert!(
149 font_thread_has_closed,
150 "Failed to receive a response from live font cache"
151 );
152 panic!("SystemFontService has already exited.");
153 };
154
155 let templates: Vec<_> = templates.into_iter().map(FontTemplateRef::new).collect();
156 self.templates.write().insert(cache_key, templates.clone());
157
158 templates
159 }
160
161 pub fn generate_font_key(&self, painter_id: PainterId) -> FontKey {
162 let (result_sender, result_receiver) =
163 generic_channel::channel().expect("failed to create IPC channel");
164 self.sender
165 .send(SystemFontServiceMessage::GetFontKey(
166 painter_id,
167 result_sender,
168 ))
169 .expect("failed to send message to system font service");
170 result_receiver
171 .recv()
172 .expect("Failed to communicate with system font service.")
173 }
174
175 pub fn generate_font_instance_key(&self, painter_id: PainterId) -> FontInstanceKey {
176 let (result_sender, result_receiver) =
177 generic_channel::channel().expect("failed to create IPC channel");
178 self.sender
179 .send(SystemFontServiceMessage::GetFontInstanceKey(
180 painter_id,
181 result_sender,
182 ))
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
189 pub fn prefetch_font_keys_for_painter(&self, painter_id: PainterId) {
190 let _ = self
191 .sender
192 .send(SystemFontServiceMessage::PrefetchFontKeys(painter_id));
193 }
194}