1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
use {
crate::{
IntoSfResult, SfResult,
cpp::FBox,
ffi::graphics as ffi,
graphics::{Glyph, Texture},
system::InputStream,
},
std::{
ffi::{CStr, CString},
io::{Read, Seek},
},
};
decl_opaque! {
/// Type for loading and manipulating character fonts.
///
/// Fonts can be loaded from a file, from memory or from a custom stream,
/// and supports the most common types of fonts.
///
/// See the [`from_file`] function for the complete list of supported formats.
///
/// [`from_file`]: Font::from_file
///
/// Once it is loaded, a `Font` instance provides three types of information about the font:
///
/// - Global metrics, such as the line spacing
/// - Per-glyph metrics, such as bounding box or kerning
/// - Pixel representation of glyphs
///
/// Fonts alone are not very useful: they hold the font data but cannot make anything useful of it.
/// To do so you need to use the [`Text`] type, which is able to properly output text with
/// several options such as character size, style, color, position, rotation, etc.
/// This separation allows more flexibility and better performances:
/// indeed a `Font` is a heavy resource, and any operation on it is
/// slow (often too slow for real-time applications).
/// On the other side, a [`Text`] is a lightweight object which can combine the
/// glyphs data and metrics of a `Font` to display any text on a render target.
/// Note that it is also possible to bind several [`Text`] instances to the same `Font`.
///
/// It is important to note that the [`Text`] instance doesn't copy the font that it uses,
/// it only keeps a reference to it.
/// Thus, a `Font` must not be destructed while it is used by a
/// [`Text`] (i.e. never write a function that uses a local `Font` instance for creating a text).
///
/// Apart from loading font files, and passing them to instances of [`Text`],
/// you should normally not have to deal directly with this type.
/// However, it may be useful to access the font metrics or rasterized glyphs for advanced usage.
///
/// Note that if the font is a bitmap font, it is not scalable,
/// thus not all requested sizes will be available to use.
/// This needs to be taken into consideration when using [`Text`].
/// If you need to display text of a certain size, make sure the corresponding bitmap font that
/// supports that size is used.
///
/// [`Text`]: crate::graphics::Text
pub Font;
}
/// Creation and loading
impl Font {
/// Creates a new (empty) font.
pub fn new() -> SfResult<FBox<Self>> {
FBox::new(unsafe { ffi::sfFont_new() }).into_sf_result()
}
/// Creates a new `Font` from a file on the filesystem.
///
/// See [`Self::load_from_file`].
pub fn from_file(path: &str) -> SfResult<FBox<Self>> {
let mut new = Self::new()?;
new.load_from_file(path)?;
Ok(new)
}
/// Creates a new `Font` from font file data in memory.
///
/// See [`Self::load_from_memory`].
///
/// # Safety
///
/// Also see [`Self::load_from_memory`].
pub unsafe fn from_memory(data: &[u8]) -> SfResult<FBox<Self>> {
let mut new = Self::new()?;
unsafe {
new.load_from_memory(data)?;
}
Ok(new)
}
/// Creates a new `Font` from static font file data in memory.
///
/// See [`Self::load_from_memory_static`].
pub fn from_memory_static(data: &'static [u8]) -> SfResult<FBox<Self>> {
let mut new = Self::new()?;
new.load_from_memory_static(data)?;
Ok(new)
}
/// Creates a new `Font` from a streamable source.
///
/// See [`Self::load_from_stream`].
///
/// # Safety
///
/// Also see [`Self::load_from_stream`].
pub unsafe fn from_stream<T: Read + Seek>(stream: &mut T) -> SfResult<FBox<Self>> {
let mut new = Self::new()?;
unsafe {
new.load_from_stream(stream)?;
}
Ok(new)
}
/// Load the font from a file.
///
/// The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, X11 PCF,
/// Windows FNT, BDF, PFR and Type 42.
/// Note that this function know nothing about the standard fonts installed on the
/// user's system, thus you can't load them directly.
///
/// # Warning
/// SFML cannot preload all the font data in this function,
/// so the file has to remain accessible until the `Font` object loads a new font or
/// is destroyed.
///
/// # Usage Example
///
/// ```
/// # use sfml::graphics::Font;
/// let font = match Font::from_file("examples/resources/sansation.ttf") {
/// Ok(font) => font,
/// Err(e) => {
/// panic!("Failed to read font file: {e}");
/// }
/// };
/// ```
pub fn load_from_file(&mut self, path: &str) -> SfResult<()> {
let c_str = CString::new(path)?;
unsafe { ffi::sfFont_loadFromFile(self, c_str.as_ptr()) }.into_sf_result()
}
/// Load the font from a custom stream.
///
/// The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, X11 PCF,
/// Windows FNT, BDF, PFR and Type 42.
///
/// # Safety
/// SFML cannot preload all the font data in this function, so the stream has to remain
/// accessible until the `Font` object loads a new font or is destroyed.
///
/// # See also
/// [`Font::from_file`], [`Font::from_memory`]
pub unsafe fn load_from_stream<T: Read + Seek>(&mut self, stream: &mut T) -> SfResult<()> {
let mut input_stream = InputStream::new(stream);
unsafe { ffi::sfFont_loadFromStream(self, &mut *input_stream.stream) }.into_sf_result()
}
/// Load the font from a file in memory.
///
/// The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, X11 PCF,
/// Windows FNT, BDF, PFR and Type 42.
///
/// # Safety
/// SFML cannot preload all the font data in this function, so the buffer pointed by `memory`
/// has to remain valid until the `Font` object loads a new font or is destroyed.
///
/// For a safe version, see [`Font::from_memory_static`].
///
/// # See also
///
/// [`Font::from_file`], [`Font::from_stream`]
pub unsafe fn load_from_memory(&mut self, data: &[u8]) -> SfResult<()> {
unsafe { ffi::sfFont_loadFromMemory(self, data.as_ptr(), data.len()) }.into_sf_result()
}
/// Load the font from a file in static memory.
///
/// This function is safe because the font will stay in memory as long as required.
///
/// See [`Self::load_from_memory`].
pub fn load_from_memory_static(&mut self, data: &'static [u8]) -> SfResult<()> {
unsafe { self.load_from_memory(data) }
}
}
/// Font information, properties, glyph fetch
impl Font {
/// Get the kerning value corresponding to a given pair of characters in a font
///
/// # Arguments
/// * first - Unicode code point of the first character
/// * second - Unicode code point of the second character
/// * characterSize - Character size, in pixels
///
/// Return the kerning offset, in pixels
///
/// # Usage Example
///
/// ```
/// # use sfml::graphics::Font;
/// # let font = Font::from_file("examples/resources/sansation.ttf").unwrap();
/// let kerning = font.kerning(0, 0, 32);
/// assert_eq!(kerning, 0.);
/// ```
#[must_use]
pub fn kerning(&self, first: u32, second: u32, character_size: u32) -> f32 {
unsafe { ffi::sfFont_getKerning(self, first, second, character_size) }
}
/// Get the bold kerning value corresponding to a given pair of characters in a font
///
/// # Arguments
/// * first - Unicode code point of the first character
/// * second - Unicode code point of the second character
/// * characterSize - Character size, in pixels
///
/// Return the bold kerning offset, in pixels
///
/// # Usage Example
///
/// ```
/// # use sfml::graphics::Font;
/// # let font = Font::from_file("examples/resources/sansation.ttf").unwrap();
/// let kerning = font.bold_kerning(0, 0, 32);
/// assert_eq!(kerning, 0.);
/// ```
#[must_use]
pub fn bold_kerning(&self, first: u32, second: u32, character_size: u32) -> f32 {
unsafe { ffi::sfFont_getBoldKerning(self, first, second, character_size) }
}
/// Get the line spacing value
///
/// # Arguments
/// * characterSize - Character size, in pixels
///
/// Return the line spacing, in pixels
///
/// # Usage Example
///
/// ```
/// # use sfml::graphics::Font;
/// # let font = Font::from_file("examples/resources/sansation.ttf").unwrap();
/// let line_spacing = font.line_spacing(32);
/// assert_eq!(line_spacing, 35.);
/// ```
#[must_use]
pub fn line_spacing(&self, character_size: u32) -> f32 {
unsafe { ffi::sfFont_getLineSpacing(self, character_size) }
}
/// Get a glyph in a font
///
/// # Arguments
/// * codePoint - Unicode code point of the character to get
/// * characterSize - Character size, in pixels
/// * bold - Retrieve the bold version or the regular one?
///
/// Return the corresponding glyph
#[must_use]
pub fn glyph(
&self,
codepoint: u32,
character_size: u32,
bold: bool,
outline_thickness: f32,
) -> Glyph {
unsafe {
Glyph(ffi::sfFont_getGlyph(
self,
codepoint,
character_size,
bold,
outline_thickness,
))
}
}
/// Returns the font information.
///
/// # Usage Example
///
/// ```
/// # use sfml::graphics::Font;
/// let font = Font::from_file("examples/resources/sansation.ttf").unwrap();
/// let font_info = font.info();
/// assert_eq!(font_info.family, "Sansation");
/// ```
#[must_use]
pub fn info(&self) -> Info {
unsafe {
let raw = ffi::sfFont_getInfo(self);
let family = CStr::from_ptr(raw.family).to_string_lossy().into_owned();
Info { family }
}
}
/// Returns the position of the underline.
///
/// # Usage Example
///
/// ```
/// # use sfml::graphics::Font;
/// # let font = Font::from_file("examples/resources/sansation.ttf").unwrap();
/// let underline_position = font.underline_position(32);
/// assert_eq!(underline_position, 3.734375);
/// ```
#[must_use]
pub fn underline_position(&self, character_size: u32) -> f32 {
unsafe { ffi::sfFont_getUnderlinePosition(self, character_size) }
}
/// Returns the thickness of the underline.
///
/// # Usage Example
///
/// ```
/// # use sfml::graphics::Font;
/// # let font = Font::from_file("examples/resources/sansation.ttf").unwrap();
/// let underline_thickness = font.underline_thickness(32);
/// assert_eq!(underline_thickness, 2.34375);
/// ```
#[must_use]
pub fn underline_thickness(&self, character_size: u32) -> f32 {
unsafe { ffi::sfFont_getUnderlineThickness(self, character_size) }
}
}
/// Texture atlas and smoothing
impl Font {
/// Get the texture containing the glyphs of a given size in a font
///
/// # Arguments
/// * `character_size` - Character size, in pixels
#[must_use]
pub fn texture(&self, character_size: u32) -> &Texture {
// # Safety
//
// `getTexture` returns a reference, which is never null or dangling.
unsafe { &*ffi::sfFont_getTexture(self, character_size) }
}
/// Tell whether the smooth filter is enabled or not.
#[must_use]
pub fn is_smooth(&self) -> bool {
unsafe { ffi::sfFont_isSmooth(self) }
}
/// Enable or disable the smooth filter.
///
/// When the filter is activated, the font appears smoother so that pixels are less noticeable.
/// However if you want the font to look exactly the same as its source file,
/// you should disable it. The smooth filter is enabled by default.
///
/// # Arguments
/// * `smooth` - True to enable smoothing, false to disable smoothing
pub fn set_smooth(&mut self, smooth: bool) {
unsafe { ffi::sfFont_setSmooth(self, smooth) }
}
}
impl ToOwned for Font {
type Owned = FBox<Font>;
fn to_owned(&self) -> Self::Owned {
let fnt = unsafe { ffi::sfFont_cpy(self) };
FBox::new(fnt).expect("Failed to copy Font")
}
}
impl Drop for Font {
fn drop(&mut self) {
unsafe { ffi::sfFont_del(self) }
}
}
/// Holds various information about a font.
#[derive(Debug)]
pub struct Info {
/// The font family.
pub family: String,
}