Compute width of shaped text on-demand (#6806)

This commit is contained in:
Laurenz 2025-08-22 18:03:20 +02:00 committed by GitHub
parent aef36f3962
commit f9caddc6d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 9 additions and 25 deletions

View File

@ -82,7 +82,7 @@ impl<'a> Item<'a> {
/// The natural layouted width of the item.
pub fn natural_width(&self) -> Abs {
match self {
Self::Text(shaped) => shaped.width,
Self::Text(shaped) => shaped.width(),
Self::Absolute(v, _) => *v,
Self::Frame(frame) => frame.width(),
Self::Fractional(_, _) | Self::Tag(_) => Abs::zero(),

View File

@ -364,7 +364,6 @@ fn adjust_cj_at_line_start(p: &Preparation, items: &mut Items) {
let glyph = shaped.glyphs.to_mut().first_mut().unwrap();
let shrink = glyph.shrinkability().0;
glyph.shrink_left(shrink);
shaped.width -= shrink.at(glyph.size);
} else if p.config.cjk_latin_spacing
&& glyph.is_cj_script()
&& glyph.x_offset > Em::zero()
@ -376,7 +375,6 @@ fn adjust_cj_at_line_start(p: &Preparation, items: &mut Items) {
glyph.x_advance -= shrink;
glyph.x_offset = Em::zero();
glyph.adjustability.shrinkability.0 = Em::zero();
shaped.width -= shrink.at(glyph.size);
}
}
@ -394,7 +392,6 @@ fn adjust_cj_at_line_end(p: &Preparation, items: &mut Items) {
let shrink = glyph.shrinkability().1;
let punct = shaped.glyphs.to_mut().last_mut().unwrap();
punct.shrink_right(shrink);
shaped.width -= shrink.at(punct.size);
} else if p.config.cjk_latin_spacing
&& glyph.is_cj_script()
&& (glyph.x_advance - glyph.x_offset) > Em::one()
@ -405,7 +402,6 @@ fn adjust_cj_at_line_end(p: &Preparation, items: &mut Items) {
let glyph = shaped.glyphs.to_mut().last_mut().unwrap();
glyph.x_advance -= shrink;
glyph.adjustability.shrinkability.1 = Em::zero();
shaped.width -= shrink.at(glyph.size);
}
}

View File

@ -152,7 +152,6 @@ fn add_cjk_latin_spacing(items: &mut [(Range, Item)]) {
// The spacing is default to 1/4 em, and can be shrunk to 1/8 em.
glyph.x_advance += Em::new(0.25);
glyph.adjustability.shrinkability.1 += Em::new(0.125);
text.width += Em::new(0.25).at(glyph.size);
}
// Case 2: Latin followed by a CJ character
@ -160,7 +159,6 @@ fn add_cjk_latin_spacing(items: &mut [(Range, Item)]) {
glyph.x_advance += Em::new(0.25);
glyph.x_offset += Em::new(0.25);
glyph.adjustability.shrinkability.0 += Em::new(0.125);
text.width += Em::new(0.25).at(glyph.size);
}
prev = Some(glyph);

View File

@ -47,8 +47,6 @@ pub struct ShapedText<'a> {
pub styles: StyleChain<'a>,
/// The font variant.
pub variant: FontVariant,
/// The width of the text's bounding box.
pub width: Abs,
/// The shaped glyphs.
pub glyphs: Cow<'a, [ShapedGlyph]>,
}
@ -214,7 +212,7 @@ impl<'a> ShapedText<'a> {
extra_justification: Abs,
) -> Frame {
let (top, bottom) = self.measure(engine);
let size = Size::new(self.width, top + bottom);
let size = Size::new(self.width(), top + bottom);
let mut offset = Abs::zero();
let mut frame = Frame::soft(size);
@ -332,6 +330,12 @@ impl<'a> ShapedText<'a> {
frame
}
/// Computes the width of a run of glyphs relative to the font size,
/// accounting for their individual scaling factors and other font metrics.
pub fn width(&self) -> Abs {
self.glyphs.iter().map(|g| g.x_advance.at(g.size)).sum()
}
/// Measure the top and bottom extent of this text.
pub fn measure(&self, engine: &Engine) -> (Abs, Abs) {
let mut top = Abs::zero();
@ -419,7 +423,6 @@ impl<'a> ShapedText<'a> {
region: self.region,
styles: self.styles,
variant: self.variant,
width: glyphs_width(glyphs),
glyphs: Cow::Borrowed(glyphs),
}
} else {
@ -437,12 +440,7 @@ impl<'a> ShapedText<'a> {
/// Derive an empty text run with the same properties as this one.
pub fn empty(&self) -> Self {
Self {
text: "",
width: Abs::zero(),
glyphs: Cow::Borrowed(&[]),
..*self
}
Self { text: "", glyphs: Cow::Borrowed(&[]), ..*self }
}
/// Creates shaped text containing a hyphen.
@ -485,7 +483,6 @@ impl<'a> ShapedText<'a> {
region: base.region,
styles: base.styles,
variant: base.variant,
width: x_advance.at(size),
glyphs: Cow::Owned(vec![ShapedGlyph {
font,
glyph_id: glyph_id.0,
@ -694,17 +691,10 @@ fn shape<'a>(
region,
styles,
variant: ctx.variant,
width: glyphs_width(&ctx.glyphs),
glyphs: Cow::Owned(ctx.glyphs),
}
}
/// Computes the width of a run of glyphs relative to the font size, accounting
/// for their individual scaling factors and other font metrics.
fn glyphs_width(glyphs: &[ShapedGlyph]) -> Abs {
glyphs.iter().map(|g| g.x_advance.at(g.size)).sum()
}
/// Holds shaping results and metadata common to all shaped segments.
struct ShapingContext<'a, 'v> {
engine: &'a Engine<'v>,