pub mod system_fonts {
use winapi::um::wingdi;
use winapi::um::wingdi::TEXTMETRICW;
use winapi::ctypes::{c_int, c_void};
use winapi::um::winnt::{PVOID};
use winapi::um::wingdi::FIXED_PITCH;
use winapi::um::wingdi::{ENUMLOGFONTEXW, LOGFONTW, OUT_TT_ONLY_PRECIS};
use winapi::um::wingdi::FONTENUMPROCW;
use winapi::shared::minwindef::{DWORD, LPARAM};
use std::ptr;
use std::mem;
use std::ffi::{OsStr, OsString};
use std::os::windows::ffi::{OsStrExt, OsStringExt};
pub type FontProperty = LOGFONTW;
pub struct FontPropertyBuilder {
config: FontProperty,
}
impl FontPropertyBuilder {
pub fn new() -> FontPropertyBuilder {
let string: [u16; 32] = [0; 32];
FontPropertyBuilder {
config: FontProperty {
lfHeight: 0,
lfWidth: 0,
lfEscapement: 0,
lfOrientation: 0,
lfWeight: 0,
lfItalic: 0,
lfUnderline: 0,
lfStrikeOut: 0,
lfCharSet: 0,
lfOutPrecision: OUT_TT_ONLY_PRECIS as u8,
lfClipPrecision: 0,
lfQuality: 0,
lfPitchAndFamily: 0,
lfFaceName: string,
},
}
}
pub fn italic(mut self) -> FontPropertyBuilder {
self.config.lfItalic = true as u8;
self
}
pub fn oblique(self) -> FontPropertyBuilder {
self.italic()
}
pub fn monospace(mut self) -> FontPropertyBuilder {
self.config.lfPitchAndFamily |= FIXED_PITCH as u8;
self
}
pub fn bold(mut self) -> FontPropertyBuilder {
self.config.lfWeight = 700;
self
}
pub fn family(mut self, name: &str) -> FontPropertyBuilder {
if name.len() > 31 {
panic!("Font length must me smaller than 31");
}
let name: &OsStr = name.as_ref();
let buffer = name.encode_wide();
let mut string: [u16; 32] = [0; 32]; for (index, item) in buffer.enumerate() {
string[index] = item;
}
self.config.lfFaceName = string;
self
}
pub fn build(self) -> FontProperty {
self.config
}
}
pub fn get(config: &FontProperty) -> Option<(Vec<u8>, c_int)> {
unsafe {
let hdc = wingdi::CreateCompatibleDC(ptr::null_mut());
let hfont = wingdi::CreateFontIndirectW(config as *const LOGFONTW);
wingdi::SelectObject(hdc, hfont as *mut c_void);
let size = wingdi::GetFontData(hdc, 0, 0, ptr::null_mut(), 0);
if size == 0xFFFFFFFF {
wingdi::DeleteDC(hdc);
None
} else if size > 0 {
let mut buffer: Vec<u8> = vec![0; size as usize];
let pointer = buffer.first_mut().unwrap() as *mut _ as PVOID;
let size = wingdi::GetFontData(hdc, 0, 0, pointer, size);
buffer.set_len(size as usize);
wingdi::DeleteDC(hdc);
Some((buffer, 0))
} else {
wingdi::DeleteDC(hdc);
None
}
}
}
pub fn get_native(config: &mut FontProperty) -> FontProperty {
let f: FONTENUMPROCW = Some(callback_native);
unsafe {
let mut logfont: LOGFONTW = mem::zeroed();
let pointer = &mut logfont as *mut _;
let hdc = wingdi::CreateCompatibleDC(ptr::null_mut());
wingdi::EnumFontFamiliesExW(hdc, config, f, pointer as LPARAM, 0);
wingdi::DeleteDC(hdc);
logfont
}
}
pub fn query_all() -> Vec<String> {
let mut config = FontPropertyBuilder::new().build();
query_specific(&mut config)
}
pub fn query_specific(property: &mut FontProperty) -> Vec<String> {
let mut fonts = Vec::new();
let mut f: FONTENUMPROCW = Some(callback_ttf);
unsafe {
let hdc = wingdi::CreateCompatibleDC(ptr::null_mut());
if (property.lfPitchAndFamily & FIXED_PITCH as u8) != 0 {
f = Some(callback_monospace);
}
let vec_pointer = &mut fonts as *mut Vec<String>;
wingdi::EnumFontFamiliesExW(hdc, property, f, vec_pointer as LPARAM, 0);
wingdi::DeleteDC(hdc);
}
fonts
}
#[allow(non_snake_case)]
unsafe extern "system" fn callback_ttf(lpelfe: *const LOGFONTW,
_: *const TEXTMETRICW,
fonttype: DWORD,
lparam: LPARAM)
-> c_int {
if fonttype != 4 {
return 1;
}
add_vec(lpelfe, lparam);
1
}
#[allow(non_snake_case)]
unsafe extern "system" fn callback_monospace(lpelfe: *const LOGFONTW,
_: *const TEXTMETRICW,
fonttype: DWORD,
lparam: LPARAM)
-> c_int {
if fonttype != 4 {
return 1;
}
if ((*lpelfe).lfPitchAndFamily & FIXED_PITCH as u8) == 0 {
return 1;
}
add_vec(lpelfe, lparam);
1
}
unsafe fn add_vec(lpelfe: *const LOGFONTW, lparam: LPARAM) {
let lpelfe = lpelfe as *const ENUMLOGFONTEXW;
let name_array = (*lpelfe).elfFullName;
let pos = name_array.iter().position(|c| *c == 0).unwrap();
let name_array = &name_array[0..pos];
let name = OsString::from_wide(name_array).into_string().unwrap();
if name.chars().next() != Some('@') {
let vec_pointer = lparam as *mut Vec<String>;
let ref mut fonts = *vec_pointer;
fonts.push(name);
}
}
#[allow(non_snake_case)]
unsafe extern "system" fn callback_native(lpelfe: *const LOGFONTW,
_: *const TEXTMETRICW,
fonttype: DWORD,
lparam: LPARAM)
-> c_int {
if fonttype != 4 {
return 1;
}
ptr::copy(lpelfe, lparam as *mut _, 1);
0
}
}