Transform: Fit to Comp refuses a scale that overflows (#2198)

A shape's painted bounds can be tiny enough (a 1e-305 px rectangle) that
the fit scale overflows to infinity. Non-finite bounds are skipped and a
non-finite scale returns an error before anything is written, instead of
storing infinity in the document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
SusieeTheFemboyandClaude Opus 5.5 committed 2026-10-29 05:41:00 +01:00
1 parent a3a72d48aa
commit 5224414d28
2 files changed
+14 -1

No files matched your search

+5 -1
View File
@@ -89,7 +89,7 @@ pub(super) fn transform_op(s: &mut Session, p: &Value) -> Result<Value> {
.map(|l| {
let (w, h) = effectcraft_render::source_size(&s.project, l);
if fitting && (w == 0 || h == 0) {
match effectcraft_render::content_bounds(&ectx, l).filter(|b| b[2] > b[0] && b[3] > b[1]) {
match effectcraft_render::content_bounds(&ectx, l).filter(|b| b.iter().all(|v| v.is_finite()) && b[2] > b[0] && b[3] > b[1]) {
Some(b) => (l.id, [b[2] - b[0], b[3] - b[1]], [(b[0] + b[2]) / 2.0, (b[1] + b[3]) / 2.0]),
None => (l.id, [0.0; 2], [0.0; 2]),
}
@@ -127,6 +127,10 @@ pub(super) fn transform_op(s: &mut Session, p: &Value) -> Result<Value> {
"fitHeight" => (ch / h, ch / h),
_ => (cw / w, ch / h),
};
// A tiny shape's bounds can overflow the scale; refuse rather than write infinity.
if !(sx * 100.0).is_finite() || !(sy * 100.0).is_finite() {
return Err(EngineError::Other(format!("layer {} is too small to fit to the composition", lid.0)));
}
let z = |m: &str, d: f64| tr.get(m).map(|p| p.value_at(lt).as_vec3()[2]).unwrap_or(d);
let (sz, az) = (z("scale", 100.0), z("anchor", 0.0));
set(tr, "scale", KV::Vec3([sx * 100.0, sy * 100.0, sz]));
+9
View File
@@ -1154,6 +1154,15 @@ fn fit_to_comp_fills_the_comp_with_shape_and_text_bounds() {
}
}
#[test]
fn fit_to_comp_refuses_a_scale_that_overflows() {
let mut s = comp();
let a = s.execute("layer.newShape", json!({"kind": "rect", "size": [1e-305, 80]})).unwrap()["layer"].as_u64().unwrap();
let before = s.project.clone();
assert!(s.execute("layer.transform", json!({"layers": [a], "op": "fit"})).is_err(), "an infinite scale is refused");
assert_eq!(s.project, before, "nothing was written");
}
#[test]
fn duplicated_and_pasted_layers_keep_their_links() {
let mut s = comp();