]> git.seodisparate.com - mpd_info_screen/commitdiff
Refactor freetype handling code to be safer
authorStephen Seo <seo.disparate@gmail.com>
Mon, 1 Aug 2022 07:20:34 +0000 (16:20 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Mon, 1 Aug 2022 07:20:34 +0000 (16:20 +0900)
src/unicode_support/freetype.rs

index 1bfe079a4a4a772f6d228fea7625d40b1e2dfdd8..d7a0fc5d57716dc43db40867dc64d564653a3557 100644 (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,71 +47,13 @@ mod ffi {
         pub fn get(&self) -> FT_Library {
             self.library
         }
-    }
-
-    pub struct FTOpenArgs {
-        args: FT_Open_Args,
-        // "args" has a pointer to the CString in "pathname", so it must be kept
-        #[allow(dead_code)]
-        pathname: Option<CString>,
-    }
 
-    impl FTOpenArgs {
-        pub fn new_with_path(path: &Path) -> Self {
-            unsafe {
-                let cstring: CString = CString::from_vec_unchecked(
-                    path.as_os_str().to_str().unwrap().as_bytes().to_vec(),
-                );
-                let args = FT_Open_Args {
-                    flags: FT_OPEN_PATHNAME,
-                    memory_base: std::ptr::null::<u8>(),
-                    memory_size: 0,
-                    pathname: cstring.as_ptr() as *mut i8,
-                    stream: std::ptr::null_mut::<FT_StreamRec_>(),
-                    driver: std::ptr::null_mut::<FT_ModuleRec_>(),
-                    num_params: 0,
-                    params: std::ptr::null_mut::<FT_Parameter_>(),
-                };
-
-                FTOpenArgs {
-                    args,
-                    pathname: Some(cstring),
-                }
-            }
-        }
-
-        #[allow(dead_code)]
-        pub fn get_args(&self) -> FT_Open_Args {
-            self.args
-        }
-
-        pub fn get_ptr(&mut self) -> *mut FT_Open_Args {
-            &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() };
+        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(
-                    library.get(),
+                    self.get(),
                     args.get_ptr(),
                     -1,
                     &mut face as *mut *mut FT_FaceRec_,
@@ -117,7 +66,7 @@ mod ffi {
 
                 for i in 0..count {
                     result = FT_Open_Face(
-                        library.get(),
+                        self.get(),
                         args.get_ptr(),
                         i,
                         &mut face as *mut *mut FT_FaceRec_,
@@ -126,11 +75,21 @@ mod ffi {
                         FT_Done_Face(face);
                         return Err(String::from("Failed to fetch face"));
                     }
-                    faces.faces.push(face);
+                    self.faces.push(face);
                 }
             }
 
-            Ok(faces)
+            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 {
@@ -148,12 +107,54 @@ mod ffi {
             false
         }
     }
+
+    pub struct FTOpenArgs {
+        args: FT_Open_Args,
+        // "args" has a pointer to the CString in "pathname", so it must be kept
+        #[allow(dead_code)]
+        pathname: Option<CString>,
+    }
+
+    impl FTOpenArgs {
+        pub fn new_with_path(path: &Path) -> Self {
+            unsafe {
+                let cstring: CString = CString::from_vec_unchecked(
+                    path.as_os_str().to_str().unwrap().as_bytes().to_vec(),
+                );
+                let args = FT_Open_Args {
+                    flags: FT_OPEN_PATHNAME,
+                    memory_base: std::ptr::null::<u8>(),
+                    memory_size: 0,
+                    pathname: cstring.as_ptr() as *mut i8,
+                    stream: std::ptr::null_mut::<FT_StreamRec_>(),
+                    driver: std::ptr::null_mut::<FT_ModuleRec_>(),
+                    num_params: 0,
+                    params: std::ptr::null_mut::<FT_Parameter_>(),
+                };
+
+                FTOpenArgs {
+                    args,
+                    pathname: Some(cstring),
+                }
+            }
+        }
+
+        #[allow(dead_code)]
+        pub fn get_args(&self) -> FT_Open_Args {
+            self.args
+        }
+
+        pub fn get_ptr(&mut self) -> *mut FT_Open_Args {
+            &mut self.args as *mut FT_Open_Args
+        }
+    }
 }
 
 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))
 }