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
|
use std::{fs::File, io::Read};
use ab_glyph::{point, Font, FontVec, PxScale, ScaleFont};
use anyhow::{Context, Result};
use font_kit::{
family_name::FamilyName, handle::Handle, properties::Properties, source::SystemSource,
};
use crate::wayland::ansi::{Color, StyledString};
mod layout;
fn get_font(weight: f32) -> Result<impl Font> {
let handle = SystemSource::new()
.select_best_match(
&[FamilyName::Monospace],
Properties::new().weight(font_kit::properties::Weight(weight)),
)
.context("Failed to find a monospace font")?;
match handle {
Handle::Path { path, font_index } => {
let data = {
let mut buffer = vec![];
let mut file = File::open(&path)?;
file.read_to_end(&mut buffer)?;
buffer
};
FontVec::try_from_vec_and_index(data, font_index).with_context(|| {
format!(
"Failed to load font at '{}' with index {}",
path.display(),
font_index
)
})
}
Handle::Memory { .. } => unimplemented!(),
}
}
pub(super) type ColorVec = (Vec<f32>, Vec<Option<Color>>);
pub(super) fn text(input: &StyledString) -> Result<(ColorVec, (u32, u32))> {
let normal_font = get_font(400.0)?;
let bold_font = get_font(600.0)?;
let height: f32 = 15.0;
let px_height = height.ceil() as usize;
let scale = PxScale {
x: height,
y: height,
};
let scaled_font = normal_font.into_scaled(scale);
let bold_scaled_font = bold_font.into_scaled(scale);
let mut glyphs = Vec::new();
layout::layout_paragraph(
&scaled_font,
&bold_scaled_font,
point(0.0, 0.0),
9999.0,
input,
&mut glyphs,
);
let px_width = glyphs
.iter()
.fold(0.0, |acc, (g, c)| {
let next = g.position.x
+ if c.is_bold() {
bold_scaled_font.h_advance(g.id)
} else {
scaled_font.h_advance(g.id)
};
if next > acc {
next
} else {
acc
}
})
.ceil() as usize;
// Rasterise to a f32 alpha vec
let mut pixel_data = vec![0.0; px_width * px_height];
let mut color_data = vec![None; px_width * px_height];
for (g, c) in glyphs {
let maybe_glyph = if c.is_bold() {
bold_scaled_font.outline_glyph(g)
} else {
scaled_font.outline_glyph(g)
};
if let Some(og) = maybe_glyph {
let bounds = og.px_bounds();
og.draw(|x, y, v| {
let x = x as f32 + bounds.min.x;
let y = y as f32 + bounds.min.y;
let next_idx = x as usize + y as usize * px_width;
assure_idx(&mut pixel_data, next_idx, 0.0);
assure_idx(&mut color_data, next_idx, None);
// save the coverage alpha
pixel_data[next_idx] += v;
color_data[next_idx] = c.color();
});
}
}
let len = pixel_data.len();
Ok((
(pixel_data, color_data),
(px_width as u32, (len / px_width) as u32),
))
}
fn assure_idx<T: Copy + Clone>(pixel_data: &mut Vec<T>, next_idx: usize, fill: T) {
let last = pixel_data.len() - 1;
if next_idx > last {
let needed = next_idx - last;
pixel_data.extend(vec![fill; needed]);
}
}
|