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