1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-29 04:40:03 -04:00
This commit is contained in:
Emil Ernerfeldt
2026-03-28 16:39:20 +01:00
parent b03d81fa4f
commit cb6e91204a
2 changed files with 45 additions and 27 deletions

View File

@@ -552,27 +552,35 @@ impl FontFace {
metrics: &StyledMetrics,
shaped: &ShapedGlyph,
) -> (GlyphAllocation, i32) {
if shaped.glyph_id == skrifa::GlyphId::NOTDEF {
return (GlyphAllocation::default(), shaped.h_pos as i32);
let ShapedGlyph {
glyph_id,
advance_width_px,
h_pos,
y_offset_points,
is_cjk,
} = *shaped;
if glyph_id == skrifa::GlyphId::NOTDEF {
return (GlyphAllocation::default(), h_pos.round() as i32);
}
let (h_pos_round, bin) = if shaped.is_cjk {
(shaped.h_pos.round() as i32, SubpixelBin::Zero)
let (h_pos_round, bin) = if is_cjk {
(h_pos.round() as i32, SubpixelBin::Zero)
} else {
SubpixelBin::new(shaped.h_pos)
SubpixelBin::new(h_pos)
};
let cache_key = GlyphCacheKey::new(shaped.glyph_id, metrics, bin);
let cache_key = GlyphCacheKey::new(glyph_id, metrics, bin);
if let Some(cached) = self.glyph_alloc_cache.get(&cache_key) {
let mut alloc = *cached;
alloc.advance_width_px = shaped.advance_width_px;
alloc.uv_rect.offset.y += shaped.y_offset_points;
alloc.advance_width_px = advance_width_px;
alloc.uv_rect.offset.y += y_offset_points;
return (alloc, h_pos_round);
}
let glyph_info = GlyphInfo {
id: Some(shaped.glyph_id),
advance_width_unscaled: OrderedFloat(shaped.advance_width_px / metrics.px_scale_factor),
id: Some(glyph_id),
advance_width_unscaled: OrderedFloat(advance_width_px / metrics.px_scale_factor),
};
let mut allocation = self
@@ -585,33 +593,30 @@ impl FontFace {
// Apply shaper y_offset after caching — the offset varies per call site
// so we cache the base allocation without it.
allocation.uv_rect.offset.y += shaped.y_offset_points;
allocation.uv_rect.offset.y += y_offset_points;
(allocation, h_pos_round)
}
}
/// A contiguous run of text that maps to a single font face.
///
/// Glyph positioning info from the text shaper, ready for allocation.
/// Positioning info for a single glyph, ready for atlas allocation.
#[derive(Clone, Copy, Debug)]
pub(crate) struct ShapedGlyph {
pub glyph_id: skrifa::GlyphId,
/// How far the cursor advances after this glyph, in physical pixels.
pub advance_width_px: f32,
/// Horizontal position of the glyph origin, in physical pixels.
pub h_pos: f32,
/// Vertical offset from the baseline, in UI points.
pub y_offset_points: f32,
/// CJK glyphs skip subpixel positioning to save atlas space.
pub is_cjk: bool,
}
/// Produced by [`Font::segment_into_runs`] for text shaping.
#[derive(Debug)]
pub(crate) struct TextRun {
/// Which font face should shape this run.
pub font_key: FontFaceKey,
/// Byte range within the section text.
pub byte_range: std::ops::Range<usize>,
}
// TODO(emilk): rename?
/// Wrapper over multiple [`FontFace`] (e.g. a primary + fallbacks for emojis)
pub struct Font<'a> {

View File

@@ -7,13 +7,16 @@ use emath::{Align, GuiRounding as _, NumExt as _, Pos2, Rect, Vec2, pos2, vec2};
use crate::{
Color32, Mesh, Stroke, Vertex,
stroke::PathStroke,
text::font::{StyledMetrics, is_cjk, is_cjk_break_allowed},
text::{
font::{StyledMetrics, is_cjk, is_cjk_break_allowed},
fonts::FontFaceKey,
},
};
use super::{
FontsImpl, Galley, Glyph, LayoutJob, LayoutSection, PlacedRow, Row, RowVisuals,
VariationCoords,
font::{Font, FontFace, TextRun},
font::{Font, FontFace},
};
// ----------------------------------------------------------------------------
@@ -178,6 +181,16 @@ struct ShapingContext {
prev_cluster: Option<u32>,
}
/// Produced by [`Font::segment_into_runs`] for text shaping.
#[derive(Debug)]
struct TextRun {
/// Which font face should shape this run.
pub font_key: FontFaceKey,
/// Byte range within the section text.
pub byte_range: std::ops::Range<usize>,
}
/// Emit shaped glyphs from a [`harfrust::GlyphBuffer`] into a [`Paragraph`].
fn layout_shaped_run(
font: &mut Font<'_>,
@@ -355,7 +368,7 @@ fn layout_section(
// Process each paragraph segment (split on newlines — the shaper can't handle them).
for (seg_idx, segment) in SplitOrWhole::new(section_text, job.break_on_newline).enumerate() {
if seg_idx > 0 {
if 0 < seg_idx {
out_paragraphs.push(Paragraph::from_section_index(section_index));
paragraph = out_paragraphs.last_mut().unwrap();
paragraph.empty_paragraph_height = line_height;