font_loader/
fontconfig.rs1pub mod system_fonts {
21 use servo_fontconfig::fontconfig::{FcConfig, FcInitLoadConfigAndFonts, FcNameParse};
22 use servo_fontconfig::fontconfig::{FcPattern, FcPatternCreate, FcPatternDestroy, FcFontMatch};
23 use servo_fontconfig::fontconfig::{FcFontList, FcObjectSetBuild, FcChar8, FcDefaultSubstitute};
24 use servo_fontconfig::fontconfig::{FcPatternGetString, FcPatternAddInteger, FcPatternGetInteger};
25 use servo_fontconfig::fontconfig::{FcResultMatch, FcMatchPattern, FcResultNoMatch, FcConfigSubstitute};
26 use servo_fontconfig::fontconfig::FcPatternAddString;
27
28 use libc::{c_int, c_char};
29
30 use std::ptr;
31 use std::slice;
32 use std::ffi::{CStr, CString};
33 use std::io::prelude::*;
34 use std::fs::File;
35
36 use std::sync::{Once, ONCE_INIT};
37
38 static FC_FAMILY: &'static [u8] = b"family\0";
39 static FC_FILE: &'static [u8] = b"file\0";
40 static FC_WEIGHT: &'static [u8] = b"weight\0";
41 static FC_INDEX: &'static [u8] = b"index\0";
42 static FC_SLANT: &'static [u8] = b"slant\0";
43 static FC_SPACING: &'static [u8] = b"spacing\0";
44 static FC_WEIGHT_REGULAR: c_int = 80;
57 static FC_WEIGHT_BOLD: c_int = 200;
60 static FC_SLANT_ROMAN: c_int = 0;
65 static FC_SLANT_ITALIC: c_int = 100;
66 static FC_SLANT_OBLIQUE: c_int = 110;
67
68 static FC_MONO: c_int = 100;
71 static INIT_FONTCONFIG: Once = ONCE_INIT;
74 static mut CONFIG: *mut FcConfig = 0 as *mut FcConfig;
75
76 fn init() -> *mut FcConfig {
77 unsafe {
78 INIT_FONTCONFIG.call_once(|| {
79 CONFIG = FcInitLoadConfigAndFonts();
80 });
81 CONFIG
82 }
83 }
84
85 pub struct FontProperty {
87 slant: c_int,
88 weight: c_int,
89 family: String,
90 spacing: Option<c_int>,
91 }
92
93 pub struct FontPropertyBuilder {
95 property: FontProperty,
96 }
97
98 impl FontPropertyBuilder {
99 pub fn new() -> FontPropertyBuilder {
100 let property = FontProperty {
101 slant: FC_SLANT_ROMAN,
102 weight: FC_WEIGHT_REGULAR,
103 family: String::new(),
104 spacing: None,
105 };
106 FontPropertyBuilder { property: property }
107 }
108
109 pub fn italic(mut self) -> FontPropertyBuilder {
110 self.property.slant = FC_SLANT_ITALIC;
111 self
112 }
113
114 pub fn oblique(mut self) -> FontPropertyBuilder {
115 self.property.slant = FC_SLANT_OBLIQUE;
116 self
117 }
118
119 pub fn bold(mut self) -> FontPropertyBuilder {
120 self.property.weight = FC_WEIGHT_BOLD;
121 self
122 }
123
124 pub fn monospace(mut self) -> FontPropertyBuilder {
125 self.property.spacing = Some(FC_MONO);
126 self
127 }
128
129 pub fn family(mut self, name: &str) -> FontPropertyBuilder {
130 self.property.family.clear();
131 self.property.family.push_str(name);
132 self
133 }
134
135 pub fn build(self) -> FontProperty {
136 self.property
137 }
138 }
139
140 pub fn get(property: &FontProperty) -> Option<(Vec<u8>, c_int)> {
143 let config = init();
144 let family: &str = &property.family;
145
146 unsafe {
147 let name = CString::new(family).unwrap();
148 let pat = FcNameParse(name.as_ptr() as *const FcChar8);
149 add_int(pat, FC_SLANT, property.slant);
150 add_int(pat, FC_WEIGHT, property.weight);
151 FcConfigSubstitute(config, pat, FcMatchPattern);
152 FcDefaultSubstitute(pat);
153
154 let mut result = FcResultNoMatch;
155 let font_pat = FcFontMatch(config, pat, &mut result);
156
157 if font_pat.is_null() {
158 None
159 } else {
160 let file = get_string(font_pat, FC_FILE).unwrap();
161 let index = get_int(font_pat, FC_INDEX).unwrap();
162 FcPatternDestroy(font_pat);
163 let mut file = File::open(file).unwrap();
164 let mut buf: Vec<u8> = Vec::new();
165 let _ = file.read_to_end(&mut buf);
166 Some((buf, index))
167 }
168 }
169 }
170
171 pub fn query_all() -> Vec<String> {
174 let mut property = FontPropertyBuilder::new().build();
175 query_specific(&mut property)
176 }
177
178 pub fn query_specific(property: &mut FontProperty) -> Vec<String> {
181 let mut fonts: Vec<String> = Vec::new();
182 unsafe {
183 let config = init();
184
185 let pattern = FcPatternCreate();
186 if !property.family.is_empty() {
187 add_string(pattern, FC_FAMILY, &property.family);
188 }
189 property.spacing.map(|spacing| add_int(pattern, FC_SPACING, spacing));
190 add_int(pattern, FC_WEIGHT, property.weight);
191 add_int(pattern, FC_SLANT, property.slant);
192
193 let null_ptr: *const c_char = ptr::null();
194 let o1 = FC_FAMILY.as_ptr() as *mut c_char;
195 let os = FcObjectSetBuild(o1, null_ptr);
196 let fs = FcFontList(config, pattern, os);
197
198 let patterns = slice::from_raw_parts((*fs).fonts, (*fs).nfont as usize);
199 for pat in patterns {
200 let family_name = get_string(*pat, FC_FAMILY).unwrap();
201 fonts.push(family_name);
202 }
203 }
204
205 fonts.sort();
206 fonts.dedup();
207 fonts
208 }
209
210 fn add_int(pat: *mut FcPattern, object_name: &[u8], value: c_int) {
211 let object = object_name.as_ptr() as *const c_char;
212 unsafe {
213 FcPatternAddInteger(pat, object, value);
214 }
215 }
216
217 fn get_int(pat: *mut FcPattern, object_name: &[u8]) -> Result<c_int, &str> {
218 let object = object_name.as_ptr() as *const c_char;
219 unsafe {
220 let mut int: c_int = 0;
221 if FcPatternGetInteger(pat, object, 0, &mut int) == FcResultMatch {
222 Ok(int)
223 } else {
224 Err("Type didn't match")
225 }
226 }
227 }
228
229 fn add_string(pat: *mut FcPattern, object_name: &[u8], value: &str) {
230 let value = CString::new(value).unwrap();
231 let value_ptr = value.as_ptr() as *const FcChar8;
232 let object = object_name.as_ptr() as *const c_char;
233 unsafe {
234 FcPatternAddString(pat, object, value_ptr);
235 }
236 }
237
238 fn get_string(pat: *mut FcPattern, object_name: &[u8]) -> Result<String, &str> {
239 unsafe {
240 let mut string: *mut FcChar8 = ptr::null_mut();
241 let object = object_name.as_ptr() as *const c_char;
242 if FcPatternGetString(pat, object, 0, &mut string) == FcResultMatch {
243 let cstr = CStr::from_ptr(string as *mut c_char);
244 let string = cstr.to_string_lossy().into_owned();
245 Ok(string)
246 } else {
247 Err("Type didn't match")
248 }
249 }
250 }
251}