Compare commits
1 Commits
main
...
fix/group-
| Author | SHA1 | Date |
|---|---|---|
|
|
351b2453b4 |
|
|
@ -681,6 +681,24 @@ impl Renderer {
|
||||||
if depth > 0 && view.determinant().abs() > 1e-12 && view.is_finite() { (view, view.inverse() * m) } else { (m, Affine::IDENTITY) }
|
if depth > 0 && view.determinant().abs() > 1e-12 && view.is_finite() { (view, view.inverse() * m) } else { (m, Affine::IDENTITY) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The size and transform a shape's text is set in: inside a group whose child coordinates
|
||||||
|
/// scale the shape, the shape's size in slide points and `m` with that scale taken out, so
|
||||||
|
/// insets and font sizes stay in points; otherwise `w`, `h` and `m` themselves.
|
||||||
|
fn text_space(&self, m: Affine, depth: usize, w: f64, h: f64) -> (f64, f64, Affine) {
|
||||||
|
let (_, rel) = self.line_space(m, depth);
|
||||||
|
let c = rel.as_coeffs();
|
||||||
|
let (sx, sy) = (c[0].hypot(c[1]), c[2].hypot(c[3]));
|
||||||
|
let ok = |k: f64| k.is_finite() && k > 1e-9;
|
||||||
|
if depth == 0 || !ok(sx) || !ok(sy) || ((sx - 1.0).abs() < 1e-9 && (sy - 1.0).abs() < 1e-9) {
|
||||||
|
return (w, h, m);
|
||||||
|
}
|
||||||
|
let (tw, th) = (w * sx, h * sy);
|
||||||
|
if !tw.is_finite() || !th.is_finite() {
|
||||||
|
return (w, h, m);
|
||||||
|
}
|
||||||
|
(tw, th, m * Affine::scale_non_uniform(1.0 / sx, 1.0 / sy))
|
||||||
|
}
|
||||||
|
|
||||||
fn shape_at(&mut self, ctx: &mut RenderContext, f: &Frame, rctx: &Ctx, s: &Shape, parent: Affine, depth: usize) {
|
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) {
|
if depth > 32 || (s.hidden && !f.opts.show_hidden) || f.opts.skip.contains(&s.id) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -921,6 +939,16 @@ impl Renderer {
|
||||||
if let Some(body) = &s.text
|
if let Some(body) = &s.text
|
||||||
&& !skip_text
|
&& !skip_text
|
||||||
{
|
{
|
||||||
|
// Text in a group is set at the shape's size on the slide, in points: a group's
|
||||||
|
// child-coordinate scale sizes and places the box, never the type (#233's twin).
|
||||||
|
let (tw, th, m) = self.text_space(m, depth, w, h);
|
||||||
|
let text_geo;
|
||||||
|
let geo = if (tw, th) == (w, h) {
|
||||||
|
&geo
|
||||||
|
} else {
|
||||||
|
text_geo = shape_geometry(s, tw, th);
|
||||||
|
&text_geo
|
||||||
|
};
|
||||||
let tr = geo.text_rect;
|
let tr = geo.text_rect;
|
||||||
if !body.is_empty() {
|
if !body.is_empty() {
|
||||||
let l = deckcraft_text::layout(rctx, s, body, &Opts { rect: tr, fields: &f.fields, prompt_color: None, no_shrink: false });
|
let l = deckcraft_text::layout(rctx, s, body, &Opts { rect: tr, fields: &f.fields, prompt_color: None, no_shrink: false });
|
||||||
|
|
|
||||||
|
|
@ -1553,3 +1553,33 @@ fn a_picture_casts_its_shadow_from_its_pixels() {
|
||||||
assert!(img.pixel(200, 200)[0] > 240, "{as_fill}");
|
assert!(img.pixel(200, 200)[0] > 240, "{as_fill}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn text_in_a_scaled_group_keeps_its_point_size() {
|
||||||
|
// A group's child coordinates scale its shapes' boxes, never their type: a 24 pt word in a
|
||||||
|
// group whose child space is 1/1600 of its size (as old decks write them) or 4 times it is
|
||||||
|
// 24 pt on the slide, and inside its box (it used to grow until the slide turned black).
|
||||||
|
let draw = |scale: f64| {
|
||||||
|
let mut p = Presentation::default();
|
||||||
|
let mut body = TextBody::from_text("Hello");
|
||||||
|
body.paragraphs[0].runs[0].props.size = Some(24.0);
|
||||||
|
body.paragraphs[0].runs[0].props.fill = Some(Fill::solid(ColorRef::rgb(deckcraft_color::Rgba::BLACK)));
|
||||||
|
let child = Shape { id: ShapeId(601), xfrm: Some(Xfrm::new(0.0, 0.0, 400.0 / scale, 200.0 / scale)), text: Some(body), ..Default::default() };
|
||||||
|
let g = Shape {
|
||||||
|
id: ShapeId(600),
|
||||||
|
xfrm: Some(Xfrm::new(100.0, 100.0, 400.0, 200.0)),
|
||||||
|
kind: ShapeKind::Group { children: vec![child], child: Xfrm::new(0.0, 0.0, 400.0 / scale, 200.0 / scale) },
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
std::sync::Arc::make_mut(&mut p.slides[0]).shapes = vec![g];
|
||||||
|
render_slide(&p, 0, &RenderOpts { scale: 1.0, ..Default::default() })
|
||||||
|
};
|
||||||
|
let ((_, y0, _, y1), _) = ink(&draw(1.0));
|
||||||
|
let plain = y1 - y0;
|
||||||
|
assert!(plain > 10 && plain < 30, "24 pt word ink height {plain}");
|
||||||
|
for scale in [1600.0, 4.0, 0.25] {
|
||||||
|
let ((x0, sy0, x1, sy1), _) = ink(&draw(scale));
|
||||||
|
assert!((sy1 - sy0).abs_diff(plain) <= 1, "scale {scale}: ink height {} vs {plain}", sy1 - sy0);
|
||||||
|
assert!(x0 >= 100 && x1 <= 500 && sy0 >= 100 && sy1 <= 300, "scale {scale}: ink inside the box");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue