diff --git a/crates/eps/src/ai_editing/tests.rs b/crates/eps/src/ai_editing/tests.rs index f25944060..42d3c7d73 100644 --- a/crates/eps/src/ai_editing/tests.rs +++ b/crates/eps/src/ai_editing/tests.rs @@ -833,6 +833,40 @@ fn nested_symbol_instances_stop_at_the_symbol_art_limit() { assert_eq!(layers.matches("\r\nf\r\n").count(), 3198, "the squares of the leaves written"); } +/// On a canvas of the usual size, nested symbols whose instances multiply, written as their art in +/// art cut to a clipping object, stop at [`vectorcraft_doc::MAX_SYMBOL_NODES`] objects of symbol art +/// in all, with a warning. +#[test] +fn clipped_nested_symbol_instances_stop_at_the_symbol_art_limit() { + let mut doc = Document::new(200.0, 100.0); + let layer = doc.layers[0].id; + // Empty paths: counted, but written as nothing, so the test stays small; and one filled square. + let empty = Arc::new(Node::path(doc.alloc_id(), PathData::new(vec![]), Appearance::default())); + let mut members = vec![empty; 4999]; + let square_art = shapes::rectangle(Rect::new(0.0, 0.0, 1.0, 1.0)); + members.push(Arc::new(Node::path(doc.alloc_id(), square_art, Appearance::basic(solid(Color::gray(0.5)), Paint::None, 0.0)))); + let leaves = Node::group(doc.alloc_id(), members); + doc.symbols.push(Symbol { dynamic: false, name: "Leaf".into(), art: Arc::new(leaves) }); + let leaf = Arc::new(Node::new(doc.alloc_id(), NodeKind::SymbolInstance { symbol: "Leaf".into(), xf: Affine::IDENTITY })); + let trees = Node::group(doc.alloc_id(), vec![leaf; 5000]); + doc.symbols.push(Symbol { dynamic: false, name: "Tree".into(), art: Arc::new(trees) }); + let tree = Node::new(doc.alloc_id(), NodeKind::SymbolInstance { symbol: "Tree".into(), xf: Affine::IDENTITY }); + // A group as the clipping object cuts the art instead of clipping it with a path, so the + // instances in it are written as their art. Its square is unpainted, so the only filled squares + // are the leaves'. + let outline = Node::path(doc.alloc_id(), shapes::rectangle(Rect::new(0.0, 0.0, 50.0, 50.0)), Appearance::default()); + let clip = group(&mut doc, vec![outline], false); + let clipped = group(&mut doc, vec![clip, tree], true); + doc.insert(Some(layer), usize::MAX, clipped).unwrap(); + let out = export_ai_editing(&doc, &opts()).unwrap(); + assert!(out.warnings.iter().any(|w| w == writer::SYMBOL_LIMIT), "{:?}", out.warnings); + assert!(out.warnings.iter().any(|w| w == writer::SYMBOL_ART), "{:?}", out.warnings); + // 5,001 objects for the tree and each leaf: 3,198 leaves fit in 16,000,000. + let text = String::from_utf8(out.program).unwrap(); + let layers = text.split_once("%%EndSetup").unwrap().1; + assert_eq!(layers.matches("\r\nf\r\n").count(), 3198, "the squares of the leaves written"); +} + #[test] fn a_stained_symbol_instance_is_written_in_its_stained_colors() { let mut doc = Document::new(200.0, 100.0);