2018-01-15 10:34:59 +03:00
|
|
|
//! Higher level freetype bindings
|
2018-01-17 10:02:32 +03:00
|
|
|
|
2019-05-26 18:58:59 +03:00
|
|
|
use failure::{bail, format_err, Error};
|
2019-03-23 19:28:40 +03:00
|
|
|
pub use freetype::*;
|
2018-01-15 10:34:59 +03:00
|
|
|
use std::ffi::CString;
|
|
|
|
use std::ptr;
|
|
|
|
|
2019-03-23 19:28:40 +03:00
|
|
|
#[inline]
|
|
|
|
pub fn succeeded(error: FT_Error) -> bool {
|
|
|
|
error == freetype::FT_Err_Ok as FT_Error
|
|
|
|
}
|
|
|
|
|
2018-01-15 10:34:59 +03:00
|
|
|
/// Translate an error and value into a result
|
|
|
|
fn ft_result<T>(err: FT_Error, t: T) -> Result<T, Error> {
|
2018-09-20 03:52:34 +03:00
|
|
|
if succeeded(err) {
|
2018-01-15 10:34:59 +03:00
|
|
|
Ok(t)
|
|
|
|
} else {
|
2019-02-26 19:38:51 +03:00
|
|
|
Err(format_err!("FreeType error {:?} 0x{:x}", err, err))
|
2018-01-15 10:34:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Face {
|
|
|
|
pub face: FT_Face,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Face {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
FT_Done_Face(self.face);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Face {
|
|
|
|
pub fn set_char_size(
|
|
|
|
&mut self,
|
|
|
|
char_width: FT_F26Dot6,
|
|
|
|
char_height: FT_F26Dot6,
|
|
|
|
horz_resolution: FT_UInt,
|
|
|
|
vert_resolution: FT_UInt,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
ft_result(
|
|
|
|
unsafe {
|
|
|
|
FT_Set_Char_Size(
|
|
|
|
self.face,
|
|
|
|
char_width,
|
|
|
|
char_height,
|
|
|
|
horz_resolution,
|
|
|
|
vert_resolution,
|
|
|
|
)
|
|
|
|
},
|
|
|
|
(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-09-20 03:52:34 +03:00
|
|
|
#[allow(unused)]
|
2018-01-17 10:02:32 +03:00
|
|
|
pub fn set_pixel_sizes(&mut self, char_width: u32, char_height: u32) -> Result<(), Error> {
|
2018-01-16 09:45:25 +03:00
|
|
|
ft_result(
|
2018-02-21 09:08:19 +03:00
|
|
|
unsafe { FT_Set_Pixel_Sizes(self.face, char_width, char_height) },
|
2018-01-16 09:45:25 +03:00
|
|
|
(),
|
|
|
|
)
|
|
|
|
}
|
2018-01-16 04:32:31 +03:00
|
|
|
|
2018-09-20 03:52:34 +03:00
|
|
|
pub fn select_size(&mut self, idx: usize) -> Result<(), Error> {
|
|
|
|
ft_result(unsafe { FT_Select_Size(self.face, idx as i32) }, ())
|
|
|
|
}
|
|
|
|
|
2018-01-15 10:34:59 +03:00
|
|
|
pub fn load_and_render_glyph(
|
|
|
|
&mut self,
|
|
|
|
glyph_index: FT_UInt,
|
|
|
|
load_flags: FT_Int32,
|
|
|
|
render_mode: FT_Render_Mode,
|
|
|
|
) -> Result<&FT_GlyphSlotRec_, Error> {
|
|
|
|
unsafe {
|
|
|
|
let res = FT_Load_Glyph(self.face, glyph_index, load_flags);
|
2018-09-20 03:52:34 +03:00
|
|
|
if succeeded(res) {
|
2018-01-27 22:15:53 +03:00
|
|
|
let render = FT_Render_Glyph((*self.face).glyph, render_mode);
|
2018-09-20 03:52:34 +03:00
|
|
|
if !succeeded(render) {
|
2018-01-27 22:15:53 +03:00
|
|
|
bail!("FT_Render_Glyph failed: {:?}", render);
|
|
|
|
}
|
2018-01-15 10:34:59 +03:00
|
|
|
}
|
|
|
|
ft_result(res, &*(*self.face).glyph)
|
|
|
|
}
|
|
|
|
}
|
2018-01-16 11:24:49 +03:00
|
|
|
|
2018-01-21 12:32:59 +03:00
|
|
|
pub fn cell_metrics(&mut self) -> (f64, f64) {
|
2018-01-16 11:24:49 +03:00
|
|
|
unsafe {
|
|
|
|
let metrics = &(*(*self.face).size).metrics;
|
2018-03-04 00:00:56 +03:00
|
|
|
let height = (metrics.y_scale as f64 * f64::from((*self.face).height))
|
|
|
|
/ (f64::from(0x1_0000) * 64.0);
|
2018-01-16 11:24:49 +03:00
|
|
|
|
2018-01-21 12:32:59 +03:00
|
|
|
let mut width = 0.0;
|
2018-01-16 11:24:49 +03:00
|
|
|
for i in 32..128 {
|
|
|
|
let glyph_pos = FT_Get_Char_Index(self.face, i);
|
2018-01-17 10:02:32 +03:00
|
|
|
let res = FT_Load_Glyph(self.face, glyph_pos, FT_LOAD_COLOR as i32);
|
2018-09-20 03:52:34 +03:00
|
|
|
if succeeded(res) {
|
2018-01-16 11:24:49 +03:00
|
|
|
let glyph = &(*(*self.face).glyph);
|
2018-01-21 12:32:59 +03:00
|
|
|
if glyph.metrics.horiAdvance as f64 > width {
|
|
|
|
width = glyph.metrics.horiAdvance as f64;
|
|
|
|
}
|
2018-01-16 11:24:49 +03:00
|
|
|
}
|
|
|
|
}
|
2018-01-21 12:32:59 +03:00
|
|
|
(width / 64.0, height)
|
2018-01-16 11:24:49 +03:00
|
|
|
}
|
|
|
|
}
|
2018-01-15 10:34:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Library {
|
|
|
|
lib: FT_Library,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Library {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
FT_Done_FreeType(self.lib);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Library {
|
|
|
|
pub fn new() -> Result<Library, Error> {
|
|
|
|
let mut lib = ptr::null_mut();
|
|
|
|
let res = unsafe { FT_Init_FreeType(&mut lib as *mut _) };
|
|
|
|
let lib = ft_result(res, lib)?;
|
|
|
|
Ok(Library { lib })
|
|
|
|
}
|
|
|
|
|
2019-02-19 09:02:31 +03:00
|
|
|
#[allow(dead_code)]
|
2018-01-17 10:02:32 +03:00
|
|
|
pub fn new_face<P>(&self, path: P, face_index: FT_Long) -> Result<Face, Error>
|
2018-01-15 10:34:59 +03:00
|
|
|
where
|
|
|
|
P: Into<Vec<u8>>,
|
|
|
|
{
|
|
|
|
let mut face = ptr::null_mut();
|
2018-01-16 04:32:31 +03:00
|
|
|
let path = CString::new(path.into())?;
|
2018-01-15 10:34:59 +03:00
|
|
|
|
2018-01-17 10:02:32 +03:00
|
|
|
let res = unsafe { FT_New_Face(self.lib, path.as_ptr(), face_index, &mut face as *mut _) };
|
2018-02-21 09:08:19 +03:00
|
|
|
Ok(Face {
|
|
|
|
face: ft_result(res, face)?,
|
|
|
|
})
|
2018-01-15 10:34:59 +03:00
|
|
|
}
|
|
|
|
|
2019-03-25 21:45:52 +03:00
|
|
|
#[allow(dead_code)]
|
2019-02-18 23:56:41 +03:00
|
|
|
pub fn new_face_from_slice(&self, data: &[u8], face_index: FT_Long) -> Result<Face, Error> {
|
|
|
|
let mut face = ptr::null_mut();
|
|
|
|
|
|
|
|
let res = unsafe {
|
|
|
|
FT_New_Memory_Face(
|
|
|
|
self.lib,
|
|
|
|
data.as_ptr(),
|
2019-02-19 00:13:36 +03:00
|
|
|
data.len() as _,
|
2019-02-18 23:56:41 +03:00
|
|
|
face_index,
|
|
|
|
&mut face as *mut _,
|
|
|
|
)
|
|
|
|
};
|
|
|
|
Ok(Face {
|
|
|
|
face: ft_result(res, face)?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-01-17 10:02:32 +03:00
|
|
|
pub fn set_lcd_filter(&mut self, filter: FT_LcdFilter) -> Result<(), Error> {
|
|
|
|
unsafe { ft_result(FT_Library_SetLcdFilter(self.lib, filter), ()) }
|
2018-01-15 10:34:59 +03:00
|
|
|
}
|
|
|
|
}
|