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:
@@ -2344,11 +2344,13 @@ impl Visuals {
|
|||||||
max_texture_side: _,
|
max_texture_side: _,
|
||||||
alpha_from_coverage,
|
alpha_from_coverage,
|
||||||
font_hinting,
|
font_hinting,
|
||||||
|
subpixel_binning,
|
||||||
} = text_options;
|
} = text_options;
|
||||||
|
|
||||||
text_alpha_from_coverage_ui(ui, alpha_from_coverage);
|
text_alpha_from_coverage_ui(ui, alpha_from_coverage);
|
||||||
|
|
||||||
ui.checkbox(font_hinting, "Enable font hinting");
|
ui.checkbox(font_hinting, "Font hinting (sharper text)");
|
||||||
|
ui.checkbox(subpixel_binning, "Sub-pixel binning (more even kerning)");
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.collapsing("Text cursor", |ui| {
|
ui.collapsing("Text cursor", |ui| {
|
||||||
@@ -2913,10 +2915,11 @@ impl Widget for &mut FontTweak {
|
|||||||
scale,
|
scale,
|
||||||
y_offset_factor,
|
y_offset_factor,
|
||||||
y_offset,
|
y_offset,
|
||||||
hinting_override,
|
hinting,
|
||||||
coords,
|
coords,
|
||||||
thin_space_width,
|
thin_space_width,
|
||||||
tab_size,
|
tab_size,
|
||||||
|
subpixel_binning,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
ui.label("Scale");
|
ui.label("Scale");
|
||||||
@@ -2932,18 +2935,20 @@ impl Widget for &mut FontTweak {
|
|||||||
ui.add(DragValue::new(y_offset).speed(-0.02));
|
ui.add(DragValue::new(y_offset).speed(-0.02));
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|
||||||
ui.label("hinting_override");
|
ui.label("hinting");
|
||||||
ComboBox::from_id_salt("hinting_override")
|
ui.horizontal(|ui| {
|
||||||
.selected_text(match hinting_override {
|
ui.radio_value(hinting, Some(true), "on");
|
||||||
None => "None",
|
ui.radio_value(hinting, Some(false), "off");
|
||||||
Some(true) => "Enable",
|
ui.radio_value(hinting, None, "default");
|
||||||
Some(false) => "Disable",
|
});
|
||||||
})
|
ui.end_row();
|
||||||
.show_ui(ui, |ui| {
|
|
||||||
ui.selectable_value(hinting_override, None, "None");
|
ui.label("subpixel_binning");
|
||||||
ui.selectable_value(hinting_override, Some(true), "Enable");
|
ui.horizontal(|ui| {
|
||||||
ui.selectable_value(hinting_override, Some(false), "Disable");
|
ui.radio_value(subpixel_binning, Some(true), "on");
|
||||||
});
|
ui.radio_value(subpixel_binning, Some(false), "off");
|
||||||
|
ui.radio_value(subpixel_binning, None, "default");
|
||||||
|
});
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|
||||||
ui.label("coords");
|
ui.label("coords");
|
||||||
|
|||||||
@@ -316,6 +316,7 @@ pub struct FontFace {
|
|||||||
name: String,
|
name: String,
|
||||||
font: FontCell,
|
font: FontCell,
|
||||||
tweak: FontTweak,
|
tweak: FontTweak,
|
||||||
|
subpixel_binning: bool,
|
||||||
|
|
||||||
/// Cached `harfrust` shaper data (parsed GSUB/GPOS tables).
|
/// Cached `harfrust` shaper data (parsed GSUB/GPOS tables).
|
||||||
/// `ShaperData` is `Copy` — lives outside the `self_cell`.
|
/// `ShaperData` is `Copy` — lives outside the `self_cell`.
|
||||||
@@ -352,7 +353,7 @@ impl FontFace {
|
|||||||
skrifa::instance::LocationRef::default(),
|
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
|
let hinting_instance = hinting_enabled
|
||||||
.then(|| {
|
.then(|| {
|
||||||
// It doesn't really matter what we put here for options. Since the size is `unscaled()`, we will
|
// 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 shaper_data = harfrust::ShaperData::new(&font.borrow_dependent().skrifa);
|
||||||
|
|
||||||
|
let subpixel_binning = tweak.subpixel_binning.unwrap_or(options.subpixel_binning);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name,
|
name,
|
||||||
font,
|
font,
|
||||||
tweak,
|
tweak,
|
||||||
|
subpixel_binning,
|
||||||
shaper_data,
|
shaper_data,
|
||||||
glyph_info_cache: Default::default(),
|
glyph_info_cache: Default::default(),
|
||||||
glyph_alloc_cache: Default::default(),
|
glyph_alloc_cache: Default::default(),
|
||||||
@@ -551,12 +555,12 @@ impl FontFace {
|
|||||||
return (GlyphAllocation::default(), h_pos.round() as i32);
|
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
|
// CJK scripts contain a lot of characters and could hog the glyph atlas
|
||||||
// if we stored 4 subpixel offsets per glyph.
|
// if we stored 4 subpixel offsets per glyph.
|
||||||
(h_pos.round() as i32, SubpixelBin::Zero)
|
(h_pos.round() as i32, SubpixelBin::Zero)
|
||||||
} else {
|
|
||||||
SubpixelBin::new(h_pos)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let cache_key = GlyphCacheKey::new(glyph_id, metrics, bin);
|
let cache_key = GlyphCacheKey::new(glyph_id, metrics, bin);
|
||||||
|
|||||||
@@ -188,8 +188,13 @@ pub struct FontTweak {
|
|||||||
|
|
||||||
/// Override the global font hinting setting for this specific font.
|
/// Override the global font hinting setting for this specific font.
|
||||||
///
|
///
|
||||||
/// `None` means use the global setting.
|
/// `None` means use the global setting in [`TextOptions::font_hinting`].
|
||||||
pub hinting_override: Option<bool>,
|
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.
|
/// Override the font's default variation coordinates.
|
||||||
pub coords: VariationCoords,
|
pub coords: VariationCoords,
|
||||||
@@ -214,7 +219,8 @@ impl Default for FontTweak {
|
|||||||
scale: 1.0,
|
scale: 1.0,
|
||||||
y_offset_factor: 0.0,
|
y_offset_factor: 0.0,
|
||||||
y_offset: 0.0,
|
y_offset: 0.0,
|
||||||
hinting_override: None,
|
hinting: None,
|
||||||
|
subpixel_binning: None,
|
||||||
coords: VariationCoords::default(),
|
coords: VariationCoords::default(),
|
||||||
thin_space_width: 0.5,
|
thin_space_width: 0.5,
|
||||||
tab_size: 4.0,
|
tab_size: 4.0,
|
||||||
|
|||||||
@@ -34,6 +34,20 @@ pub struct TextOptions {
|
|||||||
///
|
///
|
||||||
/// Default is `true`.
|
/// Default is `true`.
|
||||||
pub font_hinting: bool,
|
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 {
|
impl Default for TextOptions {
|
||||||
@@ -42,6 +56,7 @@ impl Default for TextOptions {
|
|||||||
max_texture_side: 2048, // Small but portable
|
max_texture_side: 2048, // Small but portable
|
||||||
alpha_from_coverage: crate::AlphaFromCoverage::default(),
|
alpha_from_coverage: crate::AlphaFromCoverage::default(),
|
||||||
font_hinting: true,
|
font_hinting: true,
|
||||||
|
subpixel_binning: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user