1pub mod system_fonts {
21 use winapi::um::wingdi;
22 use winapi::um::wingdi::TEXTMETRICW;
23 use winapi::ctypes::{c_int, c_void};
24 use winapi::um::winnt::{PVOID};
25 use winapi::um::wingdi::FIXED_PITCH;
26 use winapi::um::wingdi::{ENUMLOGFONTEXW, LOGFONTW, OUT_TT_ONLY_PRECIS};
27 use winapi::um::wingdi::FONTENUMPROCW;
28 use winapi::shared::minwindef::{DWORD, LPARAM};
29
30 use std::ptr;
31 use std::mem;
32 use std::ffi::{OsStr, OsString};
33 use std::os::windows::ffi::{OsStrExt, OsStringExt};
34
35 pub type FontProperty = LOGFONTW;
37
38 pub struct FontPropertyBuilder {
40 config: FontProperty,
41 }
42
43 impl FontPropertyBuilder {
44 pub fn new() -> FontPropertyBuilder {
45 let string: [u16; 32] = [0; 32];
46 FontPropertyBuilder {
47 config: FontProperty {
48 lfHeight: 0,
49 lfWidth: 0,
50 lfEscapement: 0,
51 lfOrientation: 0,
52 lfWeight: 0,
53 lfItalic: 0,
54 lfUnderline: 0,
55 lfStrikeOut: 0,
56 lfCharSet: 0,
57 lfOutPrecision: OUT_TT_ONLY_PRECIS as u8,
58 lfClipPrecision: 0,
59 lfQuality: 0,
60 lfPitchAndFamily: 0,
61 lfFaceName: string,
62 },
63 }
64 }
65
66 pub fn italic(mut self) -> FontPropertyBuilder {
67 self.config.lfItalic = true as u8;
68 self
69 }
70
71 pub fn oblique(self) -> FontPropertyBuilder {
72 self.italic()
73 }
74
75 pub fn monospace(mut self) -> FontPropertyBuilder {
76 self.config.lfPitchAndFamily |= FIXED_PITCH as u8;
77 self
78 }
79
80 pub fn bold(mut self) -> FontPropertyBuilder {
81 self.config.lfWeight = 700;
82 self
83 }
84
85 pub fn family(mut self, name: &str) -> FontPropertyBuilder {
86 if name.len() > 31 {
87 panic!("Font length must me smaller than 31");
88 }
89 let name: &OsStr = name.as_ref();
90 let buffer = name.encode_wide();
91 let mut string: [u16; 32] = [0; 32]; for (index, item) in buffer.enumerate() {
93 string[index] = item;
94 }
95 self.config.lfFaceName = string;
96 self
97 }
98
99 pub fn build(self) -> FontProperty {
100 self.config
101 }
102 }
103
104 pub fn get(config: &FontProperty) -> Option<(Vec<u8>, c_int)> {
107 unsafe {
108 let hdc = wingdi::CreateCompatibleDC(ptr::null_mut());
109 let hfont = wingdi::CreateFontIndirectW(config as *const LOGFONTW);
110 wingdi::SelectObject(hdc, hfont as *mut c_void);
111 let size = wingdi::GetFontData(hdc, 0, 0, ptr::null_mut(), 0);
112 if size == 0xFFFFFFFF {
113 wingdi::DeleteDC(hdc);
114 None
115 } else if size > 0 {
116 let mut buffer: Vec<u8> = vec![0; size as usize];
117 let pointer = buffer.first_mut().unwrap() as *mut _ as PVOID;
118 let size = wingdi::GetFontData(hdc, 0, 0, pointer, size);
119 buffer.set_len(size as usize);
120 wingdi::DeleteDC(hdc);
121 Some((buffer, 0))
122 } else {
123 wingdi::DeleteDC(hdc);
124 None
125 }
126 }
127 }
128
129 pub fn get_native(config: &mut FontProperty) -> FontProperty {
130 let f: FONTENUMPROCW = Some(callback_native);
131 unsafe {
132 let mut logfont: LOGFONTW = mem::zeroed();
133 let pointer = &mut logfont as *mut _;
134 let hdc = wingdi::CreateCompatibleDC(ptr::null_mut());
135 wingdi::EnumFontFamiliesExW(hdc, config, f, pointer as LPARAM, 0);
136 wingdi::DeleteDC(hdc);
137 logfont
138 }
139 }
140
141 pub fn query_all() -> Vec<String> {
144 let mut config = FontPropertyBuilder::new().build();
145 query_specific(&mut config)
146 }
147
148 pub fn query_specific(property: &mut FontProperty) -> Vec<String> {
151
152 let mut fonts = Vec::new();
153 let mut f: FONTENUMPROCW = Some(callback_ttf);
154 unsafe {
155 let hdc = wingdi::CreateCompatibleDC(ptr::null_mut());
156
157 if (property.lfPitchAndFamily & FIXED_PITCH as u8) != 0 {
158 f = Some(callback_monospace);
159 }
160
161 let vec_pointer = &mut fonts as *mut Vec<String>;
162
163 wingdi::EnumFontFamiliesExW(hdc, property, f, vec_pointer as LPARAM, 0);
164 wingdi::DeleteDC(hdc);
165 }
166 fonts
167 }
168
169 #[allow(non_snake_case)]
170 unsafe extern "system" fn callback_ttf(lpelfe: *const LOGFONTW,
171 _: *const TEXTMETRICW,
172 fonttype: DWORD,
173 lparam: LPARAM)
174 -> c_int {
175
176 if fonttype != 4 {
177 return 1;
178 }
179
180 add_vec(lpelfe, lparam);
181
182 1
183 }
184
185 #[allow(non_snake_case)]
186 unsafe extern "system" fn callback_monospace(lpelfe: *const LOGFONTW,
187 _: *const TEXTMETRICW,
188 fonttype: DWORD,
189 lparam: LPARAM)
190 -> c_int {
191 if fonttype != 4 {
192 return 1;
193 }
194
195 if ((*lpelfe).lfPitchAndFamily & FIXED_PITCH as u8) == 0 {
196 return 1;
197 }
198 add_vec(lpelfe, lparam);
199
200 1
201 }
202
203 unsafe fn add_vec(lpelfe: *const LOGFONTW, lparam: LPARAM) {
204 let lpelfe = lpelfe as *const ENUMLOGFONTEXW;
205
206 let name_array = (*lpelfe).elfFullName;
207 let pos = name_array.iter().position(|c| *c == 0).unwrap();
208 let name_array = &name_array[0..pos];
209
210 let name = OsString::from_wide(name_array).into_string().unwrap();
211
212 if name.chars().next() != Some('@') {
213 let vec_pointer = lparam as *mut Vec<String>;
214 let ref mut fonts = *vec_pointer;
215 fonts.push(name);
216 }
217 }
218
219 #[allow(non_snake_case)]
220 unsafe extern "system" fn callback_native(lpelfe: *const LOGFONTW,
221 _: *const TEXTMETRICW,
222 fonttype: DWORD,
223 lparam: LPARAM)
224 -> c_int {
225
226 if fonttype != 4 {
227 return 1;
228 }
229
230 ptr::copy(lpelfe, lparam as *mut _, 1);
231
232 0
233 }
234
235}