plotters_font_loader/
win32.rs1pub 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, FF_ROMAN, FF_SWISS};
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 return self;
88 }
89
90 match name {
91 "serif" => {
92 self.config.lfPitchAndFamily |= FF_ROMAN as u8;
93 }
94 "serif-sans" => {
95 self.config.lfPitchAndFamily |= FF_SWISS as u8;
96 }
97 "monospace" => {
98 self.config.lfPitchAndFamily |= FIXED_PITCH as u8;
99 }
100 _ => {
101 let name: &OsStr = name.as_ref();
102 let buffer = name.encode_wide();
103 let mut string: [u16; 32] = [0; 32]; for (index, item) in buffer.enumerate() {
105 string[index] = item;
106 }
107 self.config.lfFaceName = string;
108 }
109 }
110 self
111 }
112
113 pub fn build(self) -> FontProperty {
114 self.config
115 }
116 }
117
118 pub fn get(config: &FontProperty) -> Option<(Vec<u8>, c_int)> {
121 unsafe {
122 let hdc = wingdi::CreateCompatibleDC(ptr::null_mut());
123 let hfont = wingdi::CreateFontIndirectW(config as *const LOGFONTW);
124 wingdi::SelectObject(hdc, hfont as *mut c_void);
125 let size = wingdi::GetFontData(hdc, 0, 0, ptr::null_mut(), 0);
126 if size == 0xFFFFFFFF {
127 wingdi::DeleteDC(hdc);
128 None
129 } else if size > 0 {
130 let mut buffer: Vec<u8> = vec![0; size as usize];
131 let pointer = buffer.first_mut().unwrap() as *mut _ as PVOID;
132 let size = wingdi::GetFontData(hdc, 0, 0, pointer, size);
133 buffer.set_len(size as usize);
134 wingdi::DeleteDC(hdc);
135 Some((buffer, 0))
136 } else {
137 wingdi::DeleteDC(hdc);
138 None
139 }
140 }
141 }
142
143 pub fn get_native(config: &mut FontProperty) -> FontProperty {
144 let f: FONTENUMPROCW = Some(callback_native);
145 unsafe {
146 let mut logfont: LOGFONTW = mem::zeroed();
147 let pointer = &mut logfont as *mut _;
148 let hdc = wingdi::CreateCompatibleDC(ptr::null_mut());
149 wingdi::EnumFontFamiliesExW(hdc, config, f, pointer as LPARAM, 0);
150 wingdi::DeleteDC(hdc);
151 logfont
152 }
153 }
154
155 pub fn query_all() -> Vec<String> {
158 let mut config = FontPropertyBuilder::new().build();
159 query_specific(&mut config)
160 }
161
162 pub fn query_specific(property: &mut FontProperty) -> Vec<String> {
165
166 let mut fonts = Vec::new();
167 let mut f: FONTENUMPROCW = Some(callback_ttf);
168 unsafe {
169 let hdc = wingdi::CreateCompatibleDC(ptr::null_mut());
170
171 if (property.lfPitchAndFamily & FIXED_PITCH as u8) != 0 {
172 f = Some(callback_monospace);
173 }
174
175 let vec_pointer = &mut fonts as *mut Vec<String>;
176
177 wingdi::EnumFontFamiliesExW(hdc, property, f, vec_pointer as LPARAM, 0);
178 wingdi::DeleteDC(hdc);
179 }
180 fonts
181 }
182
183 #[allow(non_snake_case)]
184 unsafe extern "system" fn callback_ttf(lpelfe: *const LOGFONTW,
185 _: *const TEXTMETRICW,
186 fonttype: DWORD,
187 lparam: LPARAM)
188 -> c_int {
189
190 if fonttype != 4 {
191 return 1;
192 }
193
194 add_vec(lpelfe, lparam);
195
196 1
197 }
198
199 #[allow(non_snake_case)]
200 unsafe extern "system" fn callback_monospace(lpelfe: *const LOGFONTW,
201 _: *const TEXTMETRICW,
202 fonttype: DWORD,
203 lparam: LPARAM)
204 -> c_int {
205 if fonttype != 4 {
206 return 1;
207 }
208
209 if ((*lpelfe).lfPitchAndFamily & FIXED_PITCH as u8) == 0 {
210 return 1;
211 }
212 add_vec(lpelfe, lparam);
213
214 1
215 }
216
217 unsafe fn add_vec(lpelfe: *const LOGFONTW, lparam: LPARAM) {
218 let lpelfe = lpelfe as *const ENUMLOGFONTEXW;
219
220 let name_array = (*lpelfe).elfFullName;
221 let pos = name_array.iter().position(|c| *c == 0).unwrap();
222 let name_array = &name_array[0..pos];
223
224 let name = OsString::from_wide(name_array).into_string().unwrap();
225
226 if name.chars().next() != Some('@') {
227 let vec_pointer = lparam as *mut Vec<String>;
228 let ref mut fonts = *vec_pointer;
229 fonts.push(name);
230 }
231 }
232
233 #[allow(non_snake_case)]
234 unsafe extern "system" fn callback_native(lpelfe: *const LOGFONTW,
235 _: *const TEXTMETRICW,
236 fonttype: DWORD,
237 lparam: LPARAM)
238 -> c_int {
239
240 if fonttype != 4 {
241 return 1;
242 }
243
244 ptr::copy(lpelfe, lparam as *mut _, 1);
245
246 0
247 }
248
249}