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