From 0df77d90740a6c7bbc786988cd1f7282a4d410a6 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sat, 22 Jan 2022 15:39:13 +0100 Subject: [PATCH] Round font sizes to whole pixels before deduplicating them --- epaint/src/text/font.rs | 21 ++++++----------- epaint/src/text/fonts.rs | 50 ++++++++++++++++++++-------------------- 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/epaint/src/text/font.rs b/epaint/src/text/font.rs index 6e7fe987..68e101d6 100644 --- a/epaint/src/text/font.rs +++ b/epaint/src/text/font.rs @@ -59,7 +59,7 @@ impl Default for GlyphInfo { pub struct FontImpl { ab_glyph_font: ab_glyph::FontArc, /// Maximum character height - scale_in_pixels: f32, + scale_in_pixels: u32, height_in_points: f32, // move each character by this much (hack) y_offset: f32, @@ -73,20 +73,13 @@ impl FontImpl { atlas: Arc>, pixels_per_point: f32, ab_glyph_font: ab_glyph::FontArc, - scale_in_points: f32, + scale_in_pixels: u32, y_offset: f32, ) -> FontImpl { - assert!(scale_in_points > 0.0); + assert!(scale_in_pixels > 0); assert!(pixels_per_point > 0.0); - let scale_in_pixels = pixels_per_point * scale_in_points; - - // Round to an even number of physical pixels to get even kerning. - // See https://github.com/emilk/egui/issues/382 - let scale_in_pixels = scale_in_pixels.round(); - let scale_in_points = scale_in_pixels / pixels_per_point; - - let height_in_points = scale_in_points; + let height_in_points = scale_in_pixels as f32 / pixels_per_point; // TODO: use v_metrics for line spacing ? // let v = rusttype_font.v_metrics(Scale::uniform(scale_in_pixels)); @@ -162,7 +155,7 @@ impl FontImpl { &mut self.atlas.lock(), &self.ab_glyph_font, glyph_id, - self.scale_in_pixels, + self.scale_in_pixels as f32, self.y_offset, self.pixels_per_point, ); @@ -180,7 +173,7 @@ impl FontImpl { ) -> f32 { use ab_glyph::{Font as _, ScaleFont}; self.ab_glyph_font - .as_scaled(self.scale_in_pixels) + .as_scaled(self.scale_in_pixels as f32) .kern(last_glyph_id, glyph_id) / self.pixels_per_point } @@ -375,7 +368,7 @@ fn allocate_glyph( } }); - let offset_in_pixels = vec2(bb.min.x as f32, scale_in_pixels as f32 + bb.min.y as f32); + let offset_in_pixels = vec2(bb.min.x as f32, scale_in_pixels + bb.min.y as f32); let offset = offset_in_pixels / pixels_per_point + y_offset * Vec2::Y; UvRect { offset, diff --git a/epaint/src/text/fonts.rs b/epaint/src/text/fonts.rs index fdcd4501..98500cdf 100644 --- a/epaint/src/text/fonts.rs +++ b/epaint/src/text/fonts.rs @@ -503,9 +503,8 @@ struct FontImplCache { pixels_per_point: f32, ab_glyph_fonts: BTreeMap, - /// Map font names and size to the cached `FontImpl`. - /// Can't have f32 in a HashMap or BTreeMap, so let's do a linear search - cache: Vec<(String, f32, Arc)>, + /// Map font pixel sizes and names to the cached `FontImpl`. + cache: ahash::AHashMap<(u32, String), Arc>, } impl FontImplCache { @@ -528,20 +527,7 @@ impl FontImplCache { } } - pub fn ab_glyph_font(&self, font_name: &str) -> ab_glyph::FontArc { - self.ab_glyph_fonts - .get(font_name) - .unwrap_or_else(|| panic!("No font data found for {:?}", font_name)) - .clone() - } - pub fn font_impl(&mut self, font_name: &str, scale_in_points: f32) -> Arc { - for entry in &self.cache { - if (entry.0.as_str(), entry.1) == (font_name, scale_in_points) { - return entry.2.clone(); - } - } - let y_offset = if font_name == "emoji-icon-font" { scale_in_points * 0.235 // TODO: remove font alignment hack } else { @@ -555,15 +541,29 @@ impl FontImplCache { scale_in_points }; - let font_impl = Arc::new(FontImpl::new( - self.atlas.clone(), - self.pixels_per_point, - self.ab_glyph_font(font_name), - scale_in_points, - y_offset, - )); + let scale_in_pixels = self.pixels_per_point * scale_in_points; + + // Round to an even number of physical pixels to get even kerning. + // See https://github.com/emilk/egui/issues/382 + let scale_in_pixels = scale_in_pixels.round() as u32; + self.cache - .push((font_name.to_owned(), scale_in_points, font_impl.clone())); - font_impl + .entry((scale_in_pixels, font_name.to_owned())) + .or_insert_with(|| { + let ab_glyph_font = self + .ab_glyph_fonts + .get(font_name) + .unwrap_or_else(|| panic!("No font data found for {:?}", font_name)) + .clone(); + + Arc::new(FontImpl::new( + self.atlas.clone(), + self.pixels_per_point, + ab_glyph_font, + scale_in_pixels, + y_offset, + )) + }) + .clone() } }