diff --git a/examples/plotter/Cargo.toml b/examples/plotter/Cargo.toml index 0990ad1b59d..d8566ae953a 100644 --- a/examples/plotter/Cargo.toml +++ b/examples/plotter/Cargo.toml @@ -15,11 +15,23 @@ name = "plotter" [dependencies] slint = { path = "../../api/rs/slint" } -plotters = { version = "0.3.1", default-features = false, features = ["bitmap_backend", "surface_series"] } +plotters = { git = "https://github.com/Be-ing/plotters.git", branch = "font-kit-update", default-features = false, features = ["bitmap_backend", "surface_series"] } [build-dependencies] slint-build = { path = "../../api/rs/build" } +[features] +# This is required so plotters enables font-kit's source-fontconfig-dlopen feature +# when building the workspace with `cargo build --workspace --all-features` on CI. This is because +# `--workspace --all-features` enables i-slint-backend-gl and i-slint-compiler's fontconfig-dlopen +# features. Without this, font-kit would fail to build because Cargo would activate the dlopen +# feature of yeslogic-fontconfig-sys but not font-kit's source-fontconfig-dlopen feature. +# +# If you want to enable this feature apart from `--workspace --all-features`, set the environment +# variable RUST_FONTCONFIG_DLOPEN=on to enable the fontconfig-dlopen features of +# i-slint-backend-gl and i-slint-compiler. +fontconfig-dlopen = ["plotters/fontconfig-dlopen"] + # Remove the `#wasm#` to uncomment the wasm build. # This is commented out by default because we don't want to build it as a library by default # The CI has a script that does sed "s/#wasm# //" to generate the wasm build. diff --git a/internal/backends/gl/Cargo.toml b/internal/backends/gl/Cargo.toml index 04d315d9dbc..5f044242fc4 100644 --- a/internal/backends/gl/Cargo.toml +++ b/internal/backends/gl/Cargo.toml @@ -20,6 +20,10 @@ path = "lib.rs" svg = ["resvg", "usvg", "tiny-skia"] wayland = ["winit/wayland", "glutin/wayland", "copypasta/wayland"] x11 = ["winit/x11", "glutin/x11", "copypasta/x11"] +# dlopen fontconfig at runtime rather than link at build time. +# useful for cross compiling +# Using a vendored fontconfig C library does not work well, refer to Issue #88. +fontconfig-dlopen = [ "font-kit/source-fontconfig-dlopen", "yeslogic-fontconfig-sys/dlopen" ] rtti = ["i-slint-core/rtti"] @@ -65,13 +69,11 @@ glutin = { version = "0.28", default-features = false } usvg = { version= "0.22", optional = true, default-features = false, features = ["text", "memmap-fonts"] } [target.'cfg(target_family = "windows")'.dependencies] -font-kit = { version = "0.10", features = [] } +font-kit = "0.11" [target.'cfg(not(any(target_family = "windows", target_os = "macos", target_os = "ios", target_arch = "wasm32")))'.dependencies] libc = { version = "0.2" } -# Require font-config from the system on Linux. Issue #88 indicates that the copy provided by servo-fontconfig may be incompatible -# with distros at times. -servo-fontconfig = { version = "0.5", features = [ "force_system_lib" ] } +yeslogic-fontconfig-sys = "3.0.0" [target.'cfg(target_os = "macos")'.dependencies] cocoa = { version = "0.24.0" } diff --git a/internal/backends/gl/build.rs b/internal/backends/gl/build.rs new file mode 100644 index 00000000000..f0d2d156dbf --- /dev/null +++ b/internal/backends/gl/build.rs @@ -0,0 +1,10 @@ +// Copyright © SixtyFPS GmbH +// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial + +fn main() { + println!("cargo:rerun-if-env-changed=RUST_FONTCONFIG_DLOPEN"); + let dlopen = std::env::var("RUST_FONTCONFIG_DLOPEN").is_ok(); + if dlopen { + println!("cargo:rustc-cfg=feature=\"fontconfig-dlopen\""); + } +} diff --git a/internal/backends/gl/fonts/fontconfig.rs b/internal/backends/gl/fonts/fontconfig.rs index f2bb1e8d985..9b95ea1fdd4 100644 --- a/internal/backends/gl/fonts/fontconfig.rs +++ b/internal/backends/gl/fonts/fontconfig.rs @@ -1,29 +1,58 @@ // Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial -use fontconfig::fontconfig; +use fontconfig_sys as ffi; +use fontconfig_sys::ffi_dispatch; + +#[cfg(feature = "fontconfig-dlopen")] +use ffi::statics::LIB; +#[cfg(not(feature = "fontconfig-dlopen"))] +use ffi::*; // This is duplicated in the slint-compiler's glyph embedding code pub fn find_families(requested_family: &str) -> Vec { unsafe { - let config = fontconfig::FcInitLoadConfigAndFonts(); + let config = ffi_dispatch!(feature = "fontconfig-dlopen", LIB, FcInitLoadConfigAndFonts,); let family_cstr = std::ffi::CString::new(requested_family).unwrap(); - let pattern = fontconfig::FcNameParse(family_cstr.as_ptr() as *mut libc::c_uchar); - fontconfig::FcConfigSubstitute(std::ptr::null_mut(), pattern, fontconfig::FcMatchPattern); - fontconfig::FcDefaultSubstitute(pattern); - let mut sort_result = fontconfig::FcResultMatch; - let result_set = - fontconfig::FcFontSort(config, pattern, 1, std::ptr::null_mut(), &mut sort_result); + let pattern = ffi_dispatch!( + feature = "fontconfig-dlopen", + LIB, + FcNameParse, + family_cstr.as_ptr() as *mut libc::c_uchar + ); + ffi_dispatch!( + feature = "fontconfig-dlopen", + LIB, + FcConfigSubstitute, + std::ptr::null_mut(), + pattern, + ffi::FcMatchPattern + ); + ffi_dispatch!(feature = "fontconfig-dlopen", LIB, FcDefaultSubstitute, pattern); + let mut sort_result = ffi::FcResultMatch; + let result_set = ffi_dispatch!( + feature = "fontconfig-dlopen", + LIB, + FcFontSort, + 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 fontconfig::FcPatternGetString( + if ffi_dispatch!( + feature = "fontconfig-dlopen", + LIB, + FcPatternGetString, *(*result_set).fonts.offset(idx as isize), b"family\0".as_ptr() as *const libc::c_char, 0, - &mut raw_family_name, - ) != fontconfig::FcResultMatch + &mut raw_family_name + ) != ffi::FcResultMatch { continue; } @@ -41,9 +70,9 @@ pub fn find_families(requested_family: &str) -> Vec { } } - fontconfig::FcFontSetDestroy(result_set); - fontconfig::FcPatternDestroy(pattern); - fontconfig::FcConfigDestroy(config); + ffi_dispatch!(feature = "fontconfig-dlopen", LIB, FcFontSetDestroy, result_set); + ffi_dispatch!(feature = "fontconfig-dlopen", LIB, FcPatternDestroy, pattern); + ffi_dispatch!(feature = "fontconfig-dlopen", LIB, FcConfigDestroy, config); families } } diff --git a/internal/compiler/Cargo.toml b/internal/compiler/Cargo.toml index 5551ec90021..458e2478ae6 100644 --- a/internal/compiler/Cargo.toml +++ b/internal/compiler/Cargo.toml @@ -20,6 +20,10 @@ path = "lib.rs" # Generators cpp = [] rust = ["quote", "proc-macro2"] +# dlopen fontconfig at runtime rather than link at build time. +# useful for cross compiling +# Using a vendored fontconfig C library does not work well, refer to Issue #88. +fontconfig-dlopen = [ "yeslogic-fontconfig-sys/dlopen" ] # Support for proc_macro spans in the token (only useful for use within a proc macro) proc_macro_span = ["quote", "proc-macro2"] @@ -61,9 +65,7 @@ usvg = "0.22" [target.'cfg(not(any(target_family = "windows", target_os = "macos", target_os = "ios", target_arch = "wasm32")))'.dependencies] libc = { version = "0.2" } -# Require font-config from the system on Linux. Issue #88 indicates that the copy provided by servo-fontconfig may be incompatible -# with distros at times. -servo-fontconfig = { version = "0.5", features = [ "force_system_lib" ] } +yeslogic-fontconfig-sys = "3.0.0" [dev-dependencies] i-slint-parser-test-macro = { path = "./parser-test-macro" } diff --git a/internal/compiler/build.rs b/internal/compiler/build.rs index 7027b3d27f2..2f45fd4ba20 100644 --- a/internal/compiler/build.rs +++ b/internal/compiler/build.rs @@ -6,6 +6,12 @@ use std::io::Write; use std::path::{Path, PathBuf}; fn main() -> std::io::Result<()> { + println!("cargo:rerun-if-env-changed=RUST_FONTCONFIG_DLOPEN"); + let dlopen = std::env::var("RUST_FONTCONFIG_DLOPEN").is_ok(); + if dlopen { + println!("cargo:rustc-cfg=feature=\"fontconfig-dlopen\""); + } + let mut library_dir = PathBuf::from(std::env::var_os("CARGO_MANIFEST_DIR").unwrap()); library_dir.push("widgets"); diff --git a/internal/compiler/passes/embed_glyphs/fontconfig.rs b/internal/compiler/passes/embed_glyphs/fontconfig.rs index b29e14c9cfe..a149687affb 100644 --- a/internal/compiler/passes/embed_glyphs/fontconfig.rs +++ b/internal/compiler/passes/embed_glyphs/fontconfig.rs @@ -1,30 +1,59 @@ // Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial -use fontconfig::fontconfig; +use fontconfig_sys as ffi; +use fontconfig_sys::ffi_dispatch; -// This is duplicated from the GL backend +#[cfg(feature = "fontconfig-dlopen")] +use ffi::statics::LIB; +#[cfg(not(feature = "fontconfig-dlopen"))] +use ffi::*; + +// This is duplicated in the slint-compiler's glyph embedding code pub fn find_families(requested_family: &str) -> Vec { #[allow(unsafe_code)] unsafe { - let config = fontconfig::FcInitLoadConfigAndFonts(); + let config = ffi_dispatch!(feature = "fontconfig-dlopen", LIB, FcInitLoadConfigAndFonts,); let family_cstr = std::ffi::CString::new(requested_family).unwrap(); - let pattern = fontconfig::FcNameParse(family_cstr.as_ptr() as *mut libc::c_uchar); - fontconfig::FcConfigSubstitute(std::ptr::null_mut(), pattern, fontconfig::FcMatchPattern); - fontconfig::FcDefaultSubstitute(pattern); - let mut sort_result = fontconfig::FcResultMatch; - let result_set = - fontconfig::FcFontSort(config, pattern, 1, std::ptr::null_mut(), &mut sort_result); + let pattern = ffi_dispatch!( + feature = "fontconfig-dlopen", + LIB, + FcNameParse, + family_cstr.as_ptr() as *mut libc::c_uchar + ); + ffi_dispatch!( + feature = "fontconfig-dlopen", + LIB, + FcConfigSubstitute, + std::ptr::null_mut(), + pattern, + ffi::FcMatchPattern + ); + ffi_dispatch!(feature = "fontconfig-dlopen", LIB, FcDefaultSubstitute, pattern); + let mut sort_result = ffi::FcResultMatch; + let result_set = ffi_dispatch!( + feature = "fontconfig-dlopen", + LIB, + FcFontSort, + 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 fontconfig::FcPatternGetString( + if ffi_dispatch!( + feature = "fontconfig-dlopen", + LIB, + FcPatternGetString, *(*result_set).fonts.offset(idx as isize), b"family\0".as_ptr() as *const libc::c_char, 0, - &mut raw_family_name, - ) != fontconfig::FcResultMatch + &mut raw_family_name + ) != ffi::FcResultMatch { continue; } @@ -42,9 +71,9 @@ pub fn find_families(requested_family: &str) -> Vec { } } - fontconfig::FcFontSetDestroy(result_set); - fontconfig::FcPatternDestroy(pattern); - fontconfig::FcConfigDestroy(config); + ffi_dispatch!(feature = "fontconfig-dlopen", LIB, FcFontSetDestroy, result_set); + ffi_dispatch!(feature = "fontconfig-dlopen", LIB, FcPatternDestroy, pattern); + ffi_dispatch!(feature = "fontconfig-dlopen", LIB, FcConfigDestroy, config); families } }