From 7ef9e5a3e8b56fff63580e58e61d7046bc715997 Mon Sep 17 00:00:00 2001 From: Salman Abuhaimed <85521119+BKSalman@users.noreply.github.com> Date: Fri, 18 Jul 2025 21:00:24 +0300 Subject: [PATCH] Fix Text node glyph duplication and wrong tilt calculation with per-glyph instances (#2907) * fix: text node subpaths duplication * fix: text node tilt calculation for per-glyph instaces --- node-graph/gcore/src/text/to_path.rs | 38 ++++++++++++++++------------ 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/node-graph/gcore/src/text/to_path.rs b/node-graph/gcore/src/text/to_path.rs index b96e03ff..880a05fe 100644 --- a/node-graph/gcore/src/text/to_path.rs +++ b/node-graph/gcore/src/text/to_path.rs @@ -50,16 +50,14 @@ impl PathBuilder { } if per_glyph_instances { - if !self.glyph_subpaths.is_empty() { - self.vector_table.push(Instance { - instance: VectorData::from_subpaths(core::mem::take(&mut self.glyph_subpaths), false), - transform: DAffine2::from_translation(glyph_offset), - ..Default::default() - }) - } - } else if !self.glyph_subpaths.is_empty() { - for subpath in self.glyph_subpaths.iter() { - // Unwrapping here is ok, since the check above guarantees there is at least one `VectorData` + self.vector_table.push(Instance { + instance: VectorData::from_subpaths(core::mem::take(&mut self.glyph_subpaths), false), + transform: DAffine2::from_translation(glyph_offset), + ..Default::default() + }); + } else { + for subpath in self.glyph_subpaths.drain(..) { + // Unwrapping here is ok because `self.vector_table` is initialized with a single `VectorData` self.vector_table.get_mut(0).unwrap().instance.append_subpath(subpath, false); } } @@ -128,18 +126,26 @@ fn render_glyph_run(glyph_run: &GlyphRun<'_, ()>, path_builder: &mut PathBuilder // User-requested tilt applied around baseline to avoid vertical displacement // Translation ensures rotation point is at the baseline, not origin - let skew = DAffine2::from_translation(DVec2::new(0., run_y as f64)) - * DAffine2::from_cols_array(&[1., 0., -tilt.to_radians().tan(), 1., 0., 0.]) - * DAffine2::from_translation(DVec2::new(0., -run_y as f64)); + let skew = if per_glyph_instances { + DAffine2::from_cols_array(&[1., 0., -tilt.to_radians().tan(), 1., 0., 0.]) + } else { + DAffine2::from_translation(DVec2::new(0., run_y as f64)) + * DAffine2::from_cols_array(&[1., 0., -tilt.to_radians().tan(), 1., 0., 0.]) + * DAffine2::from_translation(DVec2::new(0., -run_y as f64)) + }; let synthesis = run.synthesis(); // Font synthesis (e.g., synthetic italic) applied separately from user transforms // This preserves the distinction between font styling and user transformations let style_skew = synthesis.skew().map(|angle| { - DAffine2::from_translation(DVec2::new(0., run_y as f64)) - * DAffine2::from_cols_array(&[1., 0., -angle.to_radians().tan() as f64, 1., 0., 0.]) - * DAffine2::from_translation(DVec2::new(0., -run_y as f64)) + if per_glyph_instances { + DAffine2::from_cols_array(&[1., 0., -angle.to_radians().tan() as f64, 1., 0., 0.]) + } else { + DAffine2::from_translation(DVec2::new(0., run_y as f64)) + * DAffine2::from_cols_array(&[1., 0., -angle.to_radians().tan() as f64, 1., 0., 0.]) + * DAffine2::from_translation(DVec2::new(0., -run_y as f64)) + } }); let font = run.font();