Baseline grid: find the page under a grouped frame from its spread position

A group's transform can move a frame onto another page; the page lookup
used the frame's bounds without its parents' transforms, so the grid took
the wrong page's top margin.
This commit is contained in:
aiongg
2026-10-24 04:39:34 +00:00
parent 14da000a35
commit 05901d3ec1
2 changed files with 31 additions and 4 deletions
+5 -4
View File
@@ -686,17 +686,18 @@ pub fn frame_specs(doc: &Document, sid: StoryId) -> Vec<FrameSpec> {
r.is_finite() && r.x0 < a.x1 && r.x1 > a.x0 && r.y0 < a.y1 && r.y1 > a.y0
});
}
// The frame's center on its spread: a group around it can move it to another page.
let center_x = loc.as_ref().map_or(item.bounds(), |l| doc.parent_xf(l).transform_rect_bbox(item.bounds())).center().x;
let (page_name, page, left_page) = match (spread_ref, spread) {
(Some(designcraft_doc::SpreadRef::Doc(si)), Some(sp)) => {
let c = item.bounds().center();
let pi = sp.page_at_x(c.x).unwrap_or(0);
let pi = sp.page_at_x(center_x).unwrap_or(0);
let abs = doc.first_page_of_spread(si) + pi;
(Some(doc.page_name(abs)), Some(abs), sp.pages.get(pi).is_some_and(|p| p.side == designcraft_doc::PageSide::Left))
}
(Some(designcraft_doc::SpreadRef::Parent(_)), Some(sp)) => {
let prefix = sp.parent.as_ref().map(|p| p.prefix.clone()).unwrap_or_else(|| "A".into());
// The side of the parent page under the frame, so a folio there aligns to the spine of its own page.
let under = sp.page_at_x(item.bounds().center().x).and_then(|pi| sp.pages.get(pi));
let under = sp.page_at_x(center_x).and_then(|pi| sp.pages.get(pi));
let left = under.is_some_and(|p| p.side == designcraft_doc::PageSide::Left);
(Some(prefix), None, left)
}
@@ -704,7 +705,7 @@ pub fn frame_specs(doc: &Document, sid: StoryId) -> Vec<FrameSpec> {
};
let section_marker = page.map(|abs| section_marker(doc, abs));
// The page under the frame, and its bounds and margins in inner space (bounding boxes).
let under = spread.and_then(|sp| sp.page_at_x(item.bounds().center().x).and_then(|pi| sp.pages.get(pi)));
let under = spread.and_then(|sp| sp.page_at_x(center_x).and_then(|pi| sp.pages.get(pi)));
let page_rect = under.map(|pg| (inv.transform_rect_bbox(pg.bounds()), inv.transform_rect_bbox(pg.margin_rect())));
let g = &doc.settings.baseline_grid;
let (inc, start) = tf.options.baseline_grid.unwrap_or((g.increment, under.map_or(g.start, |pg| g.origin(pg))));
+26
View File
@@ -7254,6 +7254,32 @@ fn baseline_grid_relative_to_the_top_margin_starts_at_each_pages_margin() {
assert_eq!(lines.len(), 41);
}
/// A group's transform moves a frame from the left page of a spread to the right one: the grid
/// starts at the right page's top margin.
#[test]
fn baseline_grid_follows_a_grouped_frame_to_its_page() {
use designcraft_doc::{Content, GridRelative, Item, ItemId, Shape};
let mut d = Document::new(&NewDocument { pages: 3, facing_pages: true, margins: designcraft_doc::Margins::uniform(36.0), ..Default::default() });
Arc::make_mut(&mut d.spreads[1]).pages[1].margins.top = 48.0;
d.settings.baseline_grid.start = 0.0;
d.settings.baseline_grid.increment = 13.0;
d.settings.baseline_grid.relative_to = GridRelative::TopMargin;
let lid = d.default_layer();
let para = ParaFormat { para: ParaAttrs { grid_align: Some(GridAlign::AllLines), ..Default::default() }, ..Default::default() };
let (fid, sid) = d.add_text_frame(SpreadRef::Doc(1), Rect::new(36.0, 36.0, 336.0, 582.0), lid, LOREM, para).unwrap();
let sp = Arc::make_mut(&mut d.spreads[1]);
let at = sp.items.iter().position(|it| it.id == fid).unwrap();
let frame = sp.items.remove(at);
let right = sp.pages[1].x;
let mut g = Item::new(ItemId(d.alloc()), lid, Shape::Group, designcraft_geom::PathData::default());
g.content = Content::Group { items: vec![frame] };
g.xf = designcraft_geom::Affine::translate((right, 0.0));
Arc::make_mut(&mut d.spreads[1]).items.push(Arc::new(g));
let cs = compose_story(&d, sid, &ComposeOptions::default());
let first = cs.frames[0].lines[0].baseline;
assert!((first - 61.0).abs() < 1e-6, "{first}");
}
#[test]
fn cache_recomposes_when_the_grid_reference_or_a_top_margin_changes() {
use designcraft_doc::GridRelative;