Integration: placed graphics take text wrap from their object style (#389)

A graphic element that names an AppliedObjectStyle reads its
TextWrapPreference through with_style, so mode, side, offsets and
ContourOption come from the style where the graphic sets none. Test:
text_wrap_side_and_contour_come_from_the_style_for_frames_and_placed_graphics.

Also: swatch_ref's doc comment sits on swatch_ref again.
This commit is contained in:
aiongg
2026-10-10 23:37:01 +00:00
parent 06baf887fb
commit 75ce3f88e0
2 changed files with 30 additions and 3 deletions
+6 -3
View File
@@ -890,7 +890,6 @@ impl<'r> Importer<'r> {
Color::BLACK
}
/// A swatch reference (Self id) → our swatch name; unnamed colours become value-named swatches.
/// A `TextFramePreference`, with its column rule colour resolved to a swatch.
fn frame_options(&mut self, prefs: &[&El]) -> TextFrameOptions {
let mut o = text_frame_options(prefs);
@@ -900,6 +899,7 @@ impl<'r> Importer<'r> {
o
}
/// A swatch reference (Self id) → our swatch name; unnamed colours become value-named swatches.
fn swatch_ref(&mut self, r: &str) -> String {
if let Some(n) = self.swatch_names.get(r) {
return n.clone();
@@ -2590,6 +2590,8 @@ impl<'r> Importer<'r> {
None => (0.0, 0.0, 0.0, 0.0),
};
let size = ((r - l).abs(), (b - t).abs());
let wrap = if g.get("AppliedObjectStyle").is_some() { self.with_style(g, "TextWrapPreference") } else { g.find("TextWrapPreference").cloned() };
let wrap = wrap.map(|w| text_wrap(&w)).unwrap_or_default();
let link = g.find("Link");
let uri = link.and_then(|k| k.get("LinkResourceURI")).map(uri_to_path);
let mut data = g.prop_el("Contents").map(|c| base64_decode(&c.text_content())).unwrap_or_default();
@@ -2627,8 +2629,9 @@ impl<'r> Importer<'r> {
auto_fit: Default::default(),
fit_align: 4,
crop: [0.0; 4],
// A wrap set on the placed graphic (Direct Selection) is stored on the graphic element.
wrap: g.find("TextWrapPreference").map(text_wrap).unwrap_or_default(),
// A wrap set on the placed graphic (Direct Selection) is stored on the graphic element, over
// the graphic's own object style when it names one.
wrap,
})
}
+24
View File
@@ -166,3 +166,27 @@ fn exported_frames_keep_their_own_values_over_their_object_style() {
let got = back.spreads[0].items.iter().find(|i| i.object_style == "Ruled").and_then(|i| i.text_frame()).unwrap();
assert_eq!(got.options, want);
}
#[test]
fn text_wrap_side_and_contour_come_from_the_style_for_frames_and_placed_graphics() {
let styles = r#"<ObjectStyle Self="ObjectStyle/Contour" Name="Contour">
<Properties><BasedOn type="string">$ID/[None]</BasedOn></Properties>
<TextWrapPreference TextWrapMode="Contour" TextWrapSide="LeftSide">
<Properties><TextWrapOffset Top="3" Left="3" Bottom="3" Right="3"/></Properties>
<ContourOption ContourType="BoundingBox"/>
</TextWrapPreference>
</ObjectStyle>"#;
let image = r#"<Image Self="g" AppliedObjectStyle="ObjectStyle/Contour">
<TextWrapPreference TextWrapSide="RightSide"/>
</Image>"#;
let d = fixture(styles, &[(r#"AppliedObjectStyle="ObjectStyle/Contour""#, ""), ("", image)]);
let frame = &d.spreads[0].items[0].wrap;
assert_eq!(frame.mode, designcraft_doc::WrapMode::Contour);
assert_eq!(frame.side, designcraft_doc::WrapSide::LeftSide);
assert_eq!(frame.contour, designcraft_doc::ContourType::BoundingBox);
assert_eq!(frame.offsets, [3.0; 4]);
let designcraft_doc::Content::Graphic(g) = &d.spreads[0].items[1].content else { panic!("{:?}", d.spreads[0].items[1].content) };
assert_eq!(g.wrap.mode, designcraft_doc::WrapMode::Contour);
assert_eq!(g.wrap.side, designcraft_doc::WrapSide::RightSide, "the graphic's own side wins");
assert_eq!(g.wrap.contour, designcraft_doc::ContourType::BoundingBox);
}