Refactor freetype handling code to be safer

This commit is contained in:
Stephen Seo 2022-08-01 16:20:34 +09:00
parent a58121741f
commit dda5b15aa4

View file

@ -11,10 +11,16 @@ mod ffi {
pub struct FTLibrary {
library: FT_Library,
faces: Vec<FT_Face>,
}
impl Drop for FTLibrary {
fn drop(&mut self) {
for face in &self.faces {
unsafe {
FT_Done_Face(*face);
}
}
if !self.library.is_null() {
unsafe {
FT_Done_FreeType(self.library);
@ -30,6 +36,7 @@ mod ffi {
if FT_Init_FreeType(&mut library_ptr) == 0 {
Some(FTLibrary {
library: library_ptr,
faces: Vec::new(),
})
} else {
None
@ -40,6 +47,65 @@ mod ffi {
pub fn get(&self) -> FT_Library {
self.library
}
pub fn init_faces(&mut self, args: &mut FTOpenArgs) -> Result<(), String> {
unsafe {
let mut face: FT_Face = 0 as FT_Face;
// first get number of faces
let mut result = FT_Open_Face(
self.get(),
args.get_ptr(),
-1,
&mut face as *mut *mut FT_FaceRec_,
);
if result != 0 {
FT_Done_Face(face);
return Err(String::from("Failed to get number of faces"));
}
let count = (*face).num_faces;
for i in 0..count {
result = FT_Open_Face(
self.get(),
args.get_ptr(),
i,
&mut face as *mut *mut FT_FaceRec_,
);
if result != 0 {
FT_Done_Face(face);
return Err(String::from("Failed to fetch face"));
}
self.faces.push(face);
}
}
Ok(())
}
#[allow(dead_code)]
pub fn drop_faces(&mut self) {
for face in &self.faces {
unsafe {
FT_Done_Face(*face);
}
}
self.faces.clear();
}
pub fn has_char(&self, c: char) -> bool {
let char_value: u64 = c as u64;
for face in &self.faces {
unsafe {
let result = FT_Get_Char_Index(*face, char_value);
if result != 0 {
return true;
}
}
}
false
}
}
pub struct FTOpenArgs {
@ -82,78 +148,13 @@ mod ffi {
&mut self.args as *mut FT_Open_Args
}
}
pub struct FTFaces {
faces: Vec<FT_Face>,
}
impl Drop for FTFaces {
fn drop(&mut self) {
for face in &self.faces {
unsafe {
FT_Done_Face(*face);
}
}
}
}
impl FTFaces {
pub fn new(library: &FTLibrary, args: &mut FTOpenArgs) -> Result<FTFaces, String> {
let mut faces = FTFaces { faces: Vec::new() };
unsafe {
let mut face: FT_Face = 0 as FT_Face;
// first get number of faces
let mut result = FT_Open_Face(
library.get(),
args.get_ptr(),
-1,
&mut face as *mut *mut FT_FaceRec_,
);
if result != 0 {
FT_Done_Face(face);
return Err(String::from("Failed to get number of faces"));
}
let count = (*face).num_faces;
for i in 0..count {
result = FT_Open_Face(
library.get(),
args.get_ptr(),
i,
&mut face as *mut *mut FT_FaceRec_,
);
if result != 0 {
FT_Done_Face(face);
return Err(String::from("Failed to fetch face"));
}
faces.faces.push(face);
}
}
Ok(faces)
}
pub fn has_char(&self, c: char) -> bool {
let char_value: u64 = c as u64;
for face in &self.faces {
unsafe {
let result = FT_Get_Char_Index(*face, char_value);
if result != 0 {
return true;
}
}
}
false
}
}
}
pub fn font_has_char(c: char, font_path: &Path) -> Result<bool, String> {
let library = ffi::FTLibrary::new().ok_or_else(|| String::from("Failed to get FTLibrary"))?;
let mut library =
ffi::FTLibrary::new().ok_or_else(|| String::from("Failed to get FTLibrary"))?;
let mut args = ffi::FTOpenArgs::new_with_path(font_path);
let faces = ffi::FTFaces::new(&library, &mut args)?;
library.init_faces(&mut args)?;
Ok(faces.has_char(c))
Ok(library.has_char(c))
}