aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Wilm <joe@jwilm.com>2016-02-21 17:46:49 -0800
committerJoe Wilm <joe@jwilm.com>2016-02-21 17:49:13 -0800
commit32bac943433610434f7d504114d6d409c8a698af (patch)
treede01c2513fee28831d25acc79e29b849a53ac027
parent2a7dc1deb825f9f1db6de8b50656ef420ff41a44 (diff)
downloadr-alacritty-32bac943433610434f7d504114d6d409c8a698af.tar.gz
r-alacritty-32bac943433610434f7d504114d6d409c8a698af.tar.bz2
r-alacritty-32bac943433610434f7d504114d6d409c8a698af.zip
implement list_fonts::list_families
A list of families is returned. Each variant contains the variant's style, the filepath for the variant, and the index of the variant in the file. This info should be enough to get freetype to actually load a font.
-rw-r--r--src/list_fonts.rs141
1 files changed, 119 insertions, 22 deletions
diff --git a/src/list_fonts.rs b/src/list_fonts.rs
index 9b15ea3d..c418bc02 100644
--- a/src/list_fonts.rs
+++ b/src/list_fonts.rs
@@ -1,16 +1,24 @@
-use std::ffi::CStr;
+use std::ffi::{CStr, CString};
+use std::path::PathBuf;
use std::ptr;
-use std::str;
+use std::str::from_utf8;
use libc::{c_char, c_int};
use fontconfig::fontconfig::{FcConfigGetCurrent, FcConfigGetFonts, FcSetSystem};
-use fontconfig::fontconfig::{FcPatternGetString};
-use fontconfig::fontconfig::{FcResultMatch};
+use fontconfig::fontconfig::{FcPatternGetString, FcPatternCreate, FcPatternAddString};
+use fontconfig::fontconfig::{FcPatternGetInteger};
+use fontconfig::fontconfig::{FcObjectSetCreate, FcObjectSetAdd};
+use fontconfig::fontconfig::{FcResultMatch, FcFontSetList};
use fontconfig::fontconfig::{FcChar8};
+use fontconfig::fontconfig::{FcFontSetDestroy, FcPatternDestroy, FcObjectSetDestroy};
-pub fn list_font_names() -> Vec<String> {
- let mut fonts = Vec::new();
+unsafe fn fc_char8_to_string(fc_str: *mut FcChar8) -> String {
+ from_utf8(CStr::from_ptr(fc_str as *const c_char).to_bytes()).unwrap().to_owned()
+}
+
+fn list_families() -> Vec<String> {
+ let mut families = Vec::new();
unsafe {
// https://www.freedesktop.org/software/fontconfig/fontconfig-devel/fcconfiggetcurrent.html
let config = FcConfigGetCurrent(); // *mut FcConfig
@@ -22,36 +30,125 @@ pub fn list_font_names() -> Vec<String> {
for i in 0..nfont {
let font = (*font_set).fonts.offset(i); // *mut FcPattern
let id = 0 as c_int;
- let mut fullname: *mut FcChar8 = ptr::null_mut();
+ let mut family: *mut FcChar8 = ptr::null_mut();
+ let mut format: *mut FcChar8 = ptr::null_mut();
- // The second parameter here (fullname) is from the "FONT PROPERTIES" table:
- // https://www.freedesktop.org/software/fontconfig/fontconfig-devel/x19.html
let result = FcPatternGetString(*font,
- b"fullname\0".as_ptr() as *mut c_char,
+ b"fontformat\0".as_ptr() as *mut c_char,
id,
- &mut fullname);
+ &mut format);
+
if result != FcResultMatch {
continue;
}
- let s = str::from_utf8(CStr::from_ptr(fullname as *const c_char).to_bytes())
- .unwrap().to_owned();
- fonts.push(s);
+ let format = fc_char8_to_string(format);
+
+ if format != "TrueType" && format != "CFF" {
+ continue
+ }
+
+ let mut id = 0;
+ while FcPatternGetString(*font, b"family\0".as_ptr() as *mut c_char, id, &mut family) == FcResultMatch {
+ let safe_family = fc_char8_to_string(family);
+ id += 1;
+ families.push(safe_family);
+ }
}
}
- fonts
+ families.sort();
+ families.dedup();
+ families
+}
+
+#[derive(Debug)]
+pub struct Variant {
+ style: String,
+ file: PathBuf,
+ index: usize,
+}
+
+#[derive(Debug)]
+pub struct Family {
+ name: String,
+ variants: Vec<Variant>,
+}
+
+static FILE: &'static [u8] = b"file\0";
+static FAMILY: &'static [u8] = b"family\0";
+static INDEX: &'static [u8] = b"index\0";
+static STYLE: &'static [u8] = b"style\0";
+
+pub fn get_family_info(family: String) -> Family {
+
+ let mut members = Vec::new();
+
+ unsafe {
+ let config = FcConfigGetCurrent(); // *mut FcConfig
+ let mut font_set = FcConfigGetFonts(config, FcSetSystem); // *mut FcFontSet
+
+ let pattern = FcPatternCreate();
+ let family_name = CString::new(&family[..]).unwrap();
+ let family_name = family_name.as_ptr();
+
+ // Add family name to pattern. Use this for searching.
+ FcPatternAddString(pattern, FAMILY.as_ptr() as *mut c_char, family_name as *mut FcChar8);
+
+ // Request filename, style, and index for each variant in family
+ let object_set = FcObjectSetCreate(); // *mut FcObjectSet
+ FcObjectSetAdd(object_set, FILE.as_ptr() as *mut c_char);
+ FcObjectSetAdd(object_set, INDEX.as_ptr() as *mut c_char);
+ FcObjectSetAdd(object_set, STYLE.as_ptr() as *mut c_char);
+
+ let variants = FcFontSetList(config, &mut font_set, 1 /* nsets */, pattern, object_set);
+ let num_variant = (*variants).nfont as isize;
+
+ for i in 0..num_variant {
+ let font = (*variants).fonts.offset(i);
+ let mut file: *mut FcChar8 = ptr::null_mut();
+ assert_eq!(FcPatternGetString(*font, FILE.as_ptr() as *mut c_char, 0, &mut file),
+ FcResultMatch);
+ let file = fc_char8_to_string(file);
+
+ let mut style: *mut FcChar8 = ptr::null_mut();
+ assert_eq!(FcPatternGetString(*font, STYLE.as_ptr() as *mut c_char, 0, &mut style),
+ FcResultMatch);
+ let style = fc_char8_to_string(style);
+
+ let mut index = 0 as c_int;
+ assert_eq!(FcPatternGetInteger(*font, INDEX.as_ptr() as *mut c_char, 0, &mut index),
+ FcResultMatch);
+
+ members.push(Variant {
+ style: style,
+ file: PathBuf::from(file),
+ index: index as usize,
+ });
+ }
+
+ FcFontSetDestroy(variants);
+ FcPatternDestroy(pattern);
+ FcObjectSetDestroy(object_set);
+ }
+
+ Family {
+ name: family,
+ variants: members
+ }
+}
+
+pub fn get_font_families() -> Vec<Family> {
+ list_families().into_iter()
+ .map(|family| get_family_info(family))
+ .collect()
}
#[cfg(test)]
mod tests {
- use super::list_font_names;
-
#[test]
- fn list_fonts() {
- let fonts = list_font_names();
- assert!(!fonts.is_empty());
-
- println!("fonts: {:?}", fonts);
+ fn get_font_families() {
+ let families = super::get_font_families();
+ assert!(!families.is_empty());
}
}