mirror of
https://github.com/storytold/deckcraft.git
synced 2026-11-12 05:03:19 +00:00
Merge PR #249 from xmaks82: Text: exact line spacing ends at the last line's descent
# Conflicts: # crates/text/src/tests.rs
This commit is contained in:
commit
97e7164026
2 files changed
+36
-2
No files matched your search
@@ -1619,6 +1619,8 @@ fn layout_scaled(ctx: &Ctx, shape: &Shape, body: &TextBody, bp: &BodyProps, opts
|
||||
let mut numbering: Vec<u32> = vec![0; 9];
|
||||
let mut all_lines: Vec<(LineInfo, LinePlace, f64, Option<(String, f64, f64)>)> = vec![];
|
||||
let mut prev_after = 0.0;
|
||||
// How far the last line's full pitch reaches past the text (exact spacing; see below).
|
||||
let mut tail = 0.0;
|
||||
let mut shaped_paras: Vec<ParaShaped> = Vec::with_capacity(body.paragraphs.len());
|
||||
for (pi, para) in body.paragraphs.iter().enumerate() {
|
||||
let lvl = para.level.min(8) as usize;
|
||||
@@ -1695,7 +1697,11 @@ fn layout_scaled(ctx: &Ctx, shape: &Shape, body: &TextBody, bp: &BodyProps, opts
|
||||
};
|
||||
let ratio = if natural > 0.0 { lh / natural } else { 1.0 };
|
||||
let top = y;
|
||||
let baseline = top + asc * ratio;
|
||||
// Exact spacing (`spcPts`), as PowerPoint sets it: the baseline sits at 80 % of the
|
||||
// line pitch, and the text ends at the last line's descent rather than a full pitch.
|
||||
let exact = matches!(props.line_spacing, Some(Spacing::Pts(_)));
|
||||
let baseline = if exact { top + lh * 0.8 } else { top + asc * ratio };
|
||||
tail = if exact { (lh * 0.2 - desc).max(-lh) } else { 0.0 };
|
||||
y += lh;
|
||||
let x0 = if li == 0 { first_x } else { rest_x };
|
||||
let avail = (col_w - x0 - mr).max(0.0);
|
||||
@@ -1840,7 +1846,8 @@ fn layout_scaled(ctx: &Ctx, shape: &Shape, body: &TextBody, bp: &BodyProps, opts
|
||||
out.para_lines.push((first_line_idx, raw.len()));
|
||||
prev_after = spacing_pts(props.space_after, p.lead_size, reduce).max(0.0);
|
||||
}
|
||||
let total = y;
|
||||
// The text ends at the last line's descent under exact spacing.
|
||||
let total = (y - tail).max(0.0);
|
||||
out.content_height = total;
|
||||
// Where column `c` starts: from the left, or from the right with `rtlCol` (PowerPoint puts the
|
||||
// first column on the right).
|
||||
|
||||
@@ -206,6 +206,33 @@ fn saved_shrink_scale_is_drawn() {
|
||||
assert_eq!((l.font_scale, l.line_reduction), (1.0, 0.2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exact_line_spacing_ends_at_the_last_descent() {
|
||||
// 12 pt text at exactly 26.59 pt per line (a table cell PowerPoint sizes to 24.3 pt of text):
|
||||
// the baseline at 80 % of the pitch, the text ending at the last line's descent.
|
||||
let (p, mut sh) = setup("One\nTwo", 600.0, 300.0);
|
||||
for para in &mut sh.text.as_mut().unwrap().paragraphs {
|
||||
para.props.line_spacing = Some(Spacing::Pts(26.59));
|
||||
para.props.bullet = Some(Bullet::None);
|
||||
for r in &mut para.runs {
|
||||
r.props.size = Some(12.0);
|
||||
}
|
||||
}
|
||||
let l = lay(&p, &sh, 600.0, 300.0);
|
||||
let first = &l.lines[0];
|
||||
assert!((first.baseline - first.top - 26.59 * 0.8).abs() < 0.01, "{:?}", first.baseline - first.top);
|
||||
// The text ends at the last line's descent: above its full pitch by 20 % of it less the
|
||||
// descent (~2.3 pt for 12 pt type).
|
||||
let short = (l.lines[1].bottom - l.lines[0].top) - l.content_height;
|
||||
assert!(short > 1.0 && short < 26.59 * 0.2, "{short}");
|
||||
// Proportional spacing keeps full pitches.
|
||||
for para in &mut sh.text.as_mut().unwrap().paragraphs {
|
||||
para.props.line_spacing = Some(Spacing::Pct(1.0));
|
||||
}
|
||||
let l = lay(&p, &sh, 600.0, 300.0);
|
||||
assert!((l.content_height - (l.lines[1].bottom - l.lines[0].top)).abs() < 0.01);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn caret_and_hit_roundtrip() {
|
||||
let (p, sh) = setup("Hello world", 600.0, 100.0);
|
||||
|
||||
Reference in new issue
Block a user