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
use std::collections::HashMap;
use failure;
use graphics::{
character::{Character, CharacterCache},
types::{FontSize, Scalar},
};
use rusttype::{point, Error, Font, GlyphId, Rect, Scale};
use super::*;
struct CharacterDef {
offset: [Scalar; 2],
size: [Scalar; 2],
texture: RenderBuffer,
}
impl CharacterDef {
fn as_character<'a>(&'a self) -> Character<'a, RenderBuffer> {
Character {
offset: self.offset,
size: self.size,
texture: &self.texture,
}
}
}
pub struct BufferGlyphs<'f> {
characters: HashMap<(char, u32), CharacterDef>,
font: Font<'f>,
}
impl<'f> BufferGlyphs<'f> {
pub fn from_bytes(bytes: &'f [u8]) -> Result<BufferGlyphs<'f>, Error> {
Ok(BufferGlyphs {
characters: HashMap::new(),
font: Font::from_bytes(bytes)?,
})
}
pub fn from_font(font: Font<'f>) -> BufferGlyphs<'f> {
BufferGlyphs {
characters: HashMap::new(),
font,
}
}
}
impl<'f> CharacterCache for BufferGlyphs<'f> {
type Texture = RenderBuffer;
type Error = failure::Error;
fn character<'a>(
&'a mut self,
font_size: FontSize,
ch: char,
) -> Result<Character<'a, Self::Texture>, Self::Error> {
Ok(self
.characters
.entry((ch, font_size))
.or_insert({
let scale = Scale::uniform(font_size as f32);
let glyph = self.font.glyph(ch).scaled(scale);
let glyph = if glyph.id() == GlyphId(0) && glyph.shape().is_none() {
self.font.glyph('\u{FFFD}').scaled(scale)
} else {
glyph
};
let h_metrics = glyph.h_metrics();
let bounding_box = glyph.exact_bounding_box().unwrap_or(Rect {
min: point(0.0, 0.0),
max: point(0.0, 0.0),
});
let glyph = glyph.positioned(point(0.0, 0.0));
let pixel_bounding_box = glyph.pixel_bounding_box().unwrap_or(Rect {
min: point(0, 0),
max: point(0, 0),
});
let pixel_bb_width = pixel_bounding_box.width() + 2;
let pixel_bb_height = pixel_bounding_box.height() + 2;
let mut texture = RenderBuffer::new(pixel_bb_width as u32, pixel_bb_height as u32);
glyph.draw(|x, y, v| {
texture.set_pixel(x, y, [1.0, 1.0, 1.0, v]);
});
CharacterDef {
offset: [
bounding_box.min.x as Scalar - 1.0,
-pixel_bounding_box.min.y as Scalar + 1.0,
],
size: [h_metrics.advance_width as Scalar, 0 as Scalar],
texture,
}
})
.as_character())
}
fn width(&mut self, size: FontSize, text: &str) -> Result<Scalar, Self::Error> {
text.chars().fold(Ok(0.0), |sum, c| {
if let Ok(s) = sum {
if let Ok(ch) = self.character(size, c) {
Ok(s + ch.width())
} else {
sum
}
} else {
sum
}
})
}
}