mirror of
https://github.com/typst/typst
synced 2025-05-17 02:25:27 +08:00
Add microjustification
This commit is contained in:
parent
94a497a01f
commit
7f9adfac22
@ -71,6 +71,16 @@ impl Line<'_> {
|
||||
count
|
||||
}
|
||||
|
||||
/// How many glyphs are in the text where we can insert micro-amounts
|
||||
/// of additional space when encountering underfull lines.
|
||||
fn microjustifiables(&self) -> usize {
|
||||
let mut count = 0;
|
||||
for shaped in self.items.iter().filter_map(Item::text) {
|
||||
count += shaped.microjustifiables();
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
/// How much the line can stretch.
|
||||
pub fn stretchability(&self) -> Abs {
|
||||
self.items
|
||||
@ -472,6 +482,7 @@ pub fn commit(
|
||||
let fr = line.fr();
|
||||
let mut justification_ratio = 0.0;
|
||||
let mut extra_justification = Abs::zero();
|
||||
let mut extra_microjustification = Abs::zero();
|
||||
|
||||
let shrinkability = line.shrinkability();
|
||||
let stretchability = line.stretchability();
|
||||
@ -487,9 +498,13 @@ pub fn commit(
|
||||
}
|
||||
|
||||
let justifiables = line.justifiables();
|
||||
let microjustifiables = line.microjustifiables();
|
||||
|
||||
if justifiables > 0 && remaining > Abs::zero() {
|
||||
// Underfull line, distribute the extra space.
|
||||
extra_justification = remaining / justifiables as f64;
|
||||
extra_microjustification = (remaining / microjustifiables as f64).min(p.config.microjustification);
|
||||
|
||||
extra_justification = (remaining - extra_microjustification * microjustifiables as f64) / justifiables as f64;
|
||||
remaining = Abs::zero();
|
||||
}
|
||||
}
|
||||
@ -531,6 +546,7 @@ pub fn commit(
|
||||
&p.spans,
|
||||
justification_ratio,
|
||||
extra_justification,
|
||||
extra_microjustification,
|
||||
);
|
||||
push(&mut offset, frame);
|
||||
}
|
||||
|
@ -183,11 +183,13 @@ fn configuration(
|
||||
situation: Option<ParSituation>,
|
||||
) -> Config {
|
||||
let justify = base.justify;
|
||||
let microjustification = ParElem::microjustification_in(shared);
|
||||
let font_size = TextElem::size_in(shared);
|
||||
let dir = TextElem::dir_in(shared);
|
||||
|
||||
Config {
|
||||
justify,
|
||||
microjustification,
|
||||
linebreaks: base.linebreaks.unwrap_or_else(|| {
|
||||
if justify {
|
||||
Linebreaks::Optimized
|
||||
@ -267,6 +269,10 @@ struct ConfigBase {
|
||||
struct Config {
|
||||
/// Whether to justify text.
|
||||
justify: bool,
|
||||
|
||||
/// The maximum allowed kerning adjustment for microjustification.
|
||||
microjustification: Abs,
|
||||
|
||||
/// How to determine line breaks.
|
||||
linebreaks: Linebreaks,
|
||||
/// The indent the first line of a paragraph should have.
|
||||
|
@ -83,6 +83,8 @@ pub struct ShapedGlyph {
|
||||
pub c: char,
|
||||
/// Whether this glyph is justifiable for CJK scripts.
|
||||
pub is_justifiable: bool,
|
||||
/// Whether this glyph is allowed additional kerning for microjustification.
|
||||
pub is_microjustifiable: bool,
|
||||
/// The script of the glyph.
|
||||
pub script: Script,
|
||||
}
|
||||
@ -107,6 +109,11 @@ impl ShapedGlyph {
|
||||
self.is_justifiable
|
||||
}
|
||||
|
||||
/// Whether the glyph is microjustifiable.
|
||||
pub fn is_microjustifiable(&self) -> bool {
|
||||
self.is_microjustifiable
|
||||
}
|
||||
|
||||
/// Whether the glyph is part of Chinese or Japanese script (i.e. CJ, not CJK).
|
||||
pub fn is_cj_script(&self) -> bool {
|
||||
is_cj_script(self.c, self.script)
|
||||
@ -216,6 +223,7 @@ impl<'a> ShapedText<'a> {
|
||||
spans: &SpanMapper,
|
||||
justification_ratio: f64,
|
||||
extra_justification: Abs,
|
||||
extra_microjustification: Abs,
|
||||
) -> Frame {
|
||||
let (top, bottom) = self.measure(engine);
|
||||
let size = Size::new(self.width, top + bottom);
|
||||
@ -261,6 +269,10 @@ impl<'a> ShapedText<'a> {
|
||||
justification_right +=
|
||||
Em::from_length(extra_justification, self.size)
|
||||
}
|
||||
if shaped.is_microjustifiable() {
|
||||
justification_right +=
|
||||
Em::from_length(extra_microjustification, self.size)
|
||||
}
|
||||
|
||||
frame.size_mut().x += justification_left.at(self.size)
|
||||
+ justification_right.at(self.size);
|
||||
@ -375,6 +387,12 @@ impl<'a> ShapedText<'a> {
|
||||
self.glyphs.iter().filter(|g| g.is_justifiable()).count()
|
||||
}
|
||||
|
||||
/// How many glyphs are in the text that are allowed extra kerning for the
|
||||
/// use of justification when encountering underfull lines.
|
||||
pub fn microjustifiables(&self) -> usize {
|
||||
self.glyphs.iter().filter(|g| g.is_microjustifiable()).count()
|
||||
}
|
||||
|
||||
/// Whether the last glyph is a CJK character which should not be justified
|
||||
/// on line end.
|
||||
pub fn cjk_justifiable_at_last(&self) -> bool {
|
||||
@ -496,6 +514,7 @@ impl<'a> ShapedText<'a> {
|
||||
safe_to_break: true,
|
||||
c: '-',
|
||||
is_justifiable: false,
|
||||
is_microjustifiable: false,
|
||||
script: Script::Common,
|
||||
};
|
||||
match side {
|
||||
@ -881,6 +900,7 @@ fn shape_segment<'a>(
|
||||
x_advance,
|
||||
Adjustability::default().stretchability,
|
||||
),
|
||||
is_microjustifiable: true,
|
||||
script,
|
||||
});
|
||||
} else {
|
||||
@ -973,6 +993,7 @@ fn shape_tofus(ctx: &mut ShapingContext, base: usize, text: &str, font: Font) {
|
||||
x_advance,
|
||||
Adjustability::default().stretchability,
|
||||
),
|
||||
is_microjustifiable: false,
|
||||
script,
|
||||
});
|
||||
};
|
||||
|
@ -138,6 +138,17 @@ pub struct ParElem {
|
||||
#[default(false)]
|
||||
pub justify: bool,
|
||||
|
||||
/// The maximum amount of kerning that is allowed to be used to further
|
||||
/// justify an existing line. When this value is nonzero, additional
|
||||
/// justification will be applied to individual glyphs.
|
||||
///
|
||||
/// Note that microjustifications are applied only after a line of text has
|
||||
/// been constructed. This means that the layout will *not* be affected by
|
||||
/// microjustifications, but the internal kerning of a line will be.
|
||||
#[resolve]
|
||||
#[default(Em::new(0.0).into())]
|
||||
pub microjustification: Length,
|
||||
|
||||
/// How to determine line breaks.
|
||||
///
|
||||
/// When this property is set to `{auto}`, its default value, optimized line
|
||||
|
Loading…
x
Reference in New Issue
Block a user