Remove yeslogic-fontconfig dependency

We need only 9 different functions from fontconfig and one data
structure.  We can do that interaction with libloading by hand and avoid
causing issues like servo/font-kit#212
This commit is contained in:
Simon Hausmann 2023-06-21 09:35:10 +02:00 committed by Simon Hausmann
parent a259095353
commit c81a3f7b64
4 changed files with 76 additions and 28 deletions

View file

@ -95,7 +95,6 @@ rust-version = "1.66"
[workspace.dependencies]
resvg = { version= "0.34.0", default-features = false, features = ["text"] }
fontdb = { version = "0.14.1", default-features = false }
yeslogic-fontconfig-sys = { version = "3.2.0", features = ["dlopen"] }
send_wrapper = { version = "0.6.0" }
[profile.release]

View file

@ -16,7 +16,7 @@ homepage = "https://slint.dev"
path = "lib.rs"
[features]
shared-fontdb = ["dep:fontdb", "dep:libc", "dep:yeslogic-fontconfig-sys", "derive_more", "cfg-if"]
shared-fontdb = ["dep:fontdb", "dep:libloading", "derive_more", "cfg-if"]
[dependencies]
fontdb = { workspace = true, optional = true }
@ -24,8 +24,7 @@ derive_more = { version = "0.99.5", optional = true }
cfg-if = { version = "1", optional = true }
[target.'cfg(not(any(target_family = "windows", target_os = "macos", target_os = "ios", target_arch = "wasm32")))'.dependencies]
libc = { version = "0.2", optional = true }
yeslogic-fontconfig-sys = { workspace = true, optional = true }
libloading = { version = "0.8.0", optional = true }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
fontdb = { workspace = true, optional = true, default-features = true, features = ["fontconfig", "memmap"] }

View file

@ -3,31 +3,86 @@
#![allow(unsafe_code)]
use fontconfig_sys as ffi;
use core::ffi::{c_char, c_int, c_uchar, c_void};
use ffi::statics::LIB;
const FC_MATCH_PATTERN: c_int = 0;
const FC_RESULT_MATCH: c_int = 0;
#[repr(C)]
struct FcFontSet {
nfont: c_int,
sfont: c_int,
fonts: *mut *mut c_void,
}
// This is duplicated in the slint-compiler's glyph embedding code
pub fn find_families(requested_family: &str) -> Vec<String> {
unsafe {
let config = (LIB.FcInitLoadConfigAndFonts)();
let fontconfig = libloading::Library::new("libfontconfig.so.1")
.expect("Unable to dlopen libfontconfig.so.1");
let fc_init_load_config_and_fonts: libloading::Symbol<
unsafe extern "C" fn() -> *mut c_void,
> = fontconfig
.get(b"FcInitLoadConfigAndFonts")
.expect("Unable to find FcInitLoadConfigAndFonts");
let fc_name_parse: libloading::Symbol<unsafe extern "C" fn(*const c_uchar) -> *mut c_void> =
fontconfig.get(b"FcNameParse").expect("Unable to find FcNameParse");
let fc_config_substitute: libloading::Symbol<
unsafe extern "C" fn(
*mut c_void, // FcConfig *
*mut c_void, // FcPattern *
c_int, // FcMatchKind
) -> c_int,
> = fontconfig.get(b"FcConfigSubstitute").expect("Unable to find FcConfigSubstitute");
let fc_default_substitute: libloading::Symbol<unsafe extern "C" fn(*mut c_void)> =
fontconfig.get(b"FcDefaultSubstitute").expect("Unable to find FcDefaultSubstitute");
let fc_font_sort: libloading::Symbol<
unsafe extern "C" fn(
*mut c_void, // FcConfig *
*mut c_void, // FcPattern *
c_int, // FcBool trim
*mut *mut c_void, // FcCharSet **
*mut c_int, // FcResult *
) -> *mut FcFontSet,
> = fontconfig.get(b"FcFontSort").expect("Unable to find FcFontSort");
let fc_pattern_get_string: libloading::Symbol<
unsafe extern "C" fn(
*mut c_void, // FcPattern *
*const c_char, // const char *object
c_int, // int n
*mut *mut c_uchar, // FcChar8 **s
) -> c_int,
> = fontconfig.get(b"FcPatternGetString").expect("Unable to find FcPatternGetString");
let fc_font_set_destroy: libloading::Symbol<unsafe extern "C" fn(*mut FcFontSet)> =
fontconfig.get(b"FcFontSetDestroy").expect("Unable to find FcFontSetDestroy");
let fc_pattern_destroy: libloading::Symbol<
unsafe extern "C" fn(
*mut c_void, // FcPattern *
),
> = fontconfig.get(b"FcPatternDestroy").expect("Unable to find FcPatternDestroy");
let fc_config_destroy: libloading::Symbol<
unsafe extern "C" fn(
*mut c_void, // FcConfig *
),
> = fontconfig.get(b"FcConfigDestroy").expect("Unable to find FcConfigDestroy");
let config = fc_init_load_config_and_fonts();
let family_cstr = std::ffi::CString::new(requested_family).unwrap();
let pattern = (LIB.FcNameParse)(family_cstr.as_ptr() as *mut libc::c_uchar);
(LIB.FcConfigSubstitute)(std::ptr::null_mut(), pattern, ffi::FcMatchPattern);
(LIB.FcDefaultSubstitute)(pattern);
let mut sort_result = ffi::FcResultMatch;
let result_set =
(LIB.FcFontSort)(config, pattern, 1, std::ptr::null_mut(), &mut sort_result);
let pattern = fc_name_parse(family_cstr.as_ptr() as *mut c_uchar);
fc_config_substitute(std::ptr::null_mut(), pattern, FC_MATCH_PATTERN);
fc_default_substitute(pattern);
let mut sort_result = FC_RESULT_MATCH;
let result_set = fc_font_sort(config, pattern, 1, std::ptr::null_mut(), &mut sort_result);
let mut families = Vec::new();
for idx in 0..(*result_set).nfont {
let mut raw_family_name = std::ptr::null_mut();
if (LIB.FcPatternGetString)(
if fc_pattern_get_string(
*(*result_set).fonts.offset(idx as isize),
b"family\0".as_ptr() as *const libc::c_char,
b"family\0".as_ptr() as *const c_char,
0,
&mut raw_family_name,
) != ffi::FcResultMatch
) != FC_RESULT_MATCH
{
continue;
}
@ -35,19 +90,18 @@ pub fn find_families(requested_family: &str) -> Vec<String> {
if raw_family_name.is_null() {
continue;
}
if let Some(family_name) =
std::ffi::CStr::from_ptr(raw_family_name as *const libc::c_char)
.to_str()
.ok()
.map(|raw_family_name| raw_family_name.to_owned())
if let Some(family_name) = std::ffi::CStr::from_ptr(raw_family_name as *const c_char)
.to_str()
.ok()
.map(|raw_family_name| raw_family_name.to_owned())
{
families.push(family_name)
}
}
(LIB.FcFontSetDestroy)(result_set);
(LIB.FcPatternDestroy)(pattern);
(LIB.FcConfigDestroy)(config);
fc_font_set_destroy(result_set);
fc_pattern_destroy(pattern);
fc_config_destroy(config);
families
}
}

View file

@ -96,10 +96,6 @@ fontdb = { workspace = true, optional = true, default-features = true, features
rustybuzz = { version = "0.7.0", optional = true }
fontdue = { version = "0.7.1", optional = true }
[target.'cfg(not(any(target_family = "windows", target_os = "macos", target_os = "ios", target_arch = "wasm32")))'.dependencies]
libc = { version = "0.2", optional = true }
yeslogic-fontconfig-sys = { workspace = true, optional = true }
[dev-dependencies]
slint = { path = "../../api/rs/slint", default-features = false, features = ["std", "compat-1-0"] }
i-slint-backend-testing = { path="../backends/testing" }