Merge pull request #7466 from dotCooCoo/fix/ai-wrap-options-edge-cases

.ai save: text wrap fixes for cut-away clipping fills and symbols without room
This commit is contained in:
BFlat
2026-11-15 04:22:46 +07:00
committed by GitHub
+47
View File
@@ -1187,6 +1187,32 @@ fn a_symbol_definition_is_written_only_with_room_for_its_instance() {
}
}
/// A live instance inside a stained instance's art, whose definition has no room left, is left out
/// without upsetting the art around it: with room for any number of objects the export finishes,
/// within that room.
#[test]
fn a_definition_without_room_inside_drawn_art_is_left_out() {
let mut doc = Document::new(200.0, 100.0);
let layer = doc.layers[0].id;
let leaf = square(&mut doc, Rect::new(0.0, 0.0, 10.0, 10.0), LEAF);
doc.symbols.push(Symbol { dynamic: false, name: "Leaf".into(), art: Arc::new(leaf) });
let inner = instance(&mut doc, "Leaf", Affine::translate((5.0, 5.0)));
let side = square(&mut doc, Rect::new(20.0, 0.0, 30.0, 10.0), Color::gray(0.5));
let art = group(&mut doc, vec![inner, side], false);
doc.symbols.push(Symbol { dynamic: false, name: "Branch".into(), art: Arc::new(art) });
let mut stained = instance(&mut doc, "Branch", Affine::translate((50.0, 10.0)));
stained.appearance = Appearance::basic(solid(Color::rgb(1.0, 0.0, 0.0)), Paint::None, 0.0).into();
doc.insert(Some(layer), usize::MAX, stained).unwrap();
add_rect(&mut doc, Rect::new(150.0, 10.0, 160.0, 20.0));
let read = crate::import::objects_read(&export_ai_editing(&doc, &opts()).unwrap().program).unwrap();
for max in 0..read {
let out = export_within(&doc, &opts(), max).unwrap();
assert!(out.warnings.iter().any(|w| w == writer::OBJECT_LIMIT), "art is left out with room for {max} of {read} objects");
let objects = crate::import::objects_read(&out.program).unwrap();
assert!(objects <= max, "{objects} objects read with room for {max}");
}
}
/// A symbol definition without room for its group, asked for by an instance in art drawn for an
/// object (a stained instance's art), is left out and leaves the writing of that art as it was.
#[test]
@@ -10695,4 +10721,25 @@ fn a_clipping_path_written_as_its_paint_keeps_one_text_wrap() {
assert_eq!(text.matches("(AI11TextWrapOffset)").count(), 1, "{text}");
same_wraps(&wraps(read_back(&doc).layers[0].children().unwrap()), &[(None, 5.0, true)]);
}
// The outer clipping object ends at x = 100 and the clipping path's fill starts at x = 101: the
// fill is cut away and writes nothing, and its 4 pt stroke, which reaches x = 99, keeps the
// options, whether or not the fill's lock state is written before it.
for locked in [false, true] {
let mut doc = Document::new(200.0, 100.0);
let layer = doc.layers[0].id;
let mut cutter = clipping(&mut doc, shapes::rectangle(Rect::new(101.0, 20.0, 150.0, 80.0)));
cutter.appearance = Appearance::basic(solid(Color::gray(0.5)), solid(Color::BLACK), 4.0).into();
cutter.locked = locked;
let cutter = wrapped(cutter, 5.0, true);
let member = square(&mut doc, Rect::new(110.0, 30.0, 140.0, 60.0), Color::rgb(1.0, 0.0, 0.0));
let inner = group(&mut doc, vec![cutter, member], true);
let frame = square(&mut doc, Rect::new(0.0, 0.0, 100.0, 100.0), Color::gray(0.9));
let frame = group(&mut doc, vec![frame], false);
let outer = group(&mut doc, vec![frame, inner], true);
doc.insert(Some(layer), usize::MAX, outer).unwrap();
let text = program(&doc);
assert_eq!(text.matches("(AI11TextWrapOffset)").count(), 1, "locked {locked}: {text}");
same_wraps(&wraps(read_back(&doc).layers[0].children().unwrap()), &[(None, 5.0, true)]);
}
}