Skip to content

Commit

Permalink
GL backend: add basic font fallback support for Linux
Browse files Browse the repository at this point in the history
Use the static (but long) fallback list that we get from fontconfig in the beginning.

This works, but can be optimized to operate on a trimmed and shorter list,
which will speed up the fallback. But for now this makes it work.
  • Loading branch information
tronical committed Sep 17, 2021
1 parent cc7ea5b commit d2923d5
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 34 deletions.
63 changes: 48 additions & 15 deletions sixtyfps_runtime/rendering_backends/gl/fonts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,27 @@ pub struct FontCache {
pub(crate) text_context: TextContext,
available_fonts: fontdb::Database,
_available_families: HashSet<SharedString>,
#[cfg(not(any(
target_family = "windows",
target_os = "macos",
target_os = "ios",
target_arch = "wasm32"
)))]
fontconfig_fallback_families: Vec<String>,
}

impl Default for FontCache {
fn default() -> Self {
let mut font_db = fontdb::Database::new();

#[cfg(not(any(
target_family = "windows",
target_os = "macos",
target_os = "ios",
target_arch = "wasm32"
)))]
let mut fontconfig_fallback_families;

#[cfg(target_arch = "wasm32")]
{
let data = include_bytes!("fonts/DejaVuSans.ttf");
Expand All @@ -192,7 +207,10 @@ impl Default for FontCache {
target_os = "ios",
target_arch = "wasm32"
)))]
let default_sans_serif_family = fontconfig::find_family("sans-serif");
let default_sans_serif_family = {
fontconfig_fallback_families = fontconfig::find_families("sans-serif");
fontconfig_fallback_families.remove(0)
};
font_db.set_sans_serif_family(default_sans_serif_family);
}
let _available_families =
Expand All @@ -204,6 +222,13 @@ impl Default for FontCache {
text_context: Default::default(),
available_fonts: font_db,
_available_families,
#[cfg(not(any(
target_family = "windows",
target_os = "macos",
target_os = "ios",
target_arch = "wasm32"
)))]
fontconfig_fallback_families,
}
}
}
Expand Down Expand Up @@ -370,28 +395,36 @@ impl FontCache {
.collect()
}

#[cfg(all(not(target_os = "macos"), not(target_os = "windows")))]
#[cfg(all(not(target_os = "macos"), not(target_os = "windows"), not(target_arch = "wasm32")))]
fn font_fallbacks_for_request(
&self,
_request: &FontRequest,
_reference_text: &str,
) -> Vec<FontRequest> {
[
#[cfg(target_arch = "wasm32")]
FontRequest {
family: Some("DejaVu Sans".into()),
weight: _request.weight,
pixel_size: _request.pixel_size,
letter_spacing: _request.letter_spacing,
},
#[cfg(not(target_arch = "wasm32"))]
FontRequest {
family: Some("Noto Color Emoji".into()),
self.fontconfig_fallback_families
.iter()
.map(|family_name| FontRequest {
family: Some(family_name.into()),
weight: _request.weight,
pixel_size: _request.pixel_size,
letter_spacing: _request.letter_spacing,
},
]
})
.filter(|request| self.is_known_family(request))
.collect()
}

#[cfg(target_arch = "wasm32")]
fn font_fallbacks_for_request(
&self,
_request: &FontRequest,
_reference_text: &str,
) -> Vec<FontRequest> {
[FontRequest {
family: Some("DejaVu Sans".into()),
weight: _request.weight,
pixel_size: _request.pixel_size,
letter_spacing: _request.letter_spacing,
}]
.iter()
.filter(|request| self.is_known_family(request))
.cloned()
Expand Down
45 changes: 26 additions & 19 deletions sixtyfps_runtime/rendering_backends/gl/fonts/fontconfig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ LICENSE END */

use fontconfig::fontconfig;

pub fn find_family(requested_family: &str) -> String {
pub fn find_families(requested_family: &str) -> Vec<String> {
unsafe {
let config = fontconfig::FcInitLoadConfigAndFonts();
let family_cstr = std::ffi::CString::new(requested_family).unwrap();
Expand All @@ -21,28 +21,35 @@ pub fn find_family(requested_family: &str) -> String {
let result_set =
fontconfig::FcFontSort(config, pattern, 1, std::ptr::null_mut(), &mut sort_result);

let mut raw_family_name = std::ptr::null_mut();
if fontconfig::FcPatternGetString(
*(*result_set).fonts,
b"family\0".as_ptr() as *const libc::c_char,
0,
&mut raw_family_name,
) != fontconfig::FcResultMatch
{
panic!("FcPatternGetString for family failed. is font-config not configured?")
let mut families = Vec::new();
for idx in 0..(*result_set).nfont {
let mut raw_family_name = std::ptr::null_mut();
if fontconfig::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
{
continue;
}

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())
{
families.push(family_name)
}
}

let family_name = if !raw_family_name.is_null() {
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())
} else {
None
};
fontconfig::FcFontSetDestroy(result_set);
fontconfig::FcPatternDestroy(pattern);
fontconfig::FcConfigDestroy(config);
family_name.expect("FcPatternGetString return an invalid string")
families
}
}

0 comments on commit d2923d5

Please sign in to comment.