mirror of
https://github.com/storytold/wordcraft.git
synced 2026-11-01 14:27:16 -06:00
Layout: page numbers can restart at 0 (#1601)
w:pgNumType w:start="0" was read but laid out as 1: the page counter was set to one less than the restart and could not go below zero. A report numbering its cover 0 read "Page 2" on the page Word calls 1. The restart is now the next page's number itself. 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
e9e8af517c
commit
ba1e28382d
@@ -1400,6 +1400,9 @@ struct PageBuilder<'a> {
|
||||
/// The previous paragraph ended with a page break (its mark stayed with the break): the next
|
||||
/// paragraph, first on the new page, gets no space before (Word).
|
||||
after_break_mark: bool,
|
||||
/// The number the next page takes instead of counting on: a section restarting its
|
||||
/// numbering, possibly at 0 (a cover page numbered 0).
|
||||
restart_at: Option<u32>,
|
||||
/// Wrap areas of floating objects on this page (see [`wrap_area`]).
|
||||
excl: Vec<WrapArea>,
|
||||
/// Wrap areas of the floating tables on this page, which others may not overlap.
|
||||
@@ -1815,7 +1818,7 @@ impl PageBuilder<'_> {
|
||||
self.line_no = 0;
|
||||
}
|
||||
let s = self.sect;
|
||||
self.number = self.number.saturating_add(1);
|
||||
self.number = self.restart_at.take().unwrap_or_else(|| self.number.saturating_add(1));
|
||||
let (w, h) = if self.web { (s.page_w, f32::MAX / 4.0) } else { (s.page_w, s.page_h) };
|
||||
// A footer taller than the bottom margin pushes the body up (Word: no gap), leaving it at
|
||||
// least a little room.
|
||||
@@ -2045,6 +2048,7 @@ fn layout_pass(
|
||||
orig_bottom: 0.0,
|
||||
prev: None,
|
||||
after_break_mark: false,
|
||||
restart_at: None,
|
||||
excl: Vec::new(),
|
||||
float_tables: Vec::new(),
|
||||
line_no: 0,
|
||||
@@ -2137,8 +2141,8 @@ fn layout_pass(
|
||||
pb.sect = sect;
|
||||
pb.sect_idx = si;
|
||||
}
|
||||
if let Some(n) = restart {
|
||||
pb.number = n.saturating_sub(1);
|
||||
if restart.is_some() {
|
||||
pb.restart_at = restart;
|
||||
}
|
||||
pb.foot_top = first_foot;
|
||||
pb.new_page(block, first_top);
|
||||
|
||||
@@ -688,6 +688,15 @@ fn page_break_char_starts_new_page() {
|
||||
assert_eq!(l.pages.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn page_numbers_can_restart_at_zero() {
|
||||
// `w:pgNumType w:start="0"`: a cover page numbered 0, so the page after it reads 1.
|
||||
let mut d = Document::from_text("Cover\u{000C}Contents");
|
||||
d.last_section.page_num_start = Some(0);
|
||||
let numbers: Vec<u32> = lay(&d).pages.iter().map(|p| p.number).collect();
|
||||
assert_eq!(numbers, [0, 1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn center_and_right_alignment() {
|
||||
let mut d = Document::from_text("abc\nabc\nabc");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Layout and pagination parity with Microsoft Word
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-14 · **Change:** trivial (justified vertical page alignment, #1320; previously trivial: a table's percentage width past 100% is kept; 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 (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,
|
||||
@@ -165,6 +165,7 @@ No overall parity estimate changes from these probes.
|
||||
| 2026-10-14 | trivial | A word too wide for the strip beside a square-wrapped object moves past it whole instead of being split across the strip (#1376) |
|
||||
| 2026-10-14 | trivial | Russian letter list formats (`russianLower`, `russianUpper`) draw а) б) в) … аа) бб) as Word does, instead of digits |
|
||||
| 2026-10-14 | trivial | A table's percentage width past 100% is kept, so a table pulled into the margins spans them as in Word |
|
||||
| 2026-10-14 | trivial | A section can restart its page numbers at 0 (`w:pgNumType w:start="0"`), as a cover page numbered 0 does; the restart was read but laid out from 1 |
|
||||
| 2026-10-13 | trivial | A shape or picture dragged into another column anchors there, so the text in that column wraps around it (#884) |
|
||||
| 2026-10-13 | trivial | On a page with footnotes, a paragraph that ends there keeps its space after above the footnote separator; if it doesn't fit, its last line (and, with widow control, one more) goes to the next page with the note. Pages without notes are unchanged (#1116) |
|
||||
| 2026-10-12 | trivial | STYLEREF fields in headers and footers show each page's chapter (or other styled text); Insert › Quick Parts › Field offers STYLEREF (#775) |
|
||||
|
||||
Reference in New Issue
Block a user