M0.6: content bounds helpers for viewer handles

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas
2026-10-01 14:32:21 -04:00
co-authored by Claude Opus 5.5
parent 426f153794
commit 0ec4605a32
2 changed files with 33 additions and 0 deletions
+19
View File
@@ -332,3 +332,22 @@ pub fn render_frame(project: &Project, comp: ItemId, t: Tick, scale: f64) -> Ima
#[cfg(test)]
mod tests;
/// Layer-space bounds `[x0, y0, x1, y1]` of a layer's content at the context time (source size
/// for solids/footage/precomps, glyph bounds for text, painted bounds for shapes). Used for viewer
/// handles and hit testing.
pub fn content_bounds(ctx: &EvalCtx, layer: &effectcraft_project::Layer) -> Option<[f64; 4]> {
match &layer.source {
LayerSource::Text => {
let glyphs = text::glyph_paths(ctx, layer);
let paths: Vec<_> = glyphs.into_iter().map(|g| g.0).collect();
effectcraft_path::bounds(&paths).map(|r| [r.x0, r.y0, r.x1, r.y1])
}
LayerSource::Shape => layer.props.sub("contents").and_then(|c| shapes::content_bounds(ctx, layer, c)).map(|r| [r.x0, r.y0, r.x1, r.y1]),
LayerSource::Camera | LayerSource::Light { .. } => None,
_ => {
let (w, h) = source_size(ctx.project, layer);
(w > 0 && h > 0).then_some([0.0, 0.0, w as f64, h as f64])
}
}
}
+14
View File
@@ -485,3 +485,17 @@ pub fn render(ctx: &EvalCtx, layer: &Layer, contents: &PropGroup, s: f64) -> Buf
#[cfg(test)]
mod tests;
/// Layer-space bounds of a shape layer's painted contents (strokes included), without
/// rasterising.
pub fn content_bounds(ctx: &EvalCtx, layer: &Layer, contents: &PropGroup) -> Option<kurbo::Rect> {
let mut arena = Vec::new();
let (draws, _) = collect(ctx, layer, contents, &mut arena);
draws
.iter()
.filter_map(|d| {
let paths: Vec<BezPath> = d.slots.iter().map(|&i| arena[i].clone()).filter(|p| !p.elements().is_empty()).collect();
draw_bounds(d, &paths)
})
.reduce(|a, b| a.union(b))
}