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 variation_index: i32,
45 }
46
47 impl LocalFontIdentifier {
48 pub fn index(&self) -> u32 {
49 self.variation_index.try_into().unwrap()
50 }
51
52 pub fn native_font_handle(&self) -> NativeFontHandle {
53 NativeFontHandle {
54 path: PathBuf::from(&*self.path),
55 index: self.variation_index as u32,
56 }
57 }
58
59 #[allow(unsafe_code)]
60 pub fn font_data_and_index(&self) -> Option<FontDataAndIndex> {
61 let file = File::open(Path::new(&*self.path)).ok()?;
62 let mmap = unsafe { Mmap::map(&file).ok()? };
63 let data = FontData::from_bytes(&mmap);
64
65 Some(FontDataAndIndex {
66 data,
67 index: self.variation_index as u32,
68 })
69 }
70 }
71}
72
73#[cfg(target_os = "macos")]
74mod platform {
75 use std::fs::File;
76 use std::path::Path;
77
78 use log::warn;
79 use malloc_size_of_derive::MallocSizeOf;
80 use memmap2::Mmap;
81 use read_fonts::types::NameId;
82 use read_fonts::{FileRef, TableProvider};
83 use serde::{Deserialize, Serialize};
84 use style::Atom;
85 use webrender_api::NativeFontHandle;
86
87 use crate::{FontData, FontDataAndIndex};
88
89 #[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
93 pub struct LocalFontIdentifier {
94 pub postscript_name: Atom,
95 pub path: Atom,
96 }
97
98 impl LocalFontIdentifier {
99 pub fn native_font_handle(&self) -> NativeFontHandle {
100 NativeFontHandle {
101 name: self.postscript_name.to_string(),
102 path: self.path.to_string(),
103 }
104 }
105
106 pub(crate) fn index(&self) -> u32 {
107 0
108 }
109
110 #[allow(unsafe_code)]
111 pub fn font_data_and_index(&self) -> Option<FontDataAndIndex> {
112 let file = File::open(Path::new(&*self.path)).ok()?;
113 let mmap = unsafe { Mmap::map(&file).ok()? };
114
115 let file_ref = FileRef::new(mmap.as_ref()).ok()?;
117 let index = ttc_index_from_postscript_name(file_ref, &self.postscript_name);
118
119 Some(FontDataAndIndex {
120 data: FontData::from_bytes(&mmap),
121 index,
122 })
123 }
124 }
125
126 fn ttc_index_from_postscript_name(font_file: FileRef<'_>, postscript_name: &str) -> u32 {
134 match font_file {
135 FileRef::Font(_) => 0,
137 FileRef::Collection(collection) => {
140 for i in 0..collection.len() {
141 let font = collection.get(i).unwrap();
142 let name_table = font.name().unwrap();
143 if name_table
144 .name_record()
145 .iter()
146 .filter(|record| record.name_id() == NameId::POSTSCRIPT_NAME)
147 .any(|record| {
148 record
149 .string(name_table.string_data())
150 .unwrap()
151 .chars()
152 .eq(postscript_name.chars())
153 })
154 {
155 return i;
156 }
157 }
158
159 warn!(
161 "Font with postscript_name {} not found in collection",
162 postscript_name
163 );
164 0
165 },
166 }
167 }
168}
169
170#[cfg(target_os = "windows")]
171mod platform {
172 use std::hash::Hash;
173 use std::sync::Arc;
174
175 use dwrote::{FontCollection, FontDescriptor};
176 use malloc_size_of_derive::MallocSizeOf;
177 use serde::{Deserialize, Serialize};
178 use webrender_api::NativeFontHandle;
179
180 use crate::{FontData, FontDataAndIndex};
181
182 #[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
184 pub struct LocalFontIdentifier {
185 #[ignore_malloc_size_of = "dwrote does not support MallocSizeOf"]
187 pub font_descriptor: Arc<FontDescriptor>,
188 }
189
190 impl LocalFontIdentifier {
191 pub fn index(&self) -> u32 {
192 FontCollection::system()
193 .font_from_descriptor(&self.font_descriptor)
194 .ok()
195 .flatten()
196 .map_or(0, |font| font.create_font_face().get_index())
197 }
198
199 pub fn native_font_handle(&self) -> NativeFontHandle {
200 let face = FontCollection::system()
201 .font_from_descriptor(&self.font_descriptor)
202 .ok()
203 .flatten()
204 .expect("Could not create Font from FontDescriptor")
205 .create_font_face();
206 let path = face
207 .files()
208 .ok()
209 .and_then(|files| files.first().cloned())
210 .expect("Could not get FontFace files")
211 .font_file_path()
212 .ok()
213 .expect("Could not get FontFace files path");
214 NativeFontHandle {
215 path,
216 index: face.get_index(),
217 }
218 }
219
220 pub fn font_data_and_index(&self) -> Option<FontDataAndIndex> {
221 let font = FontCollection::system()
222 .font_from_descriptor(&self.font_descriptor)
223 .ok()??;
224 let face = font.create_font_face();
225 let index = face.get_index();
226 let files = face.files().ok()?;
227 assert!(!files.is_empty());
228
229 let data = files[0].font_file_bytes().ok()?;
230 let data = FontData::from_bytes(&data);
231
232 Some(FontDataAndIndex { data, index })
233 }
234 }
235
236 impl Eq for LocalFontIdentifier {}
237
238 impl Hash for LocalFontIdentifier {
239 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
240 self.font_descriptor.family_name.hash(state);
241 self.font_descriptor.weight.to_u32().hash(state);
242 self.font_descriptor.stretch.to_u32().hash(state);
243 self.font_descriptor.style.to_u32().hash(state);
244 }
245 }
246}