mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-27 03:47:09 -06:00
Layout: a numbered paragraph opening with a page break takes its number along (#1616)
A heading whose text opens with a page break had its list number drawn on the line holding the break, so the number stood alone at the bottom of one page and the heading text started the next. Word draws the number with the text. The label now goes on the first line after a leading break. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
Brandon Thomas
parent
241743b4ab
commit
2444e64a25
@@ -668,7 +668,7 @@ fn lines(
|
||||
char_box(&ob, x0, x1, top, bottom, alpha, out);
|
||||
}
|
||||
// Label.
|
||||
if li == 0
|
||||
if li == pl.label_line()
|
||||
&& let Some(lab) = &pl.label
|
||||
{
|
||||
let gx = x + lab.x;
|
||||
|
||||
@@ -2484,6 +2484,16 @@ fn resolve_tab(pl: &mut ParaLayout, pending: &mut Option<(usize, TabStop, f32)>,
|
||||
}
|
||||
|
||||
impl ParaLayout {
|
||||
/// The line the list label is drawn on: the first, unless the paragraph opens with a page
|
||||
/// break, when Word draws it with the text on the next page.
|
||||
pub fn label_line(&self) -> usize {
|
||||
let opens_with_break = self.lines.len() > 1
|
||||
&& self.lines.first().is_some_and(|l| {
|
||||
l.end == LineEnd::PageBreak
|
||||
&& self.clusters.get(l.c0..l.c1).is_some_and(|cs| cs.iter().all(|c| matches!(c.kind, ClKind::PageBreak | ClKind::Marker)))
|
||||
});
|
||||
usize::from(opens_with_break)
|
||||
}
|
||||
/// x of byte offset `off` within line `li` (clamped to the line).
|
||||
pub fn x_of(&self, li: usize, off: usize) -> Option<f32> {
|
||||
let l = self.lines.get(li)?;
|
||||
|
||||
@@ -810,6 +810,26 @@ fn lists_get_labels_and_indent() {
|
||||
assert!((x - 108.0).abs() < 0.5, "{x}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_numbered_heading_opening_with_a_page_break_takes_its_number_along() {
|
||||
// "Before", then a numbered paragraph whose text opens with a page break: Word draws its
|
||||
// number on the next page with the text, not alone at the bottom of the first.
|
||||
let mut d = Document::from_text("Before\n\u{000C}Heading");
|
||||
let id = d.numbering.add_list(wordcraft_doc::ListKind::Numbered);
|
||||
d.format_paragraphs(&Pos::body(1, 0), &Pos::body(1, 1), &|p| p.numbering = Some(wordcraft_doc::props::NumRef { num: id, level: 0 })).unwrap();
|
||||
let l = lay(&d);
|
||||
let label_pages: Vec<usize> = l
|
||||
.pages
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, pg)| {
|
||||
flat(display::page_display(&d, pg, &Default::default())).iter().any(|x| matches!(x, display::Draw::Glyphs { text, .. } if text == "1."))
|
||||
})
|
||||
.map(|(i, _)| i)
|
||||
.collect();
|
||||
assert_eq!(label_pages, [1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn russian_letter_list_labels_draw_cyrillic() {
|
||||
// russianLower labelled items 1, 2, 3 instead of а), б), в).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Layout and pagination parity with Microsoft Word
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-14 · **Change:** trivial (a bookmark after a page break takes no line; previously trivial: a page break followed by a page break before or a next-page section starts one page; previously trivial: All Caps and Small Caps draw ß as SS, #1581; previously trivial: justified vertical page alignment, #1320; previously trivial: page numbers restart at 0; previously trivial: a list label moves with its first line when the paragraph is centred or end-aligned (#1159); previously trivial: PAGE fields in a paragraph split across pages show the page they are on, #1352; previously trivial: a dragged floating object anchors in the column it lands in, #884; previously trivial: a paragraph ending on a page with footnotes keeps its space after above the separator, #1116; previously trivial: symbol-font text drawn as Unicode symbols, #776; previously trivial: large-table scrolling measured and fixed, #811; previously trivial: text boxes use their own margins; Resize shape to fit text never cuts text, #743; previously trivial: complex-script shaping and Myanmar line breaking, #604; previously trivial: body page totals, table-cell footnotes and bookmark link pages fixed, #450 #451 #455; previously major: first version; line breaking, pagination and object placement checked against Word's behaviour from the layout source on origin/main) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-14 · **Change:** trivial (a list number stays with text after a leading page break; previously trivial: a bookmark after a page break takes no line; previously trivial: a page break followed by a page break before or a next-page section starts one page; previously trivial: All Caps and Small Caps draw ß as SS, #1581; previously trivial: justified vertical page alignment, #1320; previously trivial: page numbers restart at 0; previously trivial: a list label moves with its first line when the paragraph is centred or end-aligned (#1159); previously trivial: PAGE fields in a paragraph split across pages show the page they are on, #1352; previously trivial: a dragged floating object anchors in the column it lands in, #884; previously trivial: a paragraph ending on a page with footnotes keeps its space after above the separator, #1116; previously trivial: symbol-font text drawn as Unicode symbols, #776; previously trivial: large-table scrolling measured and fixed, #811; previously trivial: text boxes use their own margins; Resize shape to fit text never cuts text, #743; previously trivial: complex-script shaping and Myanmar line breaking, #604; previously trivial: body page totals, table-cell footnotes and bookmark link pages fixed, #450 #451 #455; previously major: first version; line breaking, pagination and object placement checked against Word's behaviour from the layout source on origin/main) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
|
||||
|
||||
A document only "opens correctly" if its pages break where Word breaks them: the same lines, the
|
||||
same page count, footnotes and pictures on the same pages. This checklist covers line breaking,
|
||||
@@ -159,6 +159,7 @@ No overall parity estimate changes from these probes.
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-14 | trivial | A numbered paragraph whose text opens with a page break draws its number on the next page with the text, as Word does |
|
||||
| 2026-10-14 | trivial | A bookmark (or other zero-width marker) after a paragraph's closing page break stays with the break instead of taking a line at the top of the next page |
|
||||
| 2026-10-14 | trivial | A paragraph of only a page break followed by a page break before, or carrying a next-page section break, starts one page, not two: the break's mark and its space after stay on the page before, as in Word |
|
||||
| 2026-10-13 | trivial | Justified vertical page alignment (#1320): the page's spare room goes equally between its blocks; a section's last page takes its own section's vertical alignment, not the next one's |
|
||||
|
||||
Reference in New Issue
Block a user