1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-02 23:00:04 -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, metrics: &StyledMetrics,
shaped: &ShapedGlyph, shaped: &ShapedGlyph,
) -> (GlyphAllocation, i32) { ) -> (GlyphAllocation, i32) {
if shaped.glyph_id == skrifa::GlyphId::NOTDEF { let ShapedGlyph {
return (GlyphAllocation::default(), shaped.h_pos as i32); 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 { let (h_pos_round, bin) = if is_cjk {
(shaped.h_pos.round() as i32, SubpixelBin::Zero) (h_pos.round() as i32, SubpixelBin::Zero)
} else { } 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) { if let Some(cached) = self.glyph_alloc_cache.get(&cache_key) {
let mut alloc = *cached; let mut alloc = *cached;
alloc.advance_width_px = shaped.advance_width_px; alloc.advance_width_px = advance_width_px;
alloc.uv_rect.offset.y += shaped.y_offset_points; alloc.uv_rect.offset.y += y_offset_points;
return (alloc, h_pos_round); return (alloc, h_pos_round);
} }
let glyph_info = GlyphInfo { let glyph_info = GlyphInfo {
id: Some(shaped.glyph_id), id: Some(glyph_id),
advance_width_unscaled: OrderedFloat(shaped.advance_width_px / metrics.px_scale_factor), advance_width_unscaled: OrderedFloat(advance_width_px / metrics.px_scale_factor),
}; };
let mut allocation = self let mut allocation = self
@@ -585,33 +593,30 @@ impl FontFace {
// Apply shaper y_offset after caching — the offset varies per call site // Apply shaper y_offset after caching — the offset varies per call site
// so we cache the base allocation without it. // 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) (allocation, h_pos_round)
} }
} }
/// A contiguous run of text that maps to a single font face. /// Positioning info for a single glyph, ready for atlas allocation.
/// #[derive(Clone, Copy, Debug)]
/// Glyph positioning info from the text shaper, ready for allocation.
pub(crate) struct ShapedGlyph { pub(crate) struct ShapedGlyph {
pub glyph_id: skrifa::GlyphId, pub glyph_id: skrifa::GlyphId,
/// How far the cursor advances after this glyph, in physical pixels.
pub advance_width_px: f32, pub advance_width_px: f32,
/// Horizontal position of the glyph origin, in physical pixels.
pub h_pos: f32, pub h_pos: f32,
/// Vertical offset from the baseline, in UI points.
pub y_offset_points: f32, pub y_offset_points: f32,
/// CJK glyphs skip subpixel positioning to save atlas space.
pub is_cjk: bool, 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? // TODO(emilk): rename?
/// Wrapper over multiple [`FontFace`] (e.g. a primary + fallbacks for emojis) /// Wrapper over multiple [`FontFace`] (e.g. a primary + fallbacks for emojis)
pub struct Font<'a> { pub struct Font<'a> {

View File

@@ -7,13 +7,16 @@ use emath::{Align, GuiRounding as _, NumExt as _, Pos2, Rect, Vec2, pos2, vec2};
use crate::{ use crate::{
Color32, Mesh, Stroke, Vertex, Color32, Mesh, Stroke, Vertex,
stroke::PathStroke, stroke::PathStroke,
text::font::{StyledMetrics, is_cjk, is_cjk_break_allowed}, text::{
font::{StyledMetrics, is_cjk, is_cjk_break_allowed},
fonts::FontFaceKey,
},
}; };
use super::{ use super::{
FontsImpl, Galley, Glyph, LayoutJob, LayoutSection, PlacedRow, Row, RowVisuals, FontsImpl, Galley, Glyph, LayoutJob, LayoutSection, PlacedRow, Row, RowVisuals,
VariationCoords, VariationCoords,
font::{Font, FontFace, TextRun}, font::{Font, FontFace},
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -178,6 +181,16 @@ struct ShapingContext {
prev_cluster: Option<u32>, 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`]. /// Emit shaped glyphs from a [`harfrust::GlyphBuffer`] into a [`Paragraph`].
fn layout_shaped_run( fn layout_shaped_run(
font: &mut Font<'_>, font: &mut Font<'_>,
@@ -355,7 +368,7 @@ fn layout_section(
// Process each paragraph segment (split on newlines — the shaper can't handle them). // 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() { 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)); out_paragraphs.push(Paragraph::from_section_index(section_index));
paragraph = out_paragraphs.last_mut().unwrap(); paragraph = out_paragraphs.last_mut().unwrap();
paragraph.empty_paragraph_height = line_height; paragraph.empty_paragraph_height = line_height;