diff --git a/crates/model/src/style.rs b/crates/model/src/style.rs index 83c494bd..e3369f35 100644 --- a/crates/model/src/style.rs +++ b/crates/model/src/style.rs @@ -324,6 +324,7 @@ pub struct Line { pub dash: Option, pub cap: Option, pub join: Option, + pub miter_limit: Option, pub compound: Option, pub head: Option, pub tail: Option, @@ -347,6 +348,7 @@ impl Line { } self.cap = self.cap.or(parent.cap); self.join = self.join.or(parent.join); + self.miter_limit = self.miter_limit.or(parent.miter_limit); self.compound = self.compound.or(parent.compound); if self.head.is_none() { self.head.clone_from(&parent.head); diff --git a/crates/pptx/src/read/dml.rs b/crates/pptx/src/read/dml.rs index 767b7dc0..e1e5dcd4 100644 --- a/crates/pptx/src/read/dml.rs +++ b/crates/pptx/src/read/dml.rs @@ -232,7 +232,10 @@ pub fn line(imp: &mut Imp, part: &Part, ln: &El) -> Line { } "round" => l.join = Some(LineJoin::Round), "bevel" => l.join = Some(LineJoin::Bevel), - "miter" => l.join = Some(LineJoin::Miter), + "miter" => { + l.join = Some(LineJoin::Miter); + l.miter_limit = e.attr("lim").and_then(|v| v.parse::().ok()).filter(|v| *v <= 1_000_000); + } "headEnd" => l.head = line_end(e), "tailEnd" => l.tail = line_end(e), _ => {} diff --git a/crates/pptx/src/write/dml.rs b/crates/pptx/src/write/dml.rs index 518f8c4a..a6d00ff4 100644 --- a/crates/pptx/src/write/dml.rs +++ b/crates/pptx/src/write/dml.rs @@ -233,7 +233,7 @@ pub fn line(w: &mut W, x: &mut Exp, o: &mut Out, tag: &str, l: &Line) { match l.join { Some(LineJoin::Round) => w.empty0("a:round"), Some(LineJoin::Bevel) => w.empty0("a:bevel"), - Some(LineJoin::Miter) => w.empty0("a:miter"), + Some(LineJoin::Miter) => w.empty("a:miter", A::new().o("lim", l.miter_limit)), None => {} } for (t, e) in [("a:headEnd", &l.head), ("a:tailEnd", &l.tail)] { diff --git a/crates/pptx/tests/it/roundtrip.rs b/crates/pptx/tests/it/roundtrip.rs index 370cc9a9..59904071 100644 --- a/crates/pptx/tests/it/roundtrip.rs +++ b/crates/pptx/tests/it/roundtrip.rs @@ -488,6 +488,20 @@ fn shapes_fills_lines_effects_round_trip() { assert_eq!(by_name(&q.slides[1], "Group").id, by_name(&p.slides[1], "Group").id); } +#[test] +fn line_miter_limit_survives_two_pptx_round_trips() { + let mut p = Presentation::default(); + let mut limited = shape(&mut p, "Limited miter", 20.0, 20.0, 100.0, 100.0); + limited.line = Some(Line { join: Some(deckcraft_model::style::LineJoin::Miter), miter_limit: Some(200_000), ..Default::default() }); + let mut defaulted = shape(&mut p, "Default miter", 140.0, 20.0, 100.0, 100.0); + defaulted.line = Some(Line { join: Some(deckcraft_model::style::LineJoin::Miter), ..Default::default() }); + Arc::make_mut(&mut p.slides[0]).shapes.extend([limited, defaulted]); + + let q = round(&round(&p)); + assert_eq!(by_name(&q.slides[0], "Limited miter").line.as_ref().and_then(|line| line.miter_limit), Some(200_000)); + assert_eq!(by_name(&q.slides[0], "Default miter").line.as_ref().and_then(|line| line.miter_limit), None); +} + #[test] fn pictures_media_and_ink_round_trip() { let p = rich_deck();