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
use { freetype, graphics };
use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::rc::Rc;
use std::path::Path;
use error::Error;
use Texture;
pub type FontSize = u32;
pub type Character = graphics::character::Character<Texture>;
#[derive(Clone)]
pub struct GlyphCache<'a> {
pub face: freetype::Face<'a>,
data: HashMap<FontSize, HashMap<char, Rc<Character>>>,
}
impl<'a> GlyphCache<'a> {
pub fn new(font: &Path) -> Result<GlyphCache<'static>, Error> {
let freetype = match freetype::Library::init() {
Ok(freetype) => freetype,
Err(why) => return Err(Error::FreetypeError(why)),
};
let face = match freetype.new_face(font, 0) {
Ok(face) => face,
Err(why) => return Err(Error::FreetypeError(why)),
};
Ok(GlyphCache {
face: face,
data: HashMap::new(),
})
}
pub fn from_bytes(font: &'a [u8]) -> Result<GlyphCache<'a>, Error> {
let freetype = match freetype::Library::init() {
Ok(freetype) => freetype,
Err(why) => return Err(Error::FreetypeError(why))
};
let face = match freetype.new_memory_face(font, 0) {
Ok(face) => face,
Err(why) => return Err(Error::FreetypeError(why))
};
Ok(GlyphCache {
face: face,
data: HashMap::new()
})
}
fn load_character(&mut self, size: FontSize, ch: char) {
if self.data.get(&size)
.map(|entry| entry.contains_key(&ch))
.unwrap_or(false) { return }
self.face.set_pixel_sizes(0, size).unwrap();
self.face.load_char(ch as usize, freetype::face::DEFAULT).unwrap();
let glyph = self.face.glyph().get_glyph().unwrap();
let bitmap_glyph = glyph.to_bitmap(freetype::render_mode::RenderMode::Normal, None)
.unwrap();
let bitmap = bitmap_glyph.bitmap();
let texture = Texture::from_memory_alpha(bitmap.buffer(),
bitmap.width() as u32,
bitmap.rows() as u32).unwrap();
let glyph_size = glyph.advance();
self.data.get_mut(&size).unwrap().insert(ch, Rc::new(Character {
offset: [
bitmap_glyph.left() as f64,
bitmap_glyph.top() as f64
],
size: [
(glyph_size.x >> 16) as f64,
(glyph_size.y >> 16) as f64
],
texture: texture,
}));
}
pub fn preload_chars<I>(
&mut self,
size: FontSize,
chars: I
)
where
I: Iterator<Item = char>
{
for ch in chars {
self.load_character(size, ch);
}
}
pub fn preload_printable_ascii(&mut self, size: FontSize) {
self.preload_chars(size, (0x20u8 .. 0x7F).map(|ch| ch as char));
}
pub fn opt_character(&self, size: FontSize, ch: char) -> Option<&Character> {
use std::borrow::Borrow;
self.data.get(&size).and_then(|entry| entry.get(&ch).map(|e| e.borrow()))
}
}
impl<'a> graphics::character::CharacterCache for GlyphCache<'a> {
type Texture = Texture;
fn character(&mut self, size: FontSize, ch: char) -> &Character {
match {
match self.data.entry(size) {
Vacant(entry) => entry.insert(HashMap::new()),
Occupied(entry) => entry.into_mut(),
}
}.contains_key(&ch) {
true => &self.data[&size][&ch],
false => { self.load_character(size, ch); &self.data[&size][&ch] }
}
}
}