1#![deny(missing_docs)]
2
3use std::collections::HashMap;
4use super::rasterize::{Font, Bitmap, Atlas, CharInfo};
5use super::glyph_packer;
6use void::Void;
7
8#[derive(Debug)]
14pub struct FontCache<T> {
15 base_font: HashMap<String, Font>,
16 cached: Vec<(String, f32, FaceCache<T>)>,
17}
18
19#[derive(Debug)]
21pub struct FaceCache<T> {
22 font: Font,
23 bitmap: T,
24 scale: f32,
25 atlas: Atlas,
26 missing: HashMap<char, Option<T>>,
27 missing_info: HashMap<char, CharInfo>,
28 line_height: f32,
29}
30
31#[derive(Debug)]
34pub struct DrawCommand<'a, T: 'a> {
35 pub bitmap: &'a T,
37 pub bitmap_location: glyph_packer::Rect,
39 pub draw_location: (f32, f32),
41}
42
43#[derive(Debug)]
46pub enum FontCacheError<E> {
47 UserError(E),
49 NoLoadedFont(String),
51 NoRenderedFace(String, f32),
53 MissingGlyph(char),
55}
56
57impl <T> FontCache<T> {
58 pub fn new() -> FontCache<T> {
60 FontCache {
61 base_font: HashMap::new(),
62 cached: Vec::new(),
63 }
64 }
65
66 pub fn load_font<S: Into<String>>(&mut self, name: S, font: Font) {
70 self.base_font.insert(name.into(), font);
71 }
72
73 pub fn create_face<I, F, E>(&mut self, name: &str, scale: f32, chars: I, f: F) -> Result<(), FontCacheError<E>>
80 where I: Iterator<Item=char>, F: Fn(Bitmap) -> Result<T, E> {
81 if self.cached.iter().any(|&(ref n, s, _)| n == name && scale == s) {
82 return Ok(());
83 }
84
85 match self.base_font.get(name).cloned() {
86 Some(font) => {
87 let fc = try!(FaceCache::new(font, scale, chars, f).or_else(|e| Err(FontCacheError::UserError(e))));
88 self.cached.push((name.into(), scale, fc));
89 return Ok(());
90 }
91 None => return Err(FontCacheError::NoLoadedFont(name.into()))
92 };
93 }
94
95 pub fn get_face_cache(&self, name: &str, scale: f32) -> Option<&FaceCache<T>> {
97 self.cached.iter()
98 .filter(|&&(ref n, s, _)| n == name && scale == s)
99 .map(|&(_, _, ref fc)| fc)
100 .next()
101 }
102
103 pub fn get_face_cache_mut(&mut self, name: &str, scale: f32) -> Option<&mut FaceCache<T>> {
105 self.cached.iter_mut()
106 .filter(|&&mut (ref n, s, _)| n == name && scale == s)
107 .map(|&mut (_, _, ref mut fc)| fc)
108 .next()
109 }
110
111 pub fn drawing_commands(&self, font_name: &str, scale: f32, string: &str) -> Result<Vec<DrawCommand<T>>, FontCacheError<Void>> {
115 let fc = try!(self.get_face_cache(font_name, scale).ok_or(FontCacheError::NoRenderedFace(font_name.into(), scale)));
116 fc.drawing_commands(string)
117 }
118
119 pub fn drawing_commands_prepared<F, E>(&mut self, font_name: &str, scale: f32, string: &str, f: F) -> Result<Vec<DrawCommand<T>>, FontCacheError<E>>
125 where F: Fn(Bitmap) -> Result<T, E> {
126 if self.get_face_cache(font_name, scale).is_none() {
127 try!(self.create_face(font_name, scale, string.chars(), |a| f(a)));
128 }
129 {
130 let fc = self.get_face_cache_mut(font_name, scale).unwrap();
131 try!(fc.prepare_string(string, f).map_err(FontCacheError::UserError));
132 }
133 Ok(self.drawing_commands(font_name, scale, string).unwrap())
134 }
135}
136
137impl <T> FaceCache<T> {
138 pub fn new<I, F, E>(font: Font, scale: f32, chars: I, f: F) -> Result<FaceCache<T>, E>
144 where I: Iterator<Item=char>, F: Fn(Bitmap) -> Result<T, E>
145 {
146 let (atlas, bitmap, line_height) = font.make_atlas(chars, scale, 3, 256, 256);
147 let bitmap = try!(f(bitmap));
148 Ok(FaceCache {
149 font: font,
150 atlas: atlas,
151 bitmap: bitmap,
152 scale: scale,
153 missing: HashMap::new(),
154 missing_info: HashMap::new(),
155 line_height: line_height,
156 })
157 }
158
159 pub fn prepare_string<F, E>(&mut self, s: &str, f: F) -> Result<(), E>
161 where F: Fn(Bitmap) -> Result<T, E>
162 {
163 for c in s.chars() {
164 if self.atlas.info(c).is_none() && !self.missing.contains_key(&c) {
165 match self.font.render_char(c, self.scale).map(|(i, a)| (i, f(a))) {
166 Some((i, Ok(b))) => {
167 self.missing.insert(c, Some(b));
168 self.missing_info.insert(c, i);
169 },
170 Some((_, Err(e))) => return Err(e),
171 None => {
172 self.missing.insert(c, None);
173 },
174 };
175 }
176 }
177 Ok(())
178 }
179
180 pub fn needs_preparing(&self, s: &str) -> bool {
183 for c in s.chars() {
184 if self.atlas.info(c).is_none() && !self.missing.contains_key(&c) {
185 return true;
186 }
187 }
188 return false;
189 }
190
191 pub fn drawing_commands(&self, s: &str) -> Result<Vec<DrawCommand<T>>, FontCacheError<Void>> {
194 let mut out = Vec::new();
195 let mut x = 0.0;
196 let mut y = self.line_height.floor();
197
198 for c in s.chars() {
199 if c == ' ' {
200 if let Some(ci) = self.atlas.info('w').or_else(|| self.missing_info.get(&c).cloned()) {
201 x += ci.bounding_box.w as f32;
202 continue;
203 }
204 }
205
206 let bitmap;
207 let info;
208
209 if let Some(ci) = self.atlas.info(c) {
210 bitmap = &self.bitmap;
211 info = ci;
212 } else if let Some(ci) = self.missing_info.get(&c).cloned() {
213 bitmap = self.missing.get(&c).unwrap().as_ref().unwrap();
214 info = ci;
215 } else {
216 return Err(FontCacheError::MissingGlyph(c));
217 }
218
219 x += info.pre_draw_advance.0;
220 y += info.pre_draw_advance.1;
221
222 let h = info.bounding_box.h as f32;
223
224 out.push(DrawCommand {
225 bitmap: bitmap,
226 bitmap_location: info.bounding_box,
227 draw_location: (x, y - h),
228 });
229
230 x += info.bounding_box.w as f32;
231 }
232 Ok(out)
233 }
234
235 pub fn drawing_commands_prepared<F, E>(&mut self, s: &str, f: F) -> Result<Vec<DrawCommand<T>>, E>
239 where F: Fn(Bitmap) -> Result<T, E> {
240 try!(self.prepare_string(s, f));
241 Ok(self.drawing_commands(s).unwrap())
242 }
243}