This commit is contained in:
Brandon Thomas
2026-10-14 01:54:39 -04:00
2 changed files with 51 additions and 6 deletions
+28 -6
View File
@@ -591,8 +591,11 @@ fn compose_with_db(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &C
.and_then(|t| t.chars().next_back())
.and_then(break_start);
if let Some(t) = story.para_table(pi) {
let start = after_break.unwrap_or(pp.start_paragraph);
if cur.last_baseline.is_some() {
cur.start(after_break.unwrap_or(pp.start_paragraph), &cols, frames, doc);
cur.start(start, &cols, frames, doc);
} else {
cur.start_at_top(start, frames, doc);
}
let at_top = cur.last_baseline.is_none();
let start_at = (cur.fi, cur.col);
@@ -847,17 +850,22 @@ fn compose_with_db(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &C
StartParagraph::NextColumn => next_column(cur),
other => cur.start(other, &cols, frames, doc),
};
// Paragraph start options.
if let Some(start) = after_break
&& cur.last_baseline.is_some()
{
begin_at(&mut cur, start);
// Paragraph start options. At the top of a frame there is nothing to break away from, but
// an odd or even page start still has to land on a page of that parity.
if let Some(start) = after_break {
if cur.last_baseline.is_some() {
begin_at(&mut cur, start);
} else {
cur.start_at_top(start, frames, doc);
}
}
if force_col[pi] {
next_column(&mut cur);
}
if cur.last_baseline.is_some() {
begin_at(&mut cur, pp.start_paragraph);
} else {
cur.start_at_top(pp.start_paragraph, frames, doc);
}
if spanning && cur.fi < frames.len() {
// Close the band: the paragraph goes below the deepest of its columns, which are
@@ -2070,6 +2078,20 @@ impl Cursor {
StartParagraph::NextEvenPage => self.next_page(frames, doc, Some(false)),
}
}
/// A start option for a paragraph at the top of a frame: there is nothing to break away from,
/// but an odd or even page start still has to land on a page of that parity, so a paragraph
/// at the top of an even page that asks for the next odd page moves on (and vice versa).
fn start_at_top(&mut self, start: StartParagraph, frames: &[FrameSpec], doc: &Document) {
let want_odd = match start {
StartParagraph::NextOddPage => true,
StartParagraph::NextEvenPage => false,
_ => return,
};
let Some(page) = frames.get(self.fi).and_then(|f| f.page) else { return };
if (doc.page_number(page) % 2 == 1) != want_odd {
self.next_page(frames, doc, Some(want_odd));
}
}
/// Move to the next frame on a later page, one with an odd page number (`odd` true) or an
/// even one (false) when asked. Frames without a page (parent pages) qualify; with no frame
/// left, the rest of the story is overset.
+23
View File
@@ -834,6 +834,29 @@ fn break_characters_end_their_paragraph_and_keep_page_parity() {
assert_eq!(cs.overset_at, Some(text.find("four").unwrap()));
}
/// A paragraph that starts at the top of a frame isn't pushed on by Next Page, but Next Odd Page
/// (or Next Even Page) still moves it when that frame is on a page of the other parity.
#[test]
fn odd_and_even_page_starts_keep_parity_at_the_top_of_a_frame() {
use designcraft_doc::StartParagraph;
use designcraft_doc::story::PAGE_BREAK;
let pages_of = |start: StartParagraph| {
let mut d = Document::new(&NewDocument { pages: 4, facing_pages: false, primary_text_frame: true, ..Default::default() });
let sid = d.settings.primary_story.unwrap();
// "two" begins at the top of page 2, after the page break that ends "one".
d.story_mut(sid).unwrap().insert(0, &format!("one{PAGE_BREAK}\ntwo\nthree"));
d.story_mut(sid).unwrap().paras[1].para.start_paragraph = Some(start);
let cs = compose_story(&d, sid, &ComposeOptions::default());
// Frame i is on page i + 1.
cs.frames.iter().enumerate().flat_map(|(fi, f)| f.lines.iter().map(move |l| (l.para, fi + 1))).collect::<Vec<_>>()
};
// Already at the top of an even page: Next Page and Next Even Page leave "two" where it is.
assert_eq!(pages_of(StartParagraph::NextPage), vec![(0, 1), (1, 2), (2, 2)]);
assert_eq!(pages_of(StartParagraph::NextEvenPage), vec![(0, 1), (1, 2), (2, 2)]);
// Next Odd Page takes it to page 3, leaving page 2 empty.
assert_eq!(pages_of(StartParagraph::NextOddPage), vec![(0, 1), (1, 3), (2, 3)]);
}
#[test]
fn line_before_a_break_character_is_a_last_line() {
// As in InDesign: column, frame and page breaks end the paragraph's last line (set with the