diff --git a/Cargo.lock b/Cargo.lock index 4286095..2a53ad6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,6 +30,15 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + [[package]] name = "alsa" version = "0.6.0" @@ -120,21 +129,26 @@ checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" [[package]] name = "bindgen" -version = "0.59.2" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +checksum = "c72a978d268b1d70b0e963217e60fdabd9523a941457a6c42a7315d15c7e89e5" dependencies = [ "bitflags", "cexpr", + "cfg-if 0.1.10", "clang-sys", + "clap", + "env_logger", "lazy_static", "lazycell", + "log", "peeking_take_while", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", + "which", ] [[package]] @@ -264,11 +278,11 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cexpr" -version = "0.6.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" dependencies = [ - "nom", + "nom 5.1.2", ] [[package]] @@ -294,13 +308,13 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.3.3" +version = "0.29.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a050e2153c5be08febd6734e29298e844fdb0fa21aeddd63b4eb7baa106c69b" +checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a" dependencies = [ "glob", "libc", - "libloading 0.7.3", + "libloading 0.5.2", ] [[package]] @@ -380,12 +394,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "const-cstr" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" - [[package]] name = "core-foundation" version = "0.6.4" @@ -496,9 +504,9 @@ dependencies = [ [[package]] name = "coreaudio-sys" -version = "0.2.10" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dff444d80630d7073077d38d40b4501fd518bd2b922c2a55edcc8b0f7be57e6" +checksum = "17f73df0f29f4c3c374854f076c47dc018f19acaa63538880dba0937ad4fa8d7" dependencies = [ "bindgen", ] @@ -781,6 +789,19 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "error-chain" version = "0.12.4" @@ -862,15 +883,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "fontconfig" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25320ad784a9578ada0b395dd7dcd2321109404bbb341ec27e64b01a1e49b47" -dependencies = [ - "yeslogic-fontconfig-sys", -] - [[package]] name = "foreign-types" version = "0.3.2" @@ -1215,6 +1227,15 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549" +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1385,6 +1406,16 @@ version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +[[package]] +name = "libloading" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" +dependencies = [ + "cc", + "winapi", +] + [[package]] name = "libloading" version = "0.6.7" @@ -1639,7 +1670,7 @@ dependencies = [ name = "mpd_info_screen" version = "0.2.20" dependencies = [ - "fontconfig", + "bindgen", "freetype", "ggez", "image 0.24.3", @@ -1793,6 +1824,16 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "memchr", + "version_check", +] + [[package]] name = "nom" version = "7.1.1" @@ -2156,6 +2197,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.20" @@ -2264,6 +2311,8 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", ] @@ -2446,9 +2495,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] name = "sid" @@ -2660,6 +2709,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -2982,6 +3040,15 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" +[[package]] +name = "which" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" +dependencies = [ + "libc", +] + [[package]] name = "winapi" version = "0.3.9" @@ -3062,7 +3129,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" dependencies = [ - "nom", + "nom 7.1.1", ] [[package]] @@ -3086,18 +3153,6 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" -[[package]] -name = "yeslogic-fontconfig-sys" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2bbd69036d397ebbff671b1b8e4d918610c181c5a16073b96f984a38d08c386" -dependencies = [ - "const-cstr", - "dlib 0.5.0", - "once_cell", - "pkg-config", -] - [[package]] name = "zip" version = "0.5.13" diff --git a/Cargo.toml b/Cargo.toml index 93a2ac8..abb330c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,9 @@ structopt = "0.3" image = "0.24" ggez = "0.7" freetype = { version = "0.7", optional = true } -fontconfig = { version = "0.5", optional = true } + +[build-dependencies] +bindgen = { version = "0.53", optional = true } [features] -unicode_support = ["dep:freetype", "dep:fontconfig"] +unicode_support = ["dep:freetype", "dep:bindgen"] diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..458302e --- /dev/null +++ b/build.rs @@ -0,0 +1,26 @@ +use std::env; +use std::path::PathBuf; + +use bindgen; + +#[cfg(not(feature = "unicode_support"))] +fn main() { +} + +#[cfg(feature = "unicode_support")] +fn main() { + println!("cargo:rustc-link-search=/usr/lib"); + println!("cargo:rustc-link-lib=fontconfig"); + println!("cargo:rerun-if-changed=src/bindgen_wrapper.h"); + + let bindings = bindgen::Builder::default() + .header("src/bindgen_wrapper.h") + .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + .generate() + .expect("Unable to generate bindings"); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("unicode_support_bindings.rs")) + .expect("Couldn't write bindings"); +} diff --git a/src/bindgen_wrapper.h b/src/bindgen_wrapper.h new file mode 100644 index 0000000..79bf5b9 --- /dev/null +++ b/src/bindgen_wrapper.h @@ -0,0 +1 @@ +#include diff --git a/src/unicode_support/fontconfig.rs b/src/unicode_support/fontconfig.rs index 8f6520d..74de4e8 100644 --- a/src/unicode_support/fontconfig.rs +++ b/src/unicode_support/fontconfig.rs @@ -1 +1,9 @@ -use fontconfig; +mod ffi { + mod bindgen { + #![allow(non_upper_case_globals)] + #![allow(non_camel_case_types)] + #![allow(non_snake_case)] + + include!(concat!(env!("OUT_DIR"), "/unicode_support_bindings.rs")); + } +} diff --git a/src/unicode_support/freetype.rs b/src/unicode_support/freetype.rs index 9dab281..91705d5 100644 --- a/src/unicode_support/freetype.rs +++ b/src/unicode_support/freetype.rs @@ -1 +1,157 @@ -use freetype; +use std::path::Path; + +mod ffi { + use freetype::freetype::{ + FT_Done_Face, FT_Done_Library, FT_Face, FT_FaceRec_, FT_Get_Char_Index, FT_Init_FreeType, + FT_Library, FT_ModuleRec_, FT_Open_Args, FT_Open_Face, FT_Parameter_, FT_StreamRec_, + FT_OPEN_PATHNAME, + }; + use std::ffi::CString; + use std::path::Path; + + pub struct FTLibrary { + library: FT_Library, + } + + impl Drop for FTLibrary { + fn drop(&mut self) { + if !self.library.is_null() { + unsafe { + FT_Done_Library(self.library); + } + } + } + } + + impl FTLibrary { + pub fn new() -> Option { + unsafe { + let mut library_ptr: FT_Library = 0 as FT_Library; + if FT_Init_FreeType(&mut library_ptr) != 0 { + Some(FTLibrary { + library: library_ptr, + }) + } else { + None + } + } + } + + pub fn get(&self) -> FT_Library { + self.library + } + } + + pub struct FTOpenArgs { + args: FT_Open_Args, + pathname: Option, + } + + impl FTOpenArgs { + pub fn new_with_path(path: &Path) -> Self { + unsafe { + let cstring: CString = CString::from_vec_unchecked( + path.as_os_str().to_str().unwrap().as_bytes().to_vec(), + ); + let mut args = FT_Open_Args { + flags: FT_OPEN_PATHNAME, + memory_base: 0 as *const u8, + memory_size: 0, + pathname: cstring.as_ptr() as *mut i8, + stream: 0 as *mut FT_StreamRec_, + driver: 0 as *mut FT_ModuleRec_, + num_params: 0, + params: 0 as *mut FT_Parameter_, + }; + + FTOpenArgs { + args, + pathname: Some(cstring), + } + } + } + + pub fn get_args(&self) -> FT_Open_Args { + self.args + } + + pub fn get_ptr(&mut self) -> *mut FT_Open_Args { + &mut self.args as *mut FT_Open_Args + } + } + + pub struct FTFaces { + faces: Vec, + } + + impl Drop for FTFaces { + fn drop(&mut self) { + for face in &self.faces { + unsafe { + FT_Done_Face(*face); + } + } + } + } + + impl FTFaces { + pub fn new(library: &FTLibrary, args: &mut FTOpenArgs) -> Result { + let mut faces = FTFaces { faces: Vec::new() }; + unsafe { + let count; + let mut face: FT_Face = 0 as FT_Face; + // first get number of faces + let mut result = FT_Open_Face( + library.get(), + args.get_ptr(), + -1, + &mut face as *mut *mut FT_FaceRec_, + ); + if result != 0 { + FT_Done_Face(face); + return Err(()); + } + count = (*face).num_faces; + + for i in 0..count { + result = FT_Open_Face( + library.get(), + args.get_ptr(), + i, + &mut face as *mut *mut FT_FaceRec_, + ); + if result != 0 { + FT_Done_Face(face); + return Err(()); + } + faces.faces.push(face); + } + } + + Ok(faces) + } + + pub fn has_char(&self, c: char) -> bool { + let char_value: u64 = c as u64; + + for face in &self.faces { + unsafe { + let result = FT_Get_Char_Index(*face, char_value); + if result != 0 { + return true; + } + } + } + + false + } + } +} + +pub fn font_has_char(c: char, font_path: &Path) -> Result { + let library = ffi::FTLibrary::new().ok_or(())?; + let mut args = ffi::FTOpenArgs::new_with_path(font_path); + let faces = ffi::FTFaces::new(&library, &mut args)?; + + Ok(faces.has_char(c)) +}