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
#![crate_name="orbfont"]
#![crate_type="lib"]
extern crate orbclient;
extern crate rusttype;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use orbclient::{Color, Renderer};
pub struct Font {
inner: rusttype::Font<'static>
}
impl Font {
#[cfg(target_os = "redox")]
pub fn find(typeface: Option<&str>, family: Option<&str>, style: Option<&str>) -> Result<Font, String> {
Font::from_path(&format!("/ui/fonts/{}/{}/{}.ttf", typeface.unwrap_or("Mono"), family.unwrap_or("Fira"), style.unwrap_or("Regular")))
}
#[cfg(not(target_os = "redox"))]
pub fn find(typeface: Option<&str>, family: Option<&str>, style: Option<&str>) -> Result<Font, String> {
Font::from_path(&format!("/usr/share/fonts/truetype/liberation/{}{}-{}.ttf", family.unwrap_or("Liberation"), typeface.unwrap_or("Mono"), style.unwrap_or("Regular")))
}
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Font, String> {
let mut file = try!(File::open(path).map_err(|err| format!("failed to open font: {}", err)));
let mut data = Vec::new();
let _ = try!(file.read_to_end(&mut data).map_err(|err| format!("failed to read font: {}", err)));
Font::from_data(data)
}
pub fn from_data<D: Into<rusttype::SharedBytes<'static>>>(data: D) -> Result<Font, String> {
let collection = rusttype::FontCollection::from_bytes(data);
let font = try!(collection.into_font().ok_or("font collection did not have exactly one font".to_string()));
Ok(Font {
inner: font
})
}
pub fn render<'a>(&'a self, text: &str, height: f32) -> Text<'a> {
let scale = rusttype::Scale::uniform(height);
let v_metrics = self.inner.v_metrics(scale);
let offset = rusttype::point(0.0, v_metrics.ascent);
let glyphs: Vec<rusttype::PositionedGlyph> = self.inner.layout(text, scale, offset).collect();
let width = glyphs.iter().rev()
.filter_map(|g| g.pixel_bounding_box()
.map(|b| b.min.x as f32 + g.unpositioned().h_metrics().advance_width))
.next().unwrap_or(0.0);
Text {
w: width.ceil() as u32,
h: height.ceil() as u32,
glyphs: glyphs
}
}
}
pub struct Text<'a> {
w: u32,
h: u32,
glyphs: Vec<rusttype::PositionedGlyph<'a>>
}
impl<'a> Text<'a> {
pub fn width(&self) -> u32 {
self.w
}
pub fn height(&self) -> u32 {
self.h
}
pub fn draw<R: Renderer>(&self, renderer: &mut R, x: i32, y: i32, color: Color) {
for g in self.glyphs.iter() {
if let Some(bb) = g.pixel_bounding_box() {
g.draw(|off_x, off_y, v| {
let off_x = off_x as i32 + bb.min.x;
let off_y = off_y as i32 + bb.min.y;
if off_x >= 0 && off_x < self.w as i32 && off_y >= 0 && off_y < self.h as i32 {
let c = (v * 255.0) as u32;
renderer.pixel(x + off_x, y + off_y, Color{
data: c << 24 | (color.data & 0xFFFFFF)
});
}
});
}
}
}
}