From b75b1548d49c3af3aa1f2f95632b7901c5d8edce Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Thu, 5 Nov 2026 21:29:59 -0800 Subject: [PATCH] Tests: a fitted text test changes its fit scale The regression test for rebuilding fitted area type after a scale change used text that overflowed at the minimum size both before and after the change, so both layouts used the same fit scale and the pixel comparison did not depend on the fit. The fixture is now 2 pt type in a small frame, drawn 20 times zoomed in. It fits at 0.7 of its size, and at 0.733 after a 1.5 times scale. The test asserts that the two fit scales differ and that the words set at the earlier fit draw different pixels, and keeps the comparison with a fresh renderer and the check that the geometry is not reused. --- crates/render/src/tests/charstroke.rs | 34 ++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/crates/render/src/tests/charstroke.rs b/crates/render/src/tests/charstroke.rs index d6d595ad5..aaa16a74c 100644 --- a/crates/render/src/tests/charstroke.rs +++ b/crates/render/src/tests/charstroke.rs @@ -189,22 +189,44 @@ fn moving_type_reuses_character_strokes_without_changing_pixels() { #[test] fn scaling_fitted_area_type_rebuilds_its_glyph_geometry() { let _fonts = fonts_steady(); - let (mut d, id) = stroked_text_doc("A long story that must shrink to fit in a small area of type"); + // 2 pt type, drawn 20× zoomed in. Shrink Text to Fit steps the size in tenths of a document + // point, so at 2 pt and at 3 pt it fits the same words at different fractions of full size. + let (mut d, id) = stroked_text_doc("Type"); if let Some(Node { kind: NodeKind::Text(t), .. }) = d.node_mut(id) { - t.kind = TextKind::Area { frame: PathData::from_bezpath(&Rect::new(0.0, 0.0, 100.0, 45.0).to_path(0.1)) }; + t.xf = Affine::IDENTITY; + t.runs[0].style.size = 2.0; + t.runs[0].style.stroke_width = 0.05; + t.kind = TextKind::Area { frame: PathData::from_bezpath(&Rect::new(0.0, 0.0, 3.0, 3.0).to_path(0.1)) }; t.area.fit = AreaFit::ShrinkText { min_percent: 30.0 }; } + let text = |d: &Document| match d.node(id).map(|n| &n.kind) { + Some(NodeKind::Text(t)) => (**t).clone(), + _ => panic!("the text object"), + }; + let fit = |d: &Document| vectorcraft_text::layout(vectorcraft_text::FontDb::global(), &text(d)).fit_scale; + let view = Affine::scale(20.0); let opts = RenderOptions::default(); let mut r = Renderer::new(); - r.render(&d, SIZE, SIZE, Affine::IDENTITY, &opts); + r.render(&d, SIZE, SIZE, view, &opts); let first = r.texts.used_in(r.stamp).next().unwrap().1.clone(); + let before = fit(&d); if let Some(Node { kind: NodeKind::Text(t), .. }) = d.node_mut(id) { - t.xf = Affine::scale(1.2) * t.xf; + t.xf = Affine::scale(1.5) * t.xf; } - let scaled = r.render(&d, SIZE, SIZE, Affine::IDENTITY, &opts); + let after = fit(&d); + assert!(before > 0.3 && before < 1.0 && after > 0.3 && after < 1.0, "it fits above the minimum both times: {before}, {after}"); + assert!((before - after).abs() > 0.01, "the scale changes the fitted size: {before}, {after}"); + let scaled = r.render(&d, SIZE, SIZE, view, &opts); let again = r.texts.used_in(r.stamp).next().unwrap().1.clone(); assert!(!Arc::ptr_eq(&first, &again), "changing area type's scale lays it out again"); - assert_eq!(scaled.pixels, Renderer::new().render(&d, SIZE, SIZE, Affine::IDENTITY, &opts).pixels); + assert_eq!(scaled.pixels, Renderer::new().render(&d, SIZE, SIZE, view, &opts).pixels); + // The words set at the earlier fit, which reusing the earlier layout would draw, draw other pixels. + let mut stale = d.clone(); + if let Some(Node { kind: NodeKind::Text(t), .. }) = stale.node_mut(id) { + **t = vectorcraft_text::scaled(t, before); + } + assert_eq!(fit(&stale), 1.0, "the earlier fit's words fit as they are"); + assert_ne!(scaled.pixels, Renderer::new().render(&stale, SIZE, SIZE, view, &opts).pixels, "the new fit changes the pixels"); } /// Frames that draw character strokes from the cache draw the same pixels, and what a renderer