Fix text sizes being too small (#2069)

Closes https://github.com/emilk/egui/issues/2068

Before this PR, the default font, Ubuntu-Light, was ~11% smaller
than it should have been, and the default monospace font, Hack,
was ~14% smaller. This means that setting the font size `12` in egui
would yield smaller text than using that font size in any other app.
Ooops!

The change is that this PR now takes into account the ttf properties
`units_per_em` and `height_unscaled`.

If your egui application has specified you own font sizes or text styles
you will see the text in your application grow
larger, unless you go in and compensate by dividing all font sizes by
~1.21 for Ubuntu-Light/Proportional and ~1.16 for Hack/Monospace,
and with something else if you are using a custom font!
This effects any use of `FontId`, `RichText::size`, etc.

This PR changes the default `Style::text_styles` to compensate,
so the default egui style should look the same before and after this PR.
This commit is contained in:
Emil Ernerfeldt 2022-09-21 21:31:08 +02:00 committed by GitHub
parent 990a8c8b44
commit 29fa63317e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 87 additions and 65 deletions

View file

@ -5,6 +5,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG
## Unreleased
* ⚠️ BREAKING: Fix text being too small ([#2069](https://github.com/emilk/egui/pull/2069)).
## 0.19.0 - 2022-08-20

View file

@ -14,7 +14,7 @@ pub fn font_family_ui(ui: &mut Ui, font_family: &mut FontFamily) {
pub fn font_id_ui(ui: &mut Ui, font_id: &mut FontId) {
let families = ui.fonts().families();
ui.horizontal(|ui| {
ui.add(Slider::new(&mut font_id.size, 4.0..=40.0).max_decimals(0));
ui.add(Slider::new(&mut font_id.size, 4.0..=40.0).max_decimals(1));
for alternative in families {
let text = alternative.to_string();
ui.radio_value(&mut font_id.family, alternative, text);

View file

@ -213,7 +213,7 @@ impl Painter {
rect.min,
Align2::LEFT_TOP,
text.to_string(),
FontId::monospace(14.0),
FontId::monospace(12.0),
color,
);
}
@ -232,7 +232,7 @@ impl Painter {
color: Color32,
text: impl ToString,
) -> Rect {
let galley = self.layout_no_wrap(text.to_string(), FontId::monospace(14.0), color);
let galley = self.layout_no_wrap(text.to_string(), FontId::monospace(12.0), color);
let rect = anchor.anchor_rect(Rect::from_min_size(pos, galley.size()));
let frame_rect = rect.expand(2.0);
self.add(Shape::rect_filled(

View file

@ -602,25 +602,16 @@ pub struct DebugOptions {
/// The default text styles of the default egui theme.
pub fn default_text_styles() -> BTreeMap<TextStyle, FontId> {
let mut text_styles = BTreeMap::new();
text_styles.insert(
TextStyle::Small,
FontId::new(10.0, FontFamily::Proportional),
);
text_styles.insert(TextStyle::Body, FontId::new(14.0, FontFamily::Proportional));
text_styles.insert(
TextStyle::Button,
FontId::new(14.0, FontFamily::Proportional),
);
text_styles.insert(
TextStyle::Heading,
FontId::new(20.0, FontFamily::Proportional),
);
text_styles.insert(
TextStyle::Monospace,
FontId::new(14.0, FontFamily::Monospace),
);
text_styles
use FontFamily::{Monospace, Proportional};
[
(TextStyle::Small, FontId::new(9.0, Proportional)),
(TextStyle::Body, FontId::new(12.5, Proportional)),
(TextStyle::Button, FontId::new(12.5, Proportional)),
(TextStyle::Heading, FontId::new(18.0, Proportional)),
(TextStyle::Monospace, FontId::new(12.0, Monospace)),
]
.into()
}
impl Default for Style {

View file

@ -405,21 +405,21 @@ fn paint_fine_lines_and_text(painter: &egui::Painter, mut rect: Rect, color: Col
rect.center_top() + vec2(0.0, x),
Align2::LEFT_TOP,
format!("{:.0}% white", 100.0 * opacity),
FontId::proportional(16.0),
FontId::proportional(14.0),
Color32::WHITE.linear_multiply(opacity),
);
painter.text(
rect.center_top() + vec2(80.0, x),
Align2::LEFT_TOP,
format!("{:.0}% gray", 100.0 * opacity),
FontId::proportional(16.0),
FontId::proportional(14.0),
Color32::GRAY.linear_multiply(opacity),
);
painter.text(
rect.center_top() + vec2(160.0, x),
Align2::LEFT_TOP,
format!("{:.0}% black", 100.0 * opacity),
FontId::proportional(16.0),
FontId::proportional(14.0),
Color32::BLACK.linear_multiply(opacity),
);
x += 20.0;
@ -434,7 +434,7 @@ fn paint_fine_lines_and_text(painter: &egui::Painter, mut rect: Rect, color: Col
rect.left_top(),
Align2::CENTER_CENTER,
width.to_string(),
FontId::monospace(14.0),
FontId::monospace(12.0),
color,
);
@ -459,7 +459,7 @@ fn paint_fine_lines_and_text(painter: &egui::Painter, mut rect: Rect, color: Col
rect.left_top(),
Align2::LEFT_CENTER,
"transparent --> opaque",
FontId::monospace(11.0),
FontId::monospace(10.0),
color,
);
rect.min.y += 12.0;

View file

@ -194,7 +194,7 @@ impl DemoWindows {
ui.add_space(12.0);
ui.vertical_centered_justified(|ui| {
if ui
.button(egui::RichText::new("Continue to the demo!").size(24.0))
.button(egui::RichText::new("Continue to the demo!").size(20.0))
.clicked()
{
close = true;
@ -211,7 +211,7 @@ impl DemoWindows {
fn mobile_top_bar(&mut self, ctx: &Context) {
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
egui::menu::bar(ui, |ui| {
let font_size = 20.0;
let font_size = 16.5;
ui.menu_button(egui::RichText::new("⏷ demos").size(font_size), |ui| {
ui.set_style(ui.ctx().style()); // ignore the "menu" style set by `menu_button`.

View file

@ -10,7 +10,7 @@ impl Default for FontBook {
fn default() -> Self {
Self {
filter: Default::default(),
font_id: egui::FontId::proportional(20.0),
font_id: egui::FontId::proportional(18.0),
named_chars: Default::default(),
}
}

View file

@ -544,7 +544,7 @@ fn text_layout_ui(
"mixing ",
0.0,
TextFormat {
font_id: FontId::proportional(20.0),
font_id: FontId::proportional(17.0),
color: default_color,
..Default::default()
},
@ -553,7 +553,7 @@ fn text_layout_ui(
"fonts, ",
0.0,
TextFormat {
font_id: FontId::monospace(14.0),
font_id: FontId::monospace(12.0),
color: default_color,
..Default::default()
},
@ -562,7 +562,7 @@ fn text_layout_ui(
"raised text, ",
0.0,
TextFormat {
font_id: FontId::proportional(8.0),
font_id: FontId::proportional(7.0),
color: default_color,
valign: Align::TOP,
..Default::default()
@ -623,7 +623,7 @@ fn text_layout_ui(
" mix these!",
0.0,
TextFormat {
font_id: FontId::proportional(8.0),
font_id: FontId::proportional(7.0),
color: Color32::LIGHT_BLUE,
background: Color32::from_rgb(128, 0, 0),
underline: Stroke::new(1.0, strong_color),

View file

@ -195,7 +195,7 @@ impl CodeTheme {
#[cfg(not(feature = "syntect"))]
impl CodeTheme {
pub fn dark() -> Self {
let font_id = egui::FontId::monospace(12.0);
let font_id = egui::FontId::monospace(10.0);
use egui::{Color32, TextFormat};
Self {
dark_mode: true,
@ -211,7 +211,7 @@ impl CodeTheme {
}
pub fn light() -> Self {
let font_id = egui::FontId::monospace(12.0);
let font_id = egui::FontId::monospace(10.0);
use egui::{Color32, TextFormat};
Self {
dark_mode: false,
@ -318,7 +318,7 @@ impl Highlighter {
// Fallback:
LayoutJob::simple(
code.into(),
egui::FontId::monospace(14.0),
egui::FontId::monospace(12.0),
if theme.dark_mode {
egui::Color32::LIGHT_GRAY
} else {
@ -364,7 +364,7 @@ impl Highlighter {
leading_space: 0.0,
byte_range: as_byte_range(text, range),
format: TextFormat {
font_id: egui::FontId::monospace(14.0),
font_id: egui::FontId::monospace(12.0),
color: text_color,
italics,
underline,

View file

@ -3,6 +3,7 @@ All notable changes to the epaint crate will be documented in this file.
## Unreleased
* ⚠️ BREAKING: Fix text being too small ([#2069](https://github.com/emilk/egui/pull/2069)).
## 0.19.0 - 2022-08-20

View file

@ -1,5 +1,4 @@
use std::collections::BTreeMap;
use std::sync::Arc;
use std::{collections::BTreeMap, sync::Arc};
use crate::{
mutex::{Mutex, MutexGuard},
@ -271,7 +270,13 @@ impl Default for FontDefinitions {
// Some good looking emojis. Use as first priority:
font_data.insert(
"NotoEmoji-Regular".to_owned(),
FontData::from_static(include_bytes!("../../fonts/NotoEmoji-Regular.ttf")),
FontData::from_static(include_bytes!("../../fonts/NotoEmoji-Regular.ttf")).tweak(
FontTweak {
scale: 0.81, // make it smaller
y_offset_factor: -0.2, // move it up
y_offset: 0.0,
},
),
);
// Bigger emojis, and more. <http://jslegers.github.io/emoji-icon-font/>:
@ -279,7 +284,7 @@ impl Default for FontDefinitions {
"emoji-icon-font".to_owned(),
FontData::from_static(include_bytes!("../../fonts/emoji-icon-font.ttf")).tweak(
FontTweak {
scale: 0.8, // make it smaller
scale: 0.88, // make it smaller
y_offset_factor: 0.07, // move it down slightly
y_offset: 0.0,
},
@ -526,6 +531,21 @@ impl FontsAndCache {
// ----------------------------------------------------------------------------
#[derive(Clone, Copy, Debug, PartialEq)]
struct HashableF32(f32);
#[allow(clippy::derive_hash_xor_eq)]
impl std::hash::Hash for HashableF32 {
#[inline(always)]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
crate::f32_hash(state, self.0);
}
}
impl Eq for HashableF32 {}
// ----------------------------------------------------------------------------
/// The collection of fonts used by `epaint`.
///
/// Required in order to paint text.
@ -535,7 +555,7 @@ pub struct FontsImpl {
definitions: FontDefinitions,
atlas: Arc<Mutex<TextureAtlas>>,
font_impl_cache: FontImplCache,
sized_family: ahash::HashMap<(u32, FontFamily), Font>,
sized_family: ahash::HashMap<(HashableF32, FontFamily), Font>,
}
impl FontsImpl {
@ -584,10 +604,9 @@ impl FontsImpl {
/// Get the right font implementation from size and [`FontFamily`].
pub fn font(&mut self, font_id: &FontId) -> &mut Font {
let FontId { size, family } = font_id;
let scale_in_pixels = self.font_impl_cache.scale_as_pixels(*size);
self.sized_family
.entry((scale_in_pixels, family.clone()))
.entry((HashableF32(*size), family.clone()))
.or_insert_with(|| {
let fonts = &self.definitions.families.get(family);
let fonts = fonts.unwrap_or_else(|| {
@ -596,7 +615,7 @@ impl FontsImpl {
let fonts: Vec<Arc<FontImpl>> = fonts
.iter()
.map(|font_name| self.font_impl_cache.font_impl(scale_in_pixels, font_name))
.map(|font_name| self.font_impl_cache.font_impl(*size, font_name))
.collect();
Font::new(fonts)
@ -699,23 +718,33 @@ impl FontImplCache {
}
}
#[inline]
pub fn scale_as_pixels(&self, scale_in_points: f32) -> u32 {
let scale_in_pixels = self.pixels_per_point * scale_in_points;
pub fn font_impl(&mut self, scale_in_points: f32, font_name: &str) -> Arc<FontImpl> {
use ab_glyph::Font as _;
// Round to an even number of physical pixels to get even kerning.
// See https://github.com/emilk/egui/issues/382
scale_in_pixels.round() as u32
}
pub fn font_impl(&mut self, scale_in_pixels: u32, font_name: &str) -> Arc<FontImpl> {
let (tweak, ab_glyph_font) = self
.ab_glyph_fonts
.get(font_name)
.unwrap_or_else(|| panic!("No font data found for {:?}", font_name))
.clone();
let scale_in_pixels = (scale_in_pixels as f32 * tweak.scale).round() as u32;
let scale_in_pixels = self.pixels_per_point * scale_in_points;
// Scale the font properly (see https://github.com/emilk/egui/issues/2068).
let units_per_em = ab_glyph_font.units_per_em().unwrap_or_else(|| {
panic!(
"The font unit size of {:?} exceeds the expected range (16..=16384)",
font_name
)
});
let font_scaling = ab_glyph_font.height_unscaled() / units_per_em;
let scale_in_pixels = scale_in_pixels * font_scaling;
// Tweak the scale as the user desired:
let scale_in_pixels = scale_in_pixels * tweak.scale;
// 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;
let y_offset_points = {
let scale_in_points = scale_in_pixels as f32 / self.pixels_per_point;

View file

@ -845,7 +845,7 @@ fn test_pre_cjk() {
"日本語とEnglishの混在した文章".into(),
super::TextFormat::default(),
);
layout_job.wrap.max_width = 100.0;
layout_job.wrap.max_width = 110.0;
let galley = super::layout(&mut fonts, layout_job.into());
assert_eq!(
galley

View file

@ -18,13 +18,13 @@ fn configure_text_styles(ctx: &egui::Context) {
let mut style = (*ctx.style()).clone();
style.text_styles = [
(TextStyle::Heading, FontId::new(30.0, Proportional)),
(heading2(), FontId::new(25.0, Proportional)),
(heading3(), FontId::new(23.0, Proportional)),
(TextStyle::Body, FontId::new(18.0, Proportional)),
(TextStyle::Monospace, FontId::new(14.0, Proportional)),
(TextStyle::Button, FontId::new(14.0, Proportional)),
(TextStyle::Small, FontId::new(10.0, Proportional)),
(TextStyle::Heading, FontId::new(25.0, Proportional)),
(heading2(), FontId::new(22.0, Proportional)),
(heading3(), FontId::new(19.0, Proportional)),
(TextStyle::Body, FontId::new(16.0, Proportional)),
(TextStyle::Monospace, FontId::new(12.0, Proportional)),
(TextStyle::Button, FontId::new(12.0, Proportional)),
(TextStyle::Small, FontId::new(8.0, Proportional)),
]
.into();
ctx.set_style(style);

View file

@ -70,7 +70,7 @@ fn custom_window_frame(
rect.center_top() + vec2(0.0, height / 2.0),
Align2::CENTER_CENTER,
title,
FontId::proportional(height - 2.0),
FontId::proportional(height * 0.8),
text_color,
);