1use core::fmt;
2use core::marker::PhantomData;
3use Nul;
4use {ffi, FtResult, GlyphSlot, Matrix, Vector};
5
6#[repr(u32)]
7#[derive(Copy, Clone)]
8pub enum KerningMode {
9 KerningDefault = ffi::FT_KERNING_DEFAULT,
10 KerningUnfitted = ffi::FT_KERNING_UNFITTED,
11 KerningUnscaled = ffi::FT_KERNING_UNSCALED,
12}
13
14bitflags! {
15 pub struct LoadFlag: i32 {
16 const DEFAULT = ::ffi::FT_LOAD_DEFAULT;
17 const NO_SCALE = ::ffi::FT_LOAD_NO_SCALE;
18 const NO_HINTING = ::ffi::FT_LOAD_NO_HINTING;
19 const RENDER = ::ffi::FT_LOAD_RENDER;
20 const NO_BITMAP = ::ffi::FT_LOAD_NO_BITMAP;
21 const VERTICAL_LAYOUT = ::ffi::FT_LOAD_VERTICAL_LAYOUT;
22 const FORCE_AUTOHINT = ::ffi::FT_LOAD_FORCE_AUTOHINT;
23 const CROP_BITMAP = ::ffi::FT_LOAD_CROP_BITMAP;
24 const PEDANTIC = ::ffi::FT_LOAD_PEDANTIC;
25 const IGNORE_GLOBAL_ADVANCE_WITH = ::ffi::FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
26 const NO_RECURSE = ::ffi::FT_LOAD_NO_RECURSE;
27 const IGNORE_TRANSFORM = ::ffi::FT_LOAD_IGNORE_TRANSFORM;
28 const MONOCHROME = ::ffi::FT_LOAD_MONOCHROME;
29 const LINEAR_DESIGN = ::ffi::FT_LOAD_LINEAR_DESIGN;
30 const NO_AUTOHINT = ::ffi::FT_LOAD_NO_AUTOHINT;
31 const TARGET_NORMAL = ::ffi::FT_LOAD_TARGET_NORMAL;
32 const TARGET_LIGHT = ::ffi::FT_LOAD_TARGET_LIGHT;
33 const TARGET_MONO = ::ffi::FT_LOAD_TARGET_MONO;
34 const TARGET_LCD = ::ffi::FT_LOAD_TARGET_LCD;
35 const TARGET_LCD_V = ::ffi::FT_LOAD_TARGET_LCD_V;
36 const COLOR = ::ffi::FT_LOAD_COLOR;
37 }
38}
39
40bitflags! {
41 pub struct StyleFlag: ffi::FT_Long {
42 const BOLD = ::ffi::FT_STYLE_FLAG_BOLD;
43 const ITALIC = ::ffi::FT_STYLE_FLAG_ITALIC;
44 }
45}
46
47#[derive(Eq, PartialEq, Hash)]
48pub struct Face<'a> {
49 library_raw: ffi::FT_Library,
50 raw: ffi::FT_Face,
51 glyph: GlyphSlot,
52 _phantom: PhantomData<&'a ()>
53}
54
55impl<'a> ::fallible::TryClone for Face<'a> {
56 type Error = ::error::Error;
57 fn try_clone(&self) -> FtResult<Self> { unsafe {
58 ::error::from_ftret(ffi::FT_Reference_Library(self.library_raw))?;
59 ::error::from_ftret(ffi::FT_Reference_Face(self.raw))?;
60 Ok(Face { ..*self })
61 } }
62}
63
64impl<'a> Face<'a> {
65 pub unsafe fn from_raw(library_raw: ffi::FT_Library, raw: ffi::FT_Face) -> Self {
66 ffi::FT_Reference_Library(library_raw);
67 Face {
68 library_raw, raw,
69 glyph: GlyphSlot::from_raw(library_raw, (*raw).glyph),
70 _phantom: PhantomData
71 }
72 }
73
74 pub fn attach_file(&self, filepathname: &str) -> FtResult<()> {
75 ::error::from_ftret(unsafe { ffi::FT_Attach_File(self.raw, filepathname.as_ptr() as *const _) })
76 }
77
78 pub fn reference(&self) -> FtResult<()> {
79 ::error::from_ftret(unsafe { ffi::FT_Reference_Face(self.raw) })
80 }
81
82 pub fn set_char_size(&self, char_width: isize, char_height: isize, horz_resolution: u32,
83 vert_resolution: u32) -> FtResult<()> {
84 ::error::from_ftret(unsafe {
85 ffi::FT_Set_Char_Size(self.raw, char_width as ffi::FT_F26Dot6,
86 char_height as ffi::FT_F26Dot6, horz_resolution,
87 vert_resolution)
88 })
89 }
90
91 pub fn set_pixel_sizes(&self, pixel_width: u32, pixel_height: u32) -> FtResult<()> {
92 ::error::from_ftret(unsafe { ffi::FT_Set_Pixel_Sizes(self.raw, pixel_width, pixel_height) })
93 }
94
95 pub fn load_glyph(&self, glyph_index: u32, load_flags: LoadFlag) -> FtResult<()> {
96 ::error::from_ftret(unsafe { ffi::FT_Load_Glyph(self.raw, glyph_index, load_flags.bits) })
97 }
98
99 pub fn load_char(&self, char_code: usize, load_flags: LoadFlag) -> FtResult<()> {
100 ::error::from_ftret(unsafe { ffi::FT_Load_Char(self.raw, char_code as ffi::FT_ULong, load_flags.bits) })
101 }
102
103 pub fn set_transform(&self, matrix: &mut Matrix, delta: &mut Vector) {
104 unsafe { ffi::FT_Set_Transform(self.raw, matrix, delta); }
105 }
106
107 pub fn get_char_index(&self, charcode: usize) -> u32 {
108 unsafe { ffi::FT_Get_Char_Index(self.raw, charcode as ffi::FT_ULong) }
109 }
110
111 pub fn get_kerning(&self, left_char_index: u32, right_char_index: u32, kern_mode: KerningMode)
112 -> FtResult<Vector> {
113 let mut vec = Vector { x: 0, y: 0 };
114
115 ::error::from_ftret(unsafe {
116 ffi::FT_Get_Kerning(self.raw, left_char_index, right_char_index,
117 kern_mode as u32, &mut vec)
118 })?;
119 Ok(vec)
120 }
121
122 #[inline(always)]
125 pub fn glyph(&self) -> &GlyphSlot { &self.glyph }
126
127 #[inline(always)]
128 pub fn has_horizontal(&self) -> bool {
129 ffi::FT_HAS_HORIZONTAL(self.raw)
130 }
131
132 #[inline(always)]
133 pub fn has_vertical(&self) -> bool {
134 ffi::FT_HAS_VERTICAL(self.raw)
135 }
136
137 #[inline(always)]
138 pub fn has_kerning(&self) -> bool {
139 ffi::FT_HAS_KERNING(self.raw)
140 }
141
142 #[inline(always)]
143 pub fn is_scalable(&self) -> bool {
144 ffi::FT_IS_SCALABLE(self.raw)
145 }
146
147 #[inline(always)]
148 pub fn is_sfnt(&self) -> bool {
149 ffi::FT_IS_SFNT(self.raw)
150 }
151
152 #[inline(always)]
153 pub fn is_fixed_width(&self) -> bool {
154 ffi::FT_IS_FIXED_WIDTH(self.raw)
155 }
156
157 #[inline(always)]
158 pub fn has_fixed_sizes(&self) -> bool {
159 ffi::FT_HAS_FIXED_SIZES(self.raw)
160 }
161
162 #[inline(always)]
163 pub fn has_glyph_names(&self) -> bool {
164 ffi::FT_HAS_GLYPH_NAMES(self.raw)
165 }
166
167 #[inline(always)]
168 pub fn is_cid_keyed(&self) -> bool {
169 ffi::FT_IS_CID_KEYED(self.raw)
170 }
171
172 #[inline(always)]
173 pub fn is_tricky(&self) -> bool {
174 ffi::FT_IS_TRICKY(self.raw)
175 }
176
177 #[inline(always)]
178 pub fn has_color(&self) -> bool {
179 ffi::FT_HAS_COLOR(self.raw)
180 }
181
182 #[inline(always)]
183 pub fn raw(&self) -> &ffi::FT_FaceRec {
184 unsafe { &*self.raw }
185 }
186
187 #[inline(always)]
188 pub fn raw_mut(&mut self) -> &mut ffi::FT_FaceRec {
189 unsafe { &mut *self.raw }
190 }
191
192 #[inline(always)]
193 pub fn ascender(&self) -> ffi::FT_Short {
194 unsafe { (*self.raw).ascender }
195 }
196
197 #[inline(always)]
198 pub fn descender(&self) -> ffi::FT_Short {
199 unsafe { (*self.raw).descender }
200 }
201
202 #[inline(always)]
203 pub fn em_size(&self) -> ffi::FT_Short {
204 unsafe { (*self.raw).units_per_EM as i16 }
205 }
206
207 #[inline(always)]
208 pub fn height(&self) -> ffi::FT_Short {
209 unsafe { (*self.raw).height }
210 }
211
212 #[inline(always)]
213 pub fn max_advance_width(&self) -> ffi::FT_Short {
214 unsafe { (*self.raw).max_advance_width }
215 }
216
217 #[inline(always)]
218 pub fn max_advance_height(&self) -> ffi::FT_Short {
219 unsafe { (*self.raw).max_advance_height }
220 }
221
222 #[inline(always)]
223 pub fn underline_position(&self) -> ffi::FT_Short {
224 unsafe { (*self.raw).underline_position }
225 }
226
227 #[inline(always)]
228 pub fn underline_thickness(&self) -> ffi::FT_Short {
229 unsafe { (*self.raw).underline_thickness }
230 }
231
232 #[inline(always)]
233 pub fn num_faces(&self) -> i16 { unsafe { (*self.raw).num_faces as i16 } }
234
235 pub fn family_name(&self) -> Option<&Nul<u8>> {
236 unsafe { ((*self.raw).family_name as *mut u8).as_ref() }
237 .map(|p| unsafe { Nul::new_unchecked(p) })
238 }
239
240 pub fn style_name(&self) -> Option<&Nul<u8>> {
241 unsafe { ((*self.raw).style_name as *mut u8).as_ref() }
242 .map(|p| unsafe { Nul::new_unchecked(p) })
243 }
244
245 pub fn style_flags(&self) -> StyleFlag {
246 StyleFlag::from_bits_truncate(unsafe { (*self.raw).style_flags })
247 }
248
249 pub fn size_metrics(&self) -> Option<ffi::FT_Size_Metrics> {
250 if self.raw.is_null() {
251 None
252 } else {
253 let size = unsafe { (*self.raw).size };
254 if size.is_null() {
255 None
256 } else {
257 Some(unsafe { (*size).metrics })
258 }
259 }
260 }
261
262 pub fn postscript_name(&self) -> Option<&Nul<u8>> {
263 unsafe { (ffi::FT_Get_Postscript_Name(self.raw) as *mut u8).as_ref() }
264 .map(|p| unsafe { Nul::new_unchecked(p) })
265 }
266}
267
268impl<'a> fmt::Debug for Face<'a> {
269 fn fmt(&self, form: &mut fmt::Formatter) -> fmt::Result {
270 let name = self.style_name()
271 .and_then(|s| ::core::str::from_utf8(&s[..]).ok())
272 .unwrap_or("[unknown name]");
273 form.write_str("Font Face: ")?;
274 form.write_str(&name[..])
275 }
276}
277
278impl<'a> Drop for Face<'a> {
279 fn drop(&mut self) { unsafe {
280 ::error::from_ftret(ffi::FT_Done_Face(self.raw)).expect("Failed to drop face");
281 ::error::from_ftret(ffi::FT_Done_Library(self.library_raw)).expect("Failed to drop library");
282 } }
283}