use std::os::raw::{c_long, c_void};
use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::OnceLock;
use freetype_sys::{
FT_Add_Default_Modules, FT_Done_Library, FT_Library, FT_Memory, FT_MemoryRec, FT_New_Library,
};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use parking_lot::Mutex;
use servo_allocator::libc_compat::{free, malloc, realloc};
use servo_allocator::usable_size;
static FREETYPE_MEMORY_USAGE: AtomicUsize = AtomicUsize::new(0);
static FREETYPE_LIBRARY_HANDLE: OnceLock<Mutex<FreeTypeLibraryHandle>> = OnceLock::new();
extern "C" fn ft_alloc(_: FT_Memory, req_size: c_long) -> *mut c_void {
unsafe {
let pointer = malloc(req_size as usize);
FREETYPE_MEMORY_USAGE.fetch_add(usable_size(pointer), Ordering::Relaxed);
pointer
}
}
extern "C" fn ft_free(_: FT_Memory, pointer: *mut c_void) {
unsafe {
FREETYPE_MEMORY_USAGE.fetch_sub(usable_size(pointer), Ordering::Relaxed);
free(pointer as *mut _);
}
}
extern "C" fn ft_realloc(
_: FT_Memory,
_old_size: c_long,
new_req_size: c_long,
old_pointer: *mut c_void,
) -> *mut c_void {
unsafe {
FREETYPE_MEMORY_USAGE.fetch_sub(usable_size(old_pointer), Ordering::Relaxed);
let new_pointer = realloc(old_pointer, new_req_size as usize);
FREETYPE_MEMORY_USAGE.fetch_add(usable_size(new_pointer), Ordering::Relaxed);
new_pointer
}
}
#[derive(Clone, Debug)]
pub(crate) struct FreeTypeLibraryHandle {
pub freetype_library: FT_Library,
freetype_memory: FT_Memory,
}
unsafe impl Sync for FreeTypeLibraryHandle {}
unsafe impl Send for FreeTypeLibraryHandle {}
impl Drop for FreeTypeLibraryHandle {
#[allow(unused)]
fn drop(&mut self) {
assert!(!self.freetype_library.is_null());
unsafe {
FT_Done_Library(self.freetype_library);
Box::from_raw(self.freetype_memory);
}
}
}
impl MallocSizeOf for FreeTypeLibraryHandle {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
unsafe {
FREETYPE_MEMORY_USAGE.load(Ordering::Relaxed) +
ops.malloc_size_of(self.freetype_library as *const _) +
ops.malloc_size_of(self.freetype_memory as *const _)
}
}
}
impl FreeTypeLibraryHandle {
pub(crate) fn get() -> &'static Mutex<FreeTypeLibraryHandle> {
FREETYPE_LIBRARY_HANDLE.get_or_init(|| {
let freetype_memory = Box::into_raw(Box::new(FT_MemoryRec {
user: ptr::null_mut(),
alloc: ft_alloc,
free: ft_free,
realloc: ft_realloc,
}));
unsafe {
let mut freetype_library: FT_Library = ptr::null_mut();
let result = FT_New_Library(freetype_memory, &mut freetype_library);
if 0 != result {
panic!("Unable to initialize FreeType library");
}
FT_Add_Default_Modules(freetype_library);
Mutex::new(FreeTypeLibraryHandle {
freetype_library,
freetype_memory,
})
}
})
}
}