mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 10:37:03 -06:00
Keep rounded corners round in non-uniformly scaled groups
Fixes #1083 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 5.5
parent
a31b990d32
commit
98b6d04413
@@ -851,6 +851,27 @@ impl Renderer {
|
||||
(tw, th, m * Affine::scale_non_uniform(1.0 / sx, 1.0 / sy))
|
||||
}
|
||||
|
||||
/// A shape's geometry in its own `w` × `h` space, built at its size on the slide: inside a
|
||||
/// group whose child coordinates scale the shape unevenly, the preset's rounded corners and
|
||||
/// other size-derived features stay as they would be on a plain shape of that size (#1083).
|
||||
fn scaled_geometry(&self, s: &Shape, m: Affine, depth: usize, w: f64, h: f64) -> Geometry {
|
||||
let (tw, th, _) = self.text_space(m, depth, w, h);
|
||||
if (tw, th) == (w, h) {
|
||||
return shape_geometry(s, w, h);
|
||||
}
|
||||
let mut geo = shape_geometry(s, tw, th);
|
||||
let k = |a: f64, b: f64| if b.abs() > 1e-12 { a / b } else { 1.0 };
|
||||
let back = Affine::scale_non_uniform(k(w, tw), k(h, th));
|
||||
for p in &mut geo.paths {
|
||||
p.path.apply_affine(back);
|
||||
}
|
||||
geo.text_rect = back.transform_rect_bbox(geo.text_rect);
|
||||
for p in &mut geo.sites {
|
||||
*p = back * *p;
|
||||
}
|
||||
geo
|
||||
}
|
||||
|
||||
fn shape_at(&mut self, ctx: &mut RenderContext, f: &Frame, rctx: &Ctx, s: &Shape, parent: Affine, depth: usize) {
|
||||
if depth > 32 || (s.hidden && !f.opts.show_hidden) || f.opts.skip.contains(&s.id) {
|
||||
return;
|
||||
@@ -1007,7 +1028,7 @@ impl Renderer {
|
||||
) {
|
||||
let (geo, fades) = match self.paths.iter().find(|p| p.id == s.id) {
|
||||
Some(pm) => self.morphs.geometry(pm, s, w, h),
|
||||
None => (shape_geometry(s, w, h), Vec::new()),
|
||||
None => (self.scaled_geometry(s, m, depth, w, h), Vec::new()),
|
||||
};
|
||||
let fade = |i: usize| fades.get(i).copied().unwrap_or(deckcraft_geom::morph::Fade { fill: 1.0, stroke: 1.0 });
|
||||
let (fill, fill_ph) = resolve::fill(rctx, s);
|
||||
|
||||
@@ -1971,6 +1971,37 @@ fn text_in_a_scaled_group_keeps_its_point_size() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rounded_corners_in_a_stretched_group_stay_round() {
|
||||
// #1083: a group that stretches its child space 4x across makes a rounded rectangle wider on
|
||||
// the slide, but its corners stay circular, like a plain rounded rectangle of that size.
|
||||
let round = |id: u32, w: f64, h: f64| Shape {
|
||||
id: ShapeId(id),
|
||||
xfrm: Some(Xfrm::new(0.0, 0.0, w, h)),
|
||||
geom: Geom::Preset { name: "roundRect".into(), adj: vec![16667.0] },
|
||||
fill: Some(Fill::solid(ColorRef::rgb(deckcraft_color::Rgba::BLACK))),
|
||||
line: Some(deckcraft_model::style::Line { fill: Some(Fill::None), ..Default::default() }),
|
||||
..Default::default()
|
||||
};
|
||||
let render = |sh: Shape| {
|
||||
let mut p = Presentation::default();
|
||||
std::sync::Arc::make_mut(&mut p.slides[0]).shapes = vec![sh];
|
||||
render_slide(&p, 0, &RenderOpts { scale: 1.0, ..Default::default() })
|
||||
};
|
||||
let mut plain = round(700, 400.0, 100.0);
|
||||
plain.xfrm = Some(Xfrm::new(100.0, 100.0, 400.0, 100.0));
|
||||
let plain = render(plain);
|
||||
let grouped = render(Shape {
|
||||
id: ShapeId(701),
|
||||
xfrm: Some(Xfrm::new(100.0, 100.0, 400.0, 100.0)),
|
||||
kind: ShapeKind::Group { children: vec![round(702, 100.0, 100.0)], child: Xfrm::new(0.0, 0.0, 100.0, 100.0) },
|
||||
..Default::default()
|
||||
});
|
||||
for (x, y) in [(120, 102), (102, 120), (480, 102), (498, 180), (120, 198)] {
|
||||
assert_eq!(plain.pixel(x, y), grouped.pixel(x, y), "pixel ({x},{y}) of a roundRect in a stretched group");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_fill_overlay_blends_over_the_fill() {
|
||||
// `a:fillOverlay blend="mult"`: a 50% grey multiplied over a light fill darkens it; "screen"
|
||||
|
||||
Reference in New Issue
Block a user