mirror of
https://github.com/typst/typst
synced 2025-08-24 11:44:12 +08:00
Compute width of shaped text on-demand (#6806)
This commit is contained in:
parent
aef36f3962
commit
f9caddc6d3
@ -82,7 +82,7 @@ impl<'a> Item<'a> {
|
|||||||
/// The natural layouted width of the item.
|
/// The natural layouted width of the item.
|
||||||
pub fn natural_width(&self) -> Abs {
|
pub fn natural_width(&self) -> Abs {
|
||||||
match self {
|
match self {
|
||||||
Self::Text(shaped) => shaped.width,
|
Self::Text(shaped) => shaped.width(),
|
||||||
Self::Absolute(v, _) => *v,
|
Self::Absolute(v, _) => *v,
|
||||||
Self::Frame(frame) => frame.width(),
|
Self::Frame(frame) => frame.width(),
|
||||||
Self::Fractional(_, _) | Self::Tag(_) => Abs::zero(),
|
Self::Fractional(_, _) | Self::Tag(_) => Abs::zero(),
|
||||||
|
@ -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 glyph = shaped.glyphs.to_mut().first_mut().unwrap();
|
||||||
let shrink = glyph.shrinkability().0;
|
let shrink = glyph.shrinkability().0;
|
||||||
glyph.shrink_left(shrink);
|
glyph.shrink_left(shrink);
|
||||||
shaped.width -= shrink.at(glyph.size);
|
|
||||||
} else if p.config.cjk_latin_spacing
|
} else if p.config.cjk_latin_spacing
|
||||||
&& glyph.is_cj_script()
|
&& glyph.is_cj_script()
|
||||||
&& glyph.x_offset > Em::zero()
|
&& 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_advance -= shrink;
|
||||||
glyph.x_offset = Em::zero();
|
glyph.x_offset = Em::zero();
|
||||||
glyph.adjustability.shrinkability.0 = 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 shrink = glyph.shrinkability().1;
|
||||||
let punct = shaped.glyphs.to_mut().last_mut().unwrap();
|
let punct = shaped.glyphs.to_mut().last_mut().unwrap();
|
||||||
punct.shrink_right(shrink);
|
punct.shrink_right(shrink);
|
||||||
shaped.width -= shrink.at(punct.size);
|
|
||||||
} else if p.config.cjk_latin_spacing
|
} else if p.config.cjk_latin_spacing
|
||||||
&& glyph.is_cj_script()
|
&& glyph.is_cj_script()
|
||||||
&& (glyph.x_advance - glyph.x_offset) > Em::one()
|
&& (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();
|
let glyph = shaped.glyphs.to_mut().last_mut().unwrap();
|
||||||
glyph.x_advance -= shrink;
|
glyph.x_advance -= shrink;
|
||||||
glyph.adjustability.shrinkability.1 = Em::zero();
|
glyph.adjustability.shrinkability.1 = Em::zero();
|
||||||
shaped.width -= shrink.at(glyph.size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
// The spacing is default to 1/4 em, and can be shrunk to 1/8 em.
|
||||||
glyph.x_advance += Em::new(0.25);
|
glyph.x_advance += Em::new(0.25);
|
||||||
glyph.adjustability.shrinkability.1 += Em::new(0.125);
|
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
|
// 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_advance += Em::new(0.25);
|
||||||
glyph.x_offset += Em::new(0.25);
|
glyph.x_offset += Em::new(0.25);
|
||||||
glyph.adjustability.shrinkability.0 += Em::new(0.125);
|
glyph.adjustability.shrinkability.0 += Em::new(0.125);
|
||||||
text.width += Em::new(0.25).at(glyph.size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = Some(glyph);
|
prev = Some(glyph);
|
||||||
|
@ -47,8 +47,6 @@ pub struct ShapedText<'a> {
|
|||||||
pub styles: StyleChain<'a>,
|
pub styles: StyleChain<'a>,
|
||||||
/// The font variant.
|
/// The font variant.
|
||||||
pub variant: FontVariant,
|
pub variant: FontVariant,
|
||||||
/// The width of the text's bounding box.
|
|
||||||
pub width: Abs,
|
|
||||||
/// The shaped glyphs.
|
/// The shaped glyphs.
|
||||||
pub glyphs: Cow<'a, [ShapedGlyph]>,
|
pub glyphs: Cow<'a, [ShapedGlyph]>,
|
||||||
}
|
}
|
||||||
@ -214,7 +212,7 @@ impl<'a> ShapedText<'a> {
|
|||||||
extra_justification: Abs,
|
extra_justification: Abs,
|
||||||
) -> Frame {
|
) -> Frame {
|
||||||
let (top, bottom) = self.measure(engine);
|
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 offset = Abs::zero();
|
||||||
let mut frame = Frame::soft(size);
|
let mut frame = Frame::soft(size);
|
||||||
@ -332,6 +330,12 @@ impl<'a> ShapedText<'a> {
|
|||||||
frame
|
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.
|
/// Measure the top and bottom extent of this text.
|
||||||
pub fn measure(&self, engine: &Engine) -> (Abs, Abs) {
|
pub fn measure(&self, engine: &Engine) -> (Abs, Abs) {
|
||||||
let mut top = Abs::zero();
|
let mut top = Abs::zero();
|
||||||
@ -419,7 +423,6 @@ impl<'a> ShapedText<'a> {
|
|||||||
region: self.region,
|
region: self.region,
|
||||||
styles: self.styles,
|
styles: self.styles,
|
||||||
variant: self.variant,
|
variant: self.variant,
|
||||||
width: glyphs_width(glyphs),
|
|
||||||
glyphs: Cow::Borrowed(glyphs),
|
glyphs: Cow::Borrowed(glyphs),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -437,12 +440,7 @@ impl<'a> ShapedText<'a> {
|
|||||||
|
|
||||||
/// Derive an empty text run with the same properties as this one.
|
/// Derive an empty text run with the same properties as this one.
|
||||||
pub fn empty(&self) -> Self {
|
pub fn empty(&self) -> Self {
|
||||||
Self {
|
Self { text: "", glyphs: Cow::Borrowed(&[]), ..*self }
|
||||||
text: "",
|
|
||||||
width: Abs::zero(),
|
|
||||||
glyphs: Cow::Borrowed(&[]),
|
|
||||||
..*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates shaped text containing a hyphen.
|
/// Creates shaped text containing a hyphen.
|
||||||
@ -485,7 +483,6 @@ impl<'a> ShapedText<'a> {
|
|||||||
region: base.region,
|
region: base.region,
|
||||||
styles: base.styles,
|
styles: base.styles,
|
||||||
variant: base.variant,
|
variant: base.variant,
|
||||||
width: x_advance.at(size),
|
|
||||||
glyphs: Cow::Owned(vec![ShapedGlyph {
|
glyphs: Cow::Owned(vec![ShapedGlyph {
|
||||||
font,
|
font,
|
||||||
glyph_id: glyph_id.0,
|
glyph_id: glyph_id.0,
|
||||||
@ -694,17 +691,10 @@ fn shape<'a>(
|
|||||||
region,
|
region,
|
||||||
styles,
|
styles,
|
||||||
variant: ctx.variant,
|
variant: ctx.variant,
|
||||||
width: glyphs_width(&ctx.glyphs),
|
|
||||||
glyphs: Cow::Owned(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.
|
/// Holds shaping results and metadata common to all shaped segments.
|
||||||
struct ShapingContext<'a, 'v> {
|
struct ShapingContext<'a, 'v> {
|
||||||
engine: &'a Engine<'v>,
|
engine: &'a Engine<'v>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user