mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-31 21:56:50 -06:00
Integration: the line breaker measures a tab beside a drop cap from the drop cap
#282 measures tabs in the line breaker from where layout starts the line; next's drop caps (#83) start lines beside the drop cap after it (on the right in RTL). The breaker's tab closure uses the same indent as next's width closure and line placement; measured from the frame edge, a tab looked wider and the line broke a word early.
This commit is contained in:
@@ -924,7 +924,19 @@ fn compose_with_db(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &C
|
||||
// Where each line starts relative to the tab origin, as `layout_line` places it.
|
||||
let tab = |j: usize, x: f64, i: usize| {
|
||||
let x0 = slots.get(j).map_or(col.x0, |s| s.0);
|
||||
let ind = pp.left_indent + if line_no + j == 0 { pp.first_line_indent } else { 0.0 };
|
||||
let ind = pp.left_indent
|
||||
+ match &drop_cap {
|
||||
// Beside a drop cap: at its start-side indent (the right side in RTL).
|
||||
Some(dc) if line_no + j < dc.lines && col_first_line == 0 => {
|
||||
if rtl {
|
||||
0.0
|
||||
} else {
|
||||
dc.indent()
|
||||
}
|
||||
}
|
||||
_ if line_no + j == 0 => pp.first_line_indent,
|
||||
_ => 0.0,
|
||||
};
|
||||
tab_advance(&pp.tabs, x0 + ind + x - col.x0, rest.get(i + 1..).unwrap_or_default()).0
|
||||
};
|
||||
breaker::greedy(rest, rest_h, &spacing, &width, &tab)
|
||||
|
||||
@@ -1916,6 +1916,24 @@ fn drop_cap_spans_lines_and_indents_them() {
|
||||
assert_eq!(lines[0].range.start, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tab_beside_a_drop_cap_is_measured_from_the_drop_cap() {
|
||||
// The line breaker measures a tab from where the line starts, which beside a drop cap is
|
||||
// after the drop cap: measured from the frame edge, the tab looks wider and the line breaks
|
||||
// a word early.
|
||||
let stop = designcraft_doc::TabStop { position: 100.0, align: TabAlign::Left, leader: String::new(), align_on: String::new() };
|
||||
let para = ParaAttrs { tabs: Some(vec![stop]), hyphenate: Some(false), ..drop_cap(3, 1) };
|
||||
let text = format!("Wort\t{LOREM}");
|
||||
let (d, sid, _) = drop_doc(&text, para);
|
||||
let cs = compose_story(&d, sid, &ComposeOptions::default());
|
||||
let lines = all_lines(&cs);
|
||||
let space = |g: &PlacedGlyph| g.len > 0 && text.get(g.byte..).and_then(|s| s.chars().next()).is_some_and(char::is_whitespace);
|
||||
let right = lines[0].glyphs.iter().filter(|g| g.visible && !space(g)).map(|g| g.x + g.adv).fold(0.0, f64::max);
|
||||
assert!(right <= lines[0].x1 + 0.01, "line 1 ends at {right}, past {}", lines[0].x1);
|
||||
let word: f64 = lines[1].glyphs.iter().filter(|g| g.len > 0).take_while(|g| !space(g)).map(|g| g.adv).sum();
|
||||
assert!(right + word + 4.0 > lines[0].x1, "line 2's first word ({word} pt) fits after line 1's end at {right} (edge {})", lines[0].x1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_cap_of_two_characters_as_a_local_override() {
|
||||
let (d, sid, _) = drop_doc(LOREM, drop_cap(2, 2));
|
||||
|
||||
Reference in New Issue
Block a user