aboutsummaryrefslogtreecommitdiff
path: root/src/text.rs
blob: 8f5216e649ad8abf21bed51c5ebcf3dd2cee3e75 (plain)
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
use std::collections::HashMap;
use list_fonts::get_font_families;

use freetype::Library;
use freetype::Face;
use freetype;

/// Rasterizes glyphs for a single font face.
pub struct Rasterizer {
    faces: HashMap<FontDesc, Face<'static>>,
    library: Library,
    system_fonts: HashMap<String, ::list_fonts::Family>,
}

#[inline]
fn to_freetype_26_6(f: f32) -> isize {
    ((1i32 << 6) as f32 * f) as isize
}

#[derive(Clone, PartialEq, Eq, Hash)]
pub struct FontDesc {
    name: String,
    style: String,
}

impl FontDesc {
    pub fn new<S>(name: S, style: S) -> FontDesc
        where S: Into<String>
    {
        FontDesc {
            name: name.into(),
            style: style.into()
        }
    }
}

impl Rasterizer {
    pub fn new() -> Rasterizer {
        let library = Library::init().unwrap();

        Rasterizer {
            system_fonts: get_font_families(),
            faces: HashMap::new(),
            library: library,
        }
    }

    pub fn get_face(&mut self, desc: &FontDesc) -> Option<Face<'static>> {
        if let Some(face) = self.faces.get(desc) {
            return Some(face.clone());
        }

        if let Some(font) = self.system_fonts.get(&desc.name[..]) {
            if let Some(variant) = font.variants().get(&desc.style[..]) {
                let face = self.library.new_face(variant.path(), variant.index())
                                       .expect("TODO handle new_face error");

                self.faces.insert(desc.to_owned(), face);
                return Some(self.faces.get(desc).unwrap().clone());
            }
        }

        None
    }

    pub fn get_glyph(&mut self, desc: &FontDesc, size: f32, c: char) -> RasterizedGlyph {
        let face = self.get_face(desc).expect("TODO handle get_face error");
        // TODO DPI
        face.set_char_size(to_freetype_26_6(size), 0, 96, 0).unwrap();
        face.load_char(c as usize, freetype::face::RENDER).unwrap();
        let glyph = face.glyph();

        RasterizedGlyph {
            top: glyph.bitmap_top() as usize,
            left: glyph.bitmap_left() as usize,
            width: glyph.bitmap().width() as usize,
            height: glyph.bitmap().rows() as usize,
            buf: glyph.bitmap().buffer().to_vec(),
        }
    }
}

#[derive(Debug)]
pub struct RasterizedGlyph {
    pub width: usize,
    pub height: usize,
    pub top: usize,
    pub left: usize,
    pub buf: Vec<u8>,
}


#[cfg(test)]
mod tests {
    use super::{Rasterizer, FontDesc};

    #[cfg(target_os = "linux")]
    fn font_desc() -> FontDesc {
        FontDesc::new("Ubuntu Mono", "Regular")
    }

    #[test]
    fn create_rasterizer_and_render_glyph() {
        let mut rasterizer = Rasterizer::new();
        let glyph = rasterizer.get_glyph(&font_desc(), 24., 'U');

        println!("glyph: {:?}", glyph);

        for j in 0..glyph.height {
            for i in 0..glyph.width {
                let val = glyph.buf[j * glyph.width + i];
                print!("{}", if val < 122 { " " } else { "%"});
            }

            print!("\n");
        }
    }
}