1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-29 04:40:03 -04:00

Add subpixel_binning to TextOptions and FontTweak (#8072)

This lets you turn off subpixel horizontal binning of glyphs. The option
is a trade-off between even kerning and sharp text.

* Closes https://github.com/emilk/egui/issues/8034
This commit is contained in:
Emil Ernerfeldt
2026-04-07 10:38:37 +02:00
committed by GitHub
parent ab4bca65ea
commit 3abba21f2d
4 changed files with 51 additions and 21 deletions

View File

@@ -316,6 +316,7 @@ pub struct FontFace {
name: String,
font: FontCell,
tweak: FontTweak,
subpixel_binning: bool,
/// Cached `harfrust` shaper data (parsed GSUB/GPOS tables).
/// `ShaperData` is `Copy` — lives outside the `self_cell`.
@@ -352,7 +353,7 @@ impl FontFace {
skrifa::instance::LocationRef::default(),
);
let hinting_enabled = tweak.hinting_override.unwrap_or(options.font_hinting);
let hinting_enabled = tweak.hinting.unwrap_or(options.font_hinting);
let hinting_instance = hinting_enabled
.then(|| {
// It doesn't really matter what we put here for options. Since the size is `unscaled()`, we will
@@ -379,10 +380,13 @@ impl FontFace {
let shaper_data = harfrust::ShaperData::new(&font.borrow_dependent().skrifa);
let subpixel_binning = tweak.subpixel_binning.unwrap_or(options.subpixel_binning);
Ok(Self {
name,
font,
tweak,
subpixel_binning,
shaper_data,
glyph_info_cache: Default::default(),
glyph_alloc_cache: Default::default(),
@@ -551,12 +555,12 @@ impl FontFace {
return (GlyphAllocation::default(), h_pos.round() as i32);
}
let (h_pos_round, bin) = if is_cjk {
let (h_pos_round, bin) = if self.subpixel_binning && !is_cjk {
SubpixelBin::new(h_pos)
} else {
// CJK scripts contain a lot of characters and could hog the glyph atlas
// if we stored 4 subpixel offsets per glyph.
(h_pos.round() as i32, SubpixelBin::Zero)
} else {
SubpixelBin::new(h_pos)
};
let cache_key = GlyphCacheKey::new(glyph_id, metrics, bin);

View File

@@ -188,8 +188,13 @@ pub struct FontTweak {
/// Override the global font hinting setting for this specific font.
///
/// `None` means use the global setting.
pub hinting_override: Option<bool>,
/// `None` means use the global setting in [`TextOptions::font_hinting`].
pub hinting: Option<bool>,
/// Override the global sub-pixel binning setting for this specific font.
///
/// `None` means use the global setting in [`TextOptions::subpixel_binning`].
pub subpixel_binning: Option<bool>,
/// Override the font's default variation coordinates.
pub coords: VariationCoords,
@@ -214,7 +219,8 @@ impl Default for FontTweak {
scale: 1.0,
y_offset_factor: 0.0,
y_offset: 0.0,
hinting_override: None,
hinting: None,
subpixel_binning: None,
coords: VariationCoords::default(),
thin_space_width: 0.5,
tab_size: 4.0,

View File

@@ -34,6 +34,20 @@ pub struct TextOptions {
///
/// Default is `true`.
pub font_hinting: bool,
/// Enable sub-pixel binning for glyphs.
///
/// Sub-pixel binning renders each glyph at up to four fractional horizontal offsets,
/// giving more even kerning at the cost of more atlas space.
///
/// It also lead to text looking more blurry.
///
/// This is always disabled for CJK characters (which have too many unique glyphs).
///
/// Can be overridden per font with [`FontTweak::subpixel_binning`].
///
/// Default: `true`.
pub subpixel_binning: bool,
}
impl Default for TextOptions {
@@ -42,6 +56,7 @@ impl Default for TextOptions {
max_texture_side: 2048, // Small but portable
alpha_from_coverage: crate::AlphaFromCoverage::default(),
font_hinting: true,
subpixel_binning: true,
}
}
}