From cb6e91204a1e94345f8bee1062ac2a1f98367029 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sat, 28 Mar 2026 16:39:20 +0100 Subject: [PATCH] cleanup --- crates/epaint/src/text/font.rs | 53 +++++++++++++++------------ crates/epaint/src/text/text_layout.rs | 19 ++++++++-- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/crates/epaint/src/text/font.rs b/crates/epaint/src/text/font.rs index 4561f17d6..7d71434bf 100644 --- a/crates/epaint/src/text/font.rs +++ b/crates/epaint/src/text/font.rs @@ -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, -} - // TODO(emilk): rename? /// Wrapper over multiple [`FontFace`] (e.g. a primary + fallbacks for emojis) pub struct Font<'a> { diff --git a/crates/epaint/src/text/text_layout.rs b/crates/epaint/src/text/text_layout.rs index bf4fa1b43..87b6a6ff4 100644 --- a/crates/epaint/src/text/text_layout.rs +++ b/crates/epaint/src/text/text_layout.rs @@ -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, } +/// 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, +} + /// 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;