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 { 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, Vec>); 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(pixel_data: &mut Vec, 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]); } }