From 6b7719539ec6839ab391b1650f148309d4471e44 Mon Sep 17 00:00:00 2001 From: shadow cat Date: Tue, 18 Nov 2025 01:05:51 -0500 Subject: [PATCH] better text rendering --- src/layout/text.rs | 63 +++++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/src/layout/text.rs b/src/layout/text.rs index 72c3b9a..377c800 100644 --- a/src/layout/text.rs +++ b/src/layout/text.rs @@ -1,4 +1,6 @@ -use cosmic_text::{Attrs, AttrsList, Buffer, Family, FontSystem, Metrics, SwashCache}; +use cosmic_text::{ + Attrs, AttrsList, Buffer, Family, FontSystem, Metrics, SwashCache, SwashContent, +}; use image::{Rgba, RgbaImage}; use crate::{ @@ -79,7 +81,7 @@ impl TextData { // should probably do texture packing and things if possible. // very visible if you add just a couple of wrapping texts and resize window // should also be timed to figure out exactly what points need to be sped up - let mut pixels = HashMap::default(); + let mut pixels = HashMap::<_, [u8; 4]>::default(); let mut min_x = 0; let mut min_y = 0; let mut max_x = 0; @@ -99,20 +101,46 @@ impl TextData { None => cosmic_color, }; - self.swash_cache.with_pixels( - &mut self.font_system, - physical_glyph.cache_key, - glyph_color, - |x, y, color| { - let x = physical_glyph.x + x; - let y = run.line_y as i32 + physical_glyph.y + y; - min_x = min_x.min(x); - min_y = min_y.min(y); - max_x = max_x.max(x); - max_y = max_y.max(y); - pixels.insert((x, y), Rgba(color.as_rgba())); - }, - ); + if let Some(img) = self + .swash_cache + .get_image(&mut self.font_system, physical_glyph.cache_key) + { + let mut pos = img.placement; + pos.left += physical_glyph.x; + pos.top = physical_glyph.y + run.line_y as i32 - pos.top; + min_x = min_x.min(pos.left); + min_y = min_y.min(pos.top); + max_x = max_x.max(pos.left + pos.width as i32); + max_y = max_y.max(pos.top + pos.height as i32); + let mut merge = |i, color: [u8; 4]| { + let x = i % pos.width as usize; + let y = i / pos.width as usize; + let pos = (x as i32 + pos.left, y as i32 + pos.top); + if let Some(pixel) = pixels.get_mut(&pos) { + for i in 0..4 { + pixel[i] = color[i].saturating_add(pixel[i]); + } + } else { + pixels.insert(pos, color); + } + }; + match img.content { + SwashContent::Mask => { + for (i, a) in img.data.iter().enumerate() { + let mut color = glyph_color.as_rgba(); + color[3] = ((color[3] as u32 * *a as u32) / u8::MAX as u32) as u8; + merge(i, color); + } + } + SwashContent::SubpixelMask => todo!(), + SwashContent::Color => { + let (colors, _) = img.data.as_chunks::<4>(); + for (i, color) in colors.iter().enumerate() { + merge(i, *color); + } + } + } + } } max_width = max_width.max(run.line_w); height += run.line_height; @@ -120,10 +148,11 @@ impl TextData { let img_width = (max_x - min_x + 1) as u32; let img_height = (max_y - min_y + 1) as u32; let mut image = RgbaImage::new(img_width, img_height); + for ((x, y), color) in pixels { let x = (x - min_x) as u32; let y = (y - min_y) as u32; - image.put_pixel(x, y, color); + image.put_pixel(x, y, Rgba(color)); } TextTexture { handle: textures.add(image),