Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Replace the current text rendering engine with fontdue. #28

Closed
wants to merge 4 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Fix HiDPI font rendering and general align.
This produces proper result with HiDPI screens.
The font sizes have also been adjusted, so that
the final result matches the old sizes.
hasenbanck committed Oct 16, 2020
commit 4922d553ede55d209e007194fe6ec7474598c5c3
93 changes: 60 additions & 33 deletions egui/src/paint/fonts.rs
Original file line number Diff line number Diff line change
@@ -69,28 +69,28 @@ impl FontConfiguration {
TextStyle::Body,
FontDefinition {
family: FontFamily::VariableWidth,
scale_in_points: 14.0,
scale_in_points: 12.0,
},
);
definitions.insert(
TextStyle::Button,
FontDefinition {
family: FontFamily::VariableWidth,
scale_in_points: 16.0,
scale_in_points: 13.0,
},
);
definitions.insert(
TextStyle::Heading,
FontDefinition {
family: FontFamily::VariableWidth,
scale_in_points: 24.0,
scale_in_points: 20.0,
},
);
definitions.insert(
TextStyle::Monospace,
FontDefinition {
family: FontFamily::Monospace,
scale_in_points: 13.0,
scale_in_points: 11.0,
},
);
Self {
@@ -121,7 +121,7 @@ pub struct GlyphInfo {
pub uv_rect: UvRect,
}

/// Glyph layout information.
/// Glyph layout information. Units are in physical pixel and need to be scaled back to points.
#[derive(Clone, Debug, Default)]
pub struct GlyphLayout {
pub size: Vec2,
@@ -211,10 +211,10 @@ impl Fonts {

self.configuration = configuration;

let pixel_per_points = self.configuration.pixels_per_point;
let pixels_per_points = self.configuration.pixels_per_point;
for (text_style, definition) in self.configuration.definitions.clone().iter() {
let font_index = definition.family.font_index();
let scale_in_pixels = definition.scale_in_points * pixel_per_points;
let scale_in_pixels = definition.scale_in_points * pixels_per_points;

// Preload the printable ASCII characters [33, 126] (which excludes control codes):
const FIRST_ASCII: usize = 33; // !
@@ -239,9 +239,9 @@ impl Fonts {
.unwrap_or_else(|| panic!("font doesn't seem to support horizontal text layout"))
.new_line_size;
self.line_spacings
.insert(*text_style, line_spacing / pixel_per_points);
.insert(*text_style, line_spacing / pixels_per_points);
self.heights
.insert(*text_style, scale_in_pixels / pixel_per_points);
.insert(*text_style, scale_in_pixels / pixels_per_points);
}

// Make sure we seed the texture version with something unique based on the default characters:
@@ -285,7 +285,7 @@ impl Fonts {
..Default::default()
};

self.layout(style, text, &settings)
self.layout(style, text, settings)
}

// FIXME: https://github.com/mooman219/fontdue/issues/39
@@ -302,50 +302,76 @@ impl Fonts {
..Default::default()
};

self.layout(style, text, &settings)
self.layout(style, text, settings)
}

fn layout(&mut self, style: TextStyle, text: &str, settings: &LayoutSettings) -> GlyphLayout {
fn layout(
&mut self,
style: TextStyle,
text: &str,
mut settings: LayoutSettings,
) -> GlyphLayout {
// We calculate the layout in physical pixel and later scale back the metrics back to points.
// This is done to get a better looking layout.
let mut layout = GlyphLayout::with_capacity(text.len());

if text.is_empty() {
return layout;
}

let height = self.heights[&style];
// Convert points to pixel.
settings.max_width = if let Some(width) = settings.max_width {
Some(width * self.configuration.pixels_per_point)
} else {
None
};

let font_index = self.configuration.definitions[&style].family.font_index();
let pixels_per_point = self.configuration.pixels_per_point;
let height = self.heights[&style];
let px_height = self.heights[&style] * pixels_per_point;

let text_style = fontdue::layout::TextStyle {
text,
px: height,
px: px_height,
font_index,
};

self.layout_engine.layout_horizontal(
&self.fonts,
&[&text_style],
settings,
&settings,
&mut layout.glyph_positions,
);

// This assumes horizontal layout rendered from left to right.
let GlyphPosition {
x: first_x,
y: first_y,
height: first_height,
..
} = *layout.glyph_positions.first().unwrap();
let GlyphPosition {
x: last_x,
y: last_y,
width: last_width,
..
} = *layout.glyph_positions.last().unwrap();

let width = (last_x + last_width as f32) - first_x;
let height = last_y - (first_y - first_height as f32);
layout.size = vec2(width, height);
let mut min_y = f32::MAX;
let mut max_y = f32::MIN;
let mut min_x = f32::MAX;
let mut max_x = f32::MIN;

// Calculate logical points and max dimensions.
for pos in layout.glyph_positions.iter_mut() {
pos.width = (pos.width as f32 / pixels_per_point) as usize;
pos.height = (pos.height as f32 / pixels_per_point) as usize;
pos.x /= pixels_per_point;
pos.y /= pixels_per_point;

min_x = min_x.min(pos.x);
max_x = max_x.max(pos.x + pos.width as f32);
min_y = min_y.min(pos.y);
max_y = max_y.max(pos.y + pos.height as f32);
}

// Wait for fontdue do provide better line metrics to align the glyphs
// to the line with the current DPI setting.

// Add 20% height as margin to each side
let width = (max_x - min_x) + 0.4 * height;

// Add 20% height as margin to each side
let height = (max_y - min_y) + 0.4 * height;

layout.size = vec2(width, height);
layout
}

@@ -370,7 +396,8 @@ impl Fonts {
}

let uv_rect = UvRect {
size: vec2(metrics.width as f32, metrics.height as f32),
size: vec2(metrics.width as f32, metrics.height as f32)
/ self.configuration.pixels_per_point,
min: (glyph_pos.0 as u16, glyph_pos.1 as u16),
max: (
(glyph_pos.0 + metrics.width) as u16,
28 changes: 4 additions & 24 deletions egui/src/paint/tessellator.rs
Original file line number Diff line number Diff line change
@@ -761,14 +761,7 @@ fn tessellate_paint_command(
let tex_w = fonts.lock().texture().width as f32;
let tex_h = fonts.lock().texture().height as f32;

let pixels_per_point = fonts.lock().configuration().pixels_per_point;

let line_height = fonts.lock().text_style_line_spacing(text_style);
let clip_rect = clip_rect.expand(5.0); // Some fudge to handle letter slightly larger than expected.

// FIXME This value should be calculated by parent widget.
// Eye-balled for buttons.
let text_offset = vec2(0.0, -1.0);

let mut was_visible = false;
for glyph in &layout.glyph_positions {
@@ -793,31 +786,18 @@ fn tessellate_paint_command(

let glyph_info = fonts.lock().glyph_info(&glyph.key);
let uv_rect = glyph_info.uv_rect;
let mut left_top = pos + vec2(glyph.x, glyph.y) + text_offset;
left_top.x = round_to_pixel(left_top.x, pixels_per_point); // Pixel-perfection.
left_top.y = round_to_pixel(left_top.y, pixels_per_point); // Pixel-perfection.

let p = Rect::from_min_max(left_top, left_top + uv_rect.size);
let glyph_pos = vec2(glyph.x, glyph.y);
let left_top = pos + glyph_pos;
let pos = Rect::from_min_max(left_top, left_top + uv_rect.size);
let uv = Rect::from_min_max(
pos2(uv_rect.min.0 as f32 / tex_w, uv_rect.min.1 as f32 / tex_h),
pos2(uv_rect.max.0 as f32 / tex_w, uv_rect.max.1 as f32 / tex_h),
);
out.add_rect_with_uv(p, uv, color);

/* FIXME Remove me
let pos_rec = Rect::from_center_size(
Pos2::new(pos.x + glyph.x, pos.y + glyph.y),
vec2(2.0, 2.0),
);
out.add_colored_rect(pos_rec, Srgba::new(255, 0, 0, 255));
*/
out.add_rect_with_uv(pos, uv, color);
}
}
}

pub fn round_to_pixel(point: f32, pixels_per_point: f32) -> f32 {
(point * pixels_per_point).round() / pixels_per_point
}
}

/// Turns `PaintCmd`:s into sets of triangles.