Integration (#636): bracket clamps can't panic on a NaN path length

This commit is contained in:
aiongg
2026-10-13 01:02:40 +00:00
parent ebae0c7805
commit 6b2e319f96
4 changed files with 16 additions and 3 deletions
+1 -1
View File
@@ -716,7 +716,7 @@ pub fn frame_specs(doc: &Document, sid: StoryId) -> Vec<FrameSpec> {
// Keep the path identity: its synthetic area uses full line extents.
..tf.options.clone()
};
let end = pt.end.map_or(len, |e| e.clamp(0.0, len));
let end = pt.end.map_or(len, |e| e.max(0.0).min(len));
(Rect::new(0.0, 0.0, (end - pt.start).max(1.0), size * 1.6), opts)
}
None => (item.text_area(), tf.options.clone()),
+13
View File
@@ -2533,6 +2533,19 @@ fn path_text_keeps_the_original_vertical_fit_limit() {
}
}
/// A path whose length is NaN (a NaN point from a damaged file) composes without panicking on the
/// end bracket's clamp.
#[test]
fn path_text_with_a_nan_length_composes() {
let (mut d, sid, fid) = doc_with("HELLO", Rect::new(0.0, 0.0, 200.0, 100.0), ParaAttrs::default());
let it = d.item_mut(fid).unwrap();
it.shape = designcraft_doc::Shape::Path;
it.path = designcraft_geom::shapes::line(Point::ZERO, Point::new(f64::NAN, 0.0));
it.text_frame_mut().unwrap().options.path =
Some(designcraft_doc::PathType { start: 0.0, end: Some(50.0), flip: false, align: designcraft_doc::PathAlign::Baseline });
let _ = compose_story(&d, sid, &ComposeOptions::default());
}
fn two_keep_frames(text: &str) -> (Document, StoryId, ItemId, ItemId) {
let (mut d, sid, first) = baseline_fit_doc(text, 48.0);
d.item_mut(first).unwrap().path = designcraft_geom::shapes::rectangle(Rect::new(0.0, 0.0, 75.0, 48.0));
+1 -1
View File
@@ -97,7 +97,7 @@ fn path_options(s: &mut Session, p: &Value) -> Result<Value> {
return Ok(json!({"deleted": true}));
}
if let Some(v) = p.get("start").and_then(Value::as_f64).filter(|v| v.is_finite()) {
pt.start = v.clamp(0.0, len);
pt.start = v.max(0.0).min(len);
}
match p.get("end") {
Some(Value::Null) => pt.end = None,
+1 -1
View File
@@ -25,7 +25,7 @@ impl PathWarp {
/// Point and tangent angle (radians) at arc length `s` (clamped to the path).
pub fn at(&self, s: f64) -> Option<(Point, f64)> {
let s = if self.flip { self.total - s } else { s };
let mut s = s.clamp(0.0, self.total);
let mut s = s.max(0.0).min(self.total);
let n = self.segs.len();
for (i, (seg, len)) in self.segs.iter().enumerate() {
if s <= *len || i + 1 == n {