fonts_traits/
font_identifier.rs1use malloc_size_of_derive::MallocSizeOf;
6pub use platform::LocalFontIdentifier;
7use serde::{Deserialize, Serialize};
8use servo_url::ServoUrl;
9use uuid::Uuid;
10
11#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
12pub enum FontIdentifier {
13 Local(LocalFontIdentifier),
14 Web(ServoUrl),
15 ArrayBuffer(Uuid),
16}
17
18impl FontIdentifier {
19 pub fn index(&self) -> u32 {
20 match *self {
21 Self::Local(ref local_font_identifier) => local_font_identifier.index(),
22 Self::Web(_) | Self::ArrayBuffer(_) => 0,
23 }
24 }
25}
26
27#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
28mod platform {
29 use std::fs::File;
30 use std::path::{Path, PathBuf};
31
32 use malloc_size_of_derive::MallocSizeOf;
33 use memmap2::Mmap;
34 use serde::{Deserialize, Serialize};
35 use style::Atom;
36 use webrender_api::NativeFontHandle;
37
38 use crate::{FontData, FontDataAndIndex};
39
40 #[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
42 pub struct LocalFontIdentifier {
43 pub path: Atom,
45 pub face_index: u16,
47 pub named_instance_index: u16,
51 }
52
53 impl LocalFontIdentifier {
54 pub fn index(&self) -> u32 {
55 self.face_index as u32
56 }
57
58 pub fn named_instance_index(&self) -> u32 {
59 self.named_instance_index as u32
60 }
61
62 pub fn native_font_handle(&self) -> NativeFontHandle {
63 NativeFontHandle {
64 path: PathBuf::from(&*self.path),
65 index: self.face_index as u32,
66 }
67 }
68
69 #[expect(unsafe_code)]
70 pub fn font_data_and_index(&self) -> Option<FontDataAndIndex> {
71 let file = File::open(Path::new(&*self.path)).ok()?;
72 let mmap = unsafe { Mmap::map(&file).ok()? };
73 let data = FontData::from_bytes(&mmap);
74
75 Some(FontDataAndIndex {
76 data,
77 index: self.face_index as u32,
78 })
79 }
80
81 pub fn face_index_for_freetype(&self) -> u32 {
89 ((self.named_instance_index()) << 16) | self.index()
90 }
91 }
92}
93
94#[cfg(target_os = "macos")]
95mod platform {
96 use std::fs::File;
97 use std::path::Path;
98
99 use log::warn;
100 use malloc_size_of_derive::MallocSizeOf;
101 use memmap2::Mmap;
102 use read_fonts::types::NameId;
103 use read_fonts::{FileRef, TableProvider};
104 use serde::{Deserialize, Serialize};
105 use style::Atom;
106 use webrender_api::NativeFontHandle;
107
108 use crate::{FontData, FontDataAndIndex};
109
110 #[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
114 pub struct LocalFontIdentifier {
115 pub postscript_name: Atom,
116 pub path: Atom,
117 }
118
119 impl LocalFontIdentifier {
120 pub fn native_font_handle(&self) -> NativeFontHandle {
121 NativeFontHandle {
122 name: self.postscript_name.to_string(),
123 path: self.path.to_string(),
124 }
125 }
126
127 pub(crate) fn index(&self) -> u32 {
128 0
129 }
130
131 #[expect(unsafe_code)]
132 pub fn font_data_and_index(&self) -> Option<FontDataAndIndex> {
133 let file = File::open(Path::new(&*self.path)).ok()?;
134 let mmap = unsafe { Mmap::map(&file).ok()? };
135
136 let file_ref = FileRef::new(mmap.as_ref()).ok()?;
138 let index = ttc_index_from_postscript_name(file_ref, &self.postscript_name);
139
140 Some(FontDataAndIndex {
141 data: FontData::from_bytes(&mmap),
142 index,
143 })
144 }
145 }
146
147 fn ttc_index_from_postscript_name(font_file: FileRef<'_>, postscript_name: &str) -> u32 {
155 match font_file {
156 FileRef::Font(_) => 0,
158 FileRef::Collection(collection) => {
161 for i in 0..collection.len() {
162 let font = collection.get(i).unwrap();
163 let name_table = font.name().unwrap();
164 if name_table
165 .name_record()
166 .iter()
167 .filter(|record| record.name_id() == NameId::POSTSCRIPT_NAME)
168 .any(|record| {
169 record
170 .string(name_table.string_data())
171 .unwrap()
172 .chars()
173 .eq(postscript_name.chars())
174 })
175 {
176 return i;
177 }
178 }
179
180 warn!(
182 "Font with postscript_name {} not found in collection",
183 postscript_name
184 );
185 0
186 },
187 }
188 }
189}
190
191#[cfg(target_os = "windows")]
192mod platform {
193 use std::hash::Hash;
194 use std::sync::Arc;
195
196 use dwrote::{FontCollection, FontDescriptor};
197 use malloc_size_of_derive::MallocSizeOf;
198 use serde::{Deserialize, Serialize};
199 use webrender_api::NativeFontHandle;
200
201 use crate::{FontData, FontDataAndIndex};
202
203 #[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
205 pub struct LocalFontIdentifier {
206 #[ignore_malloc_size_of = "dwrote does not support MallocSizeOf"]
208 pub font_descriptor: Arc<FontDescriptor>,
209 }
210
211 impl LocalFontIdentifier {
212 pub fn index(&self) -> u32 {
213 FontCollection::system()
214 .font_from_descriptor(&self.font_descriptor)
215 .ok()
216 .flatten()
217 .map_or(0, |font| font.create_font_face().get_index())
218 }
219
220 pub fn native_font_handle(&self) -> NativeFontHandle {
221 let face = FontCollection::system()
222 .font_from_descriptor(&self.font_descriptor)
223 .ok()
224 .flatten()
225 .expect("Could not create Font from FontDescriptor")
226 .create_font_face();
227 let path = face
228 .files()
229 .ok()
230 .and_then(|files| files.first().cloned())
231 .expect("Could not get FontFace files")
232 .font_file_path()
233 .ok()
234 .expect("Could not get FontFace files path");
235 NativeFontHandle {
236 path,
237 index: face.get_index(),
238 }
239 }
240
241 pub fn font_data_and_index(&self) -> Option<FontDataAndIndex> {
242 let font = FontCollection::system()
243 .font_from_descriptor(&self.font_descriptor)
244 .ok()??;
245 let face = font.create_font_face();
246 let index = face.get_index();
247 let files = face.files().ok()?;
248 assert!(!files.is_empty());
249
250 let data = files[0].font_file_bytes().ok()?;
251 let data = FontData::from_bytes(&data);
252
253 Some(FontDataAndIndex { data, index })
254 }
255 }
256
257 impl Eq for LocalFontIdentifier {}
258
259 impl Hash for LocalFontIdentifier {
260 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
261 self.font_descriptor.family_name.hash(state);
262 self.font_descriptor.weight.to_u32().hash(state);
263 self.font_descriptor.stretch.to_u32().hash(state);
264 self.font_descriptor.style.to_u32().hash(state);
265 }
266 }
267}