1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-10 15:04:32 +03:00

fonts: manage fontconfig and freetype associated files better

I noticed a lot of things bleeding into the process and its children,
so work a bit harder to trim the resource usage back
This commit is contained in:
Wez Furlong 2019-12-14 15:22:47 -08:00
parent 990d12fdf4
commit 50f72c43b3
2 changed files with 72 additions and 6 deletions

View File

@ -7,9 +7,48 @@ use std::fmt;
use std::mem;
use std::os::raw::c_int;
use std::ptr;
use std::sync::Mutex;
static FC_MONO: i32 = 100;
lazy_static::lazy_static! {
/// This is hideous and gross, but we don't have a lot of choice.
/// The issue here is that the fontconfig library maintains some
/// global state that is implicitly initialized by the various
/// library functions. There isn't a way for a single code path
/// to maintain an isolated set of state. In wezterm we only
/// use fontconfig to discover files and then we don't need to
/// talk to it again, so it is desirable to have it unload its
/// various caches and references to fonts when we're done with
/// it. We use this counter to tell when we've released the
/// final reference to a fontconfig object so that we can tell
/// the library to shutdown.
static ref NUM_OBJECTS :Mutex<usize> = Mutex::new(0);
}
fn add_object() {
let mut num = NUM_OBJECTS.lock().unwrap();
*num = *num + 1;
log::trace!("fc object count + -> {}", *num);
}
fn release_object() {
let mut num = NUM_OBJECTS.lock().unwrap();
let count = *num - 1;
*num = count;
log::trace!("fc object count - -> {}", *num);
if count == 0 {
log::trace!("Finalize fontconfig!");
// There are no more objects referencing the fontconfig
// library, so we can release it now
unsafe {
FcFini();
}
}
}
pub struct FontSet {
fonts: *mut FcFontSet,
}
@ -19,6 +58,7 @@ impl Drop for FontSet {
unsafe {
FcFontSetDestroy(self.fonts);
}
release_object();
}
}
@ -47,6 +87,7 @@ impl<'a> Iterator for FontSetIter<'a> {
.as_mut()
.unwrap();
FcPatternReference(pat);
add_object();
self.position += 1;
Some(Pattern { pat })
}
@ -106,6 +147,7 @@ impl Pattern {
unsafe {
let p = FcPatternCreate();
ensure!(!p.is_null(), "FcPatternCreate failed");
add_object();
Ok(Pattern { pat: p })
}
}
@ -177,6 +219,7 @@ impl Pattern {
unsafe {
let pat = FcFontRenderPrepare(ptr::null_mut(), self.pat, pat.pat);
ensure!(!pat.is_null(), "failed to prepare pattern");
add_object();
Ok(Pattern { pat })
}
}
@ -208,6 +251,9 @@ impl Pattern {
&mut res.0 as *mut _,
);
if !fonts.is_null() {
add_object();
}
res.result(FontSet { fonts })
}
}
@ -279,6 +325,7 @@ impl Drop for Pattern {
unsafe {
FcPatternDestroy(self.pat);
}
release_object();
}
}

View File

@ -3,7 +3,6 @@
use crate::font::locator::FontDataHandle;
use failure::{bail, format_err, Error, Fallible, ResultExt};
pub use freetype::*;
use std::ffi::CString;
use std::ptr;
#[inline]
@ -203,15 +202,35 @@ impl Library {
#[allow(dead_code)]
pub fn new_face<P>(&self, path: P, face_index: FT_Long) -> Result<Face, Error>
where
P: Into<Vec<u8>>,
P: AsRef<std::path::Path>,
{
let mut face = ptr::null_mut();
let path = CString::new(path.into())?;
let path = path.as_ref();
let res = unsafe { FT_New_Face(self.lib, path.as_ptr(), face_index, &mut face as *mut _) };
// We open the file for ourselves and treat it as a memory based
// face because freetype doesn't use O_CLOEXEC and keeps the fd
// floating around for a long time!
let data = std::fs::read(path)?;
log::error!("Loading {} for freetype!", path.display());
let res = unsafe {
FT_New_Memory_Face(
self.lib,
data.as_ptr(),
data.len() as _,
face_index,
&mut face as *mut _,
)
};
Ok(Face {
face: ft_result(res, face).context("FT_New_Face")?,
_bytes: Vec::new(),
face: ft_result(res, face).map_err(|e| {
e.context(format!(
"FT_New_Memory_Face for {} index {}",
path.display(),
face_index
))
})?,
_bytes: data,
})
}