Round font sizes to whole pixels before deduplicating them

This commit is contained in:
Emil Ernerfeldt 2022-01-22 15:39:13 +01:00
parent 67c58ace27
commit 0df77d9074
2 changed files with 32 additions and 39 deletions

View file

@ -59,7 +59,7 @@ impl Default for GlyphInfo {
pub struct FontImpl { pub struct FontImpl {
ab_glyph_font: ab_glyph::FontArc, ab_glyph_font: ab_glyph::FontArc,
/// Maximum character height /// Maximum character height
scale_in_pixels: f32, scale_in_pixels: u32,
height_in_points: f32, height_in_points: f32,
// move each character by this much (hack) // move each character by this much (hack)
y_offset: f32, y_offset: f32,
@ -73,20 +73,13 @@ impl FontImpl {
atlas: Arc<Mutex<TextureAtlas>>, atlas: Arc<Mutex<TextureAtlas>>,
pixels_per_point: f32, pixels_per_point: f32,
ab_glyph_font: ab_glyph::FontArc, ab_glyph_font: ab_glyph::FontArc,
scale_in_points: f32, scale_in_pixels: u32,
y_offset: f32, y_offset: f32,
) -> FontImpl { ) -> FontImpl {
assert!(scale_in_points > 0.0); assert!(scale_in_pixels > 0);
assert!(pixels_per_point > 0.0); assert!(pixels_per_point > 0.0);
let scale_in_pixels = pixels_per_point * scale_in_points; let height_in_points = scale_in_pixels as f32 / pixels_per_point;
// 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;
// TODO: use v_metrics for line spacing ? // TODO: use v_metrics for line spacing ?
// let v = rusttype_font.v_metrics(Scale::uniform(scale_in_pixels)); // let v = rusttype_font.v_metrics(Scale::uniform(scale_in_pixels));
@ -162,7 +155,7 @@ impl FontImpl {
&mut self.atlas.lock(), &mut self.atlas.lock(),
&self.ab_glyph_font, &self.ab_glyph_font,
glyph_id, glyph_id,
self.scale_in_pixels, self.scale_in_pixels as f32,
self.y_offset, self.y_offset,
self.pixels_per_point, self.pixels_per_point,
); );
@ -180,7 +173,7 @@ impl FontImpl {
) -> f32 { ) -> f32 {
use ab_glyph::{Font as _, ScaleFont}; use ab_glyph::{Font as _, ScaleFont};
self.ab_glyph_font self.ab_glyph_font
.as_scaled(self.scale_in_pixels) .as_scaled(self.scale_in_pixels as f32)
.kern(last_glyph_id, glyph_id) .kern(last_glyph_id, glyph_id)
/ self.pixels_per_point / 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; let offset = offset_in_pixels / pixels_per_point + y_offset * Vec2::Y;
UvRect { UvRect {
offset, offset,

View file

@ -503,9 +503,8 @@ struct FontImplCache {
pixels_per_point: f32, pixels_per_point: f32,
ab_glyph_fonts: BTreeMap<String, ab_glyph::FontArc>, ab_glyph_fonts: BTreeMap<String, ab_glyph::FontArc>,
/// Map font names and size to the cached `FontImpl`. /// Map font pixel sizes and names to the cached `FontImpl`.
/// Can't have f32 in a HashMap or BTreeMap, so let's do a linear search cache: ahash::AHashMap<(u32, String), Arc<FontImpl>>,
cache: Vec<(String, f32, Arc<FontImpl>)>,
} }
impl FontImplCache { 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<FontImpl> { pub fn font_impl(&mut self, font_name: &str, scale_in_points: f32) -> Arc<FontImpl> {
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" { let y_offset = if font_name == "emoji-icon-font" {
scale_in_points * 0.235 // TODO: remove font alignment hack scale_in_points * 0.235 // TODO: remove font alignment hack
} else { } else {
@ -555,15 +541,29 @@ impl FontImplCache {
scale_in_points scale_in_points
}; };
let font_impl = Arc::new(FontImpl::new( 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
.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.atlas.clone(),
self.pixels_per_point, self.pixels_per_point,
self.ab_glyph_font(font_name), ab_glyph_font,
scale_in_points, scale_in_pixels,
y_offset, y_offset,
)); ))
self.cache })
.push((font_name.to_owned(), scale_in_points, font_impl.clone())); .clone()
font_impl
} }
} }