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