/
font_list.rs
143 lines (121 loc) · 5.3 KB
/
font_list.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use fontconfig::fontconfig::{FcChar8, FcResultMatch, FcSetSystem};
use fontconfig::fontconfig::{FcConfigGetCurrent, FcConfigGetFonts, FcConfigSubstitute};
use fontconfig::fontconfig::{FcDefaultSubstitute, FcFontMatch, FcNameParse, FcPatternGetString};
use fontconfig::fontconfig::{FcFontSetDestroy, FcMatchPattern, FcPatternCreate, FcPatternDestroy};
use fontconfig::fontconfig::{FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy, FcPatternAddString};
use fontconfig::fontconfig::{FcObjectSetAdd, FcPatternGetInteger};
use libc;
use libc::{c_char, c_int};
use std::borrow::ToOwned;
use std::ffi::CString;
use std::ptr;
use super::c_str_to_string;
static FC_FAMILY: &'static [u8] = b"family\0";
static FC_FILE: &'static [u8] = b"file\0";
static FC_INDEX: &'static [u8] = b"index\0";
static FC_FONTFORMAT: &'static [u8] = b"fontformat\0";
pub fn for_each_available_family<F>(mut callback: F) where F: FnMut(String) {
unsafe {
let config = FcConfigGetCurrent();
let font_set = FcConfigGetFonts(config, FcSetSystem);
for i in 0..((*font_set).nfont as isize) {
let font = (*font_set).fonts.offset(i);
let mut family: *mut FcChar8 = ptr::null_mut();
let mut format: *mut FcChar8 = ptr::null_mut();
let mut v: c_int = 0;
if FcPatternGetString(*font, FC_FONTFORMAT.as_ptr() as *mut c_char, v, &mut format) != FcResultMatch {
continue;
}
// Skip bitmap fonts. They aren't supported by FreeType.
let fontformat = c_str_to_string(format as *const c_char);
if fontformat != "TrueType" &&
fontformat != "CFF" &&
fontformat != "Type 1" {
continue;
}
while FcPatternGetString(*font, FC_FAMILY.as_ptr() as *mut c_char, v, &mut family) == FcResultMatch {
let family_name = c_str_to_string(family as *const c_char);
callback(family_name);
v += 1;
}
}
}
}
pub fn for_each_variation<F>(family_name: &str, mut callback: F)
where F: FnMut(String)
{
debug!("getting variations for {}", family_name);
unsafe {
let config = FcConfigGetCurrent();
let mut font_set = FcConfigGetFonts(config, FcSetSystem);
let font_set_array_ptr = &mut font_set;
let pattern = FcPatternCreate();
assert!(!pattern.is_null());
let family_name_c = CString::new(family_name).unwrap();
let family_name = family_name_c.as_ptr();
let ok = FcPatternAddString(pattern, FC_FAMILY.as_ptr() as *mut c_char, family_name as *mut FcChar8);
assert!(ok != 0);
let object_set = FcObjectSetCreate();
assert!(!object_set.is_null());
FcObjectSetAdd(object_set, FC_FILE.as_ptr() as *mut c_char);
FcObjectSetAdd(object_set, FC_INDEX.as_ptr() as *mut c_char);
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
debug!("found {} variations", (*matches).nfont);
for i in 0..((*matches).nfont as isize) {
let font = (*matches).fonts.offset(i);
let mut file: *mut FcChar8 = ptr::null_mut();
let result = FcPatternGetString(*font, FC_FILE.as_ptr() as *mut c_char, 0, &mut file);
let file = if result == FcResultMatch {
c_str_to_string(file as *const c_char)
} else {
panic!();
};
let mut index: libc::c_int = 0;
let result = FcPatternGetInteger(*font, FC_INDEX.as_ptr() as *mut c_char, 0, &mut index);
let index = if result == FcResultMatch {
index
} else {
panic!();
};
debug!("variation file: {}", file);
debug!("variation index: {}", index);
callback(file);
}
FcFontSetDestroy(matches);
FcPatternDestroy(pattern);
FcObjectSetDestroy(object_set);
}
}
pub fn system_default_family(generic_name: &str) -> Option<String> {
let generic_name_c = CString::new(generic_name).unwrap();
let generic_name_ptr = generic_name_c.as_ptr();
unsafe {
let pattern = FcNameParse(generic_name_ptr as *mut FcChar8);
FcConfigSubstitute(ptr::null_mut(), pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);
let mut result = 0;
let family_match = FcFontMatch(ptr::null_mut(), pattern, &mut result);
let family_name = if result == FcResultMatch {
let mut match_string: *mut FcChar8 = ptr::null_mut();
FcPatternGetString(family_match, FC_FAMILY.as_ptr() as *mut c_char, 0, &mut match_string);
let result = c_str_to_string(match_string as *const c_char);
FcPatternDestroy(family_match);
Some(result)
} else {
None
};
FcPatternDestroy(pattern);
family_name
}
}
pub fn last_resort_font_families() -> Vec<String> {
vec!(
"Fira Sans".to_owned(),
"DejaVu Sans".to_owned(),
"Arial".to_owned()
)
}
pub static SANS_SERIF_FONT_FAMILY: &'static str = "DejaVu Sans";