2022-04-05 07:06:08 +10:00
|
|
|
use crate::ByteString;
|
|
|
|
use quote::quote;
|
|
|
|
|
|
|
|
use proc_macro2::TokenStream;
|
|
|
|
|
|
|
|
struct LetterData {
|
2024-03-27 20:21:06 +11:00
|
|
|
character: char,
|
2022-04-05 07:06:08 +10:00
|
|
|
width: usize,
|
2022-04-06 07:32:11 +10:00
|
|
|
height: usize,
|
|
|
|
xmin: i32,
|
|
|
|
ymin: i32,
|
|
|
|
advance_width: f32,
|
2022-04-05 07:06:08 +10:00
|
|
|
rendered: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load_font(font_data: &[u8], pixels_per_em: f32) -> TokenStream {
|
2022-04-06 07:32:11 +10:00
|
|
|
let font = fontdue::Font::from_bytes(
|
|
|
|
font_data,
|
|
|
|
fontdue::FontSettings {
|
|
|
|
scale: pixels_per_em,
|
2023-12-06 07:50:33 +11:00
|
|
|
..Default::default()
|
2022-04-06 07:32:11 +10:00
|
|
|
},
|
|
|
|
)
|
|
|
|
.expect("Invalid font data");
|
2022-04-05 07:06:08 +10:00
|
|
|
|
2022-04-06 07:44:32 +10:00
|
|
|
let line_metrics = font.horizontal_line_metrics(pixels_per_em).unwrap();
|
|
|
|
|
|
|
|
let line_height = line_metrics.new_line_size as i32;
|
2023-07-02 08:36:58 +10:00
|
|
|
let mut ascent = line_metrics.ascent as i32;
|
2022-04-06 07:44:32 +10:00
|
|
|
|
2024-03-27 20:21:06 +11:00
|
|
|
let mut letters: Vec<_> = font
|
|
|
|
.chars()
|
|
|
|
.iter()
|
|
|
|
.map(|(&c, _)| (c, font.rasterize(c, pixels_per_em)))
|
|
|
|
.map(|(c, (metrics, bitmap))| {
|
2022-04-05 07:06:08 +10:00
|
|
|
let width = metrics.width;
|
2022-04-06 07:32:11 +10:00
|
|
|
let height = metrics.height;
|
2022-04-06 07:44:32 +10:00
|
|
|
|
2022-04-24 00:42:08 +10:00
|
|
|
let rendered = bitmap
|
|
|
|
.chunks(8)
|
|
|
|
.map(|chunk| {
|
|
|
|
let mut output = 0u8;
|
|
|
|
for (i, &value) in chunk.iter().enumerate() {
|
|
|
|
if value > 100 {
|
|
|
|
output |= 1 << i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
output
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
2022-04-05 07:06:08 +10:00
|
|
|
LetterData {
|
2024-03-27 20:21:06 +11:00
|
|
|
character: c,
|
2022-04-05 07:06:08 +10:00
|
|
|
width,
|
2022-04-06 07:32:11 +10:00
|
|
|
height,
|
2022-04-24 00:42:08 +10:00
|
|
|
rendered,
|
2022-04-06 07:32:11 +10:00
|
|
|
xmin: metrics.xmin,
|
|
|
|
ymin: metrics.ymin,
|
|
|
|
advance_width: metrics.advance_width,
|
2022-04-05 07:06:08 +10:00
|
|
|
}
|
|
|
|
})
|
2023-07-02 08:36:58 +10:00
|
|
|
.collect();
|
2022-04-05 07:06:08 +10:00
|
|
|
|
2024-03-27 20:21:06 +11:00
|
|
|
letters.sort_unstable_by_key(|letter| letter.character);
|
|
|
|
|
2023-07-02 08:36:58 +10:00
|
|
|
let maximum_above_line = letters
|
|
|
|
.iter()
|
|
|
|
.map(|x| (x.height as i32 + x.ymin))
|
|
|
|
.max()
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
if (ascent - maximum_above_line) < 0 {
|
|
|
|
ascent = maximum_above_line;
|
|
|
|
}
|
|
|
|
|
|
|
|
let font = letters.iter().map(|letter_data| {
|
2024-03-27 20:21:06 +11:00
|
|
|
let character = letter_data.character;
|
2023-07-02 08:36:58 +10:00
|
|
|
let data_raw = ByteString(&letter_data.rendered);
|
|
|
|
let height = letter_data.height as u8;
|
|
|
|
let width = letter_data.width as u8;
|
|
|
|
let xmin = letter_data.xmin as i8;
|
|
|
|
let ymin = letter_data.ymin as i8;
|
|
|
|
let advance_width = letter_data.advance_width.ceil() as u8;
|
|
|
|
|
|
|
|
quote!(
|
|
|
|
display::FontLetter::new(
|
2024-03-27 20:21:06 +11:00
|
|
|
#character,
|
2023-07-02 08:36:58 +10:00
|
|
|
#width,
|
|
|
|
#height,
|
|
|
|
#data_raw,
|
|
|
|
#xmin,
|
|
|
|
#ymin,
|
|
|
|
#advance_width,
|
2022-04-06 07:32:11 +10:00
|
|
|
)
|
2023-07-02 08:36:58 +10:00
|
|
|
)
|
|
|
|
});
|
2022-04-05 07:06:08 +10:00
|
|
|
|
|
|
|
quote![
|
2022-04-24 00:33:57 +10:00
|
|
|
display::Font::new(&[#(#font),*], #line_height, #ascent)
|
2022-04-05 07:06:08 +10:00
|
|
|
]
|
|
|
|
}
|