Browse / github.com/storytold/designcraft / patch
An item a parent overrode and deleted is gone from the pages that use it (#1469)
IDML import shows a parent item that a child parent overrode and deleted **Problem:** in InDesign, removing an inherited item from a parent page works by overriding it and deleting the override. In IDML that is a `Page` whose `OverrideList` names the item while no page item with `OverriddenMasterPageItem` pointing to it exists. DesignCraft still draws the base parent's item. In our document a signature block from parent B overlaps the notice text on every page using parent E (E is based on B and removed the block). **Expectation:** an item listed in `OverrideList` without an overriding copy is not drawn on that parent or on pages using it. **Repro:** `designcraft
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- Hamza0101 (imported from pull request #1558, open)
- Base
3ce3a24f08d03935bc8cf7cb23755aca8065558c- Size
- +62 −2 in 1 file
- Review
- pending
- Shared
- 2026-10-28
- Id
a25bd81deba7c80d60f8c768
How it went
No other operator has reported using it yet.
Diff
raw · crates/render/src/lib.rs
@@ -496,12 +496,28 @@ impl Renderer { if !page.show_parent_items { continue; }- for (ppi, ppage) in doc.shown_parent_pages(sr, pi) {+ let chain = doc.shown_parent_pages(sr, pi);+ // This page's overrides, and those of every parent page behind it: a parent that+ // overrode an item of the parent it is based on and then deleted the override+ // removed that item from itself and from the pages that use it (#1469). An+ // override always names an item of a parent further back, so one set does.+ let overridden: Vec<designcraft_doc::ItemId> = page+ .overridden+ .iter()+ .copied()+ .chain(+ chain+ .iter()+ .filter_map(|(ppi, ppage)| doc.parents.get(*ppi)?.pages.get(*ppage))+ .flat_map(|ppg| ppg.overridden.iter().copied()),+ )+ .collect();+ for (ppi, ppage) in chain { let Some(parent) = doc.parents.get(ppi) else { continue }; let Some(ppg) = parent.pages.get(ppage) else { continue }; let dx = page.x - ppg.x; for it in &parent.items {- if it.layer != layer.id || page.overridden.contains(&it.id) {+ if it.layer != layer.id || overridden.contains(&it.id) { continue; } // Parent items belong to the parent page they sit on.@@ -1717,6 +1733,50 @@ mod tests { assert!(paper(103, 103) && ink(108, 108) && paper(114, 114)); } + /// In InDesign, removing an inherited item from a parent page means overriding it there and+ /// deleting the override: the parent's page keeps the item in its override list with no copy+ /// of its own. The pages that use that parent still drew the base's item — a signature block+ /// from parent B over the notice text of every page using parent E (#1469).+ #[test]+ fn an_item_a_parent_overrode_and_deleted_is_gone_from_the_pages_that_use_it() {+ let mut d = Document::new(&NewDocument { pages: 1, facing_pages: false, ..Default::default() });+ let lid = d.default_layer();+ // Parent A: a black box. Parent B: based on A, nothing of its own.+ let a = d.parents[0].id;+ let margins = d.parents[0].pages[0].margins;+ let b = d.add_parent("B", "Parent", 1, 0.0, margins);+ let box_id = designcraft_doc::ItemId(d.alloc());+ let rect = Rect::new(100.0, 100.0, 200.0, 160.0);+ let mut it = Item::new(box_id, lid, designcraft_doc::Shape::Rectangle, designcraft_geom::shapes::rectangle(rect));+ it.fill = designcraft_doc::Fill::swatch(designcraft_color::swatch::BLACK);+ d.insert_item(SpreadRef::Parent(0), it, None).unwrap();+ {+ let bp = std::sync::Arc::make_mut(&mut d.parents[1]);+ bp.parent.as_mut().unwrap().based_on = Some(a);+ }+ std::sync::Arc::make_mut(&mut d.spreads[0]).pages[0].parent = Some(b);+ let ink = |d: &Document, r: &mut Renderer| {+ let img = r.render_page(d, &Cache::new(), 0, 1.0, false, &RenderOptions::default()).unwrap();+ img.pixel(rect.center().x as u32, rect.center().y as u32)[0] < 64+ };+ let mut r = Renderer::new();+ r.threads = 0;+ assert!(ink(&d, &mut r), "the page shows parent A's box through parent B");++ // B overrides the box and the override is deleted: B's page keeps it in its override list.+ std::sync::Arc::make_mut(&mut d.parents[1]).pages[0].overridden.push(box_id);+ let mut r = Renderer::new();+ r.threads = 0;+ assert!(!ink(&d, &mut r), "the box is removed on B, so the page using B does not show it");++ // Removing the override on B brings it back, which is how InDesign's Remove All Local+ // Overrides behaves.+ std::sync::Arc::make_mut(&mut d.parents[1]).pages[0].overridden.clear();+ let mut r = Renderer::new();+ r.threads = 0;+ assert!(ink(&d, &mut r), "the box shows again");+ }+ #[test] fn arrowheads_draw_at_line_ends() { let mut d = Document::new(&NewDocument::default());