Merge pull request #2610 from storytold/fix/text-line-join

Text: stroke Line Join — Miter, Round or Bevel (#2077)
This commit is contained in:
BFlat
2026-10-30 05:41:27 +07:00
committed by GitHub
10 changed files with 90 additions and 7 deletions
+12 -1
View File
@@ -510,6 +510,7 @@ pub struct PlacedGlyph {
pub fill: [f32; 4],
pub stroke: [f32; 4],
pub stroke_width: f64,
pub join: effectcraft_path::Join,
/// Faux Bold (or synthetic bold for a family without a bold face): how far the outline grows
/// on every side, in character space (0 when not bold).
pub bold: f64,
@@ -838,6 +839,7 @@ pub fn text_geom(ctx: &EvalCtx, layer: &Layer) -> Option<TextGeom> {
fill,
stroke,
stroke_width: (base_stroke_w + x.stroke_width).max(0.0),
join: path_join(doc.line_join),
bold: if g.synth_bold { FAUX_BOLD_RADIUS * g.size } else { 0.0 },
apply_fill: st.apply_fill,
char_index: g.char_index,
@@ -853,6 +855,15 @@ pub fn glyph_paths(ctx: &EvalCtx, layer: &Layer) -> Vec<(BezPath, CharXf)> {
text_geom(ctx, layer).map(|t| t.glyphs.iter().map(|g| (g.path(), g.xf)).collect()).unwrap_or_default()
}
fn path_join(j: effectcraft_keyframe::LineJoin) -> effectcraft_path::Join {
use effectcraft_keyframe::LineJoin;
match j {
LineJoin::Miter => effectcraft_path::Join::Miter,
LineJoin::Round => effectcraft_path::Join::Round,
LineJoin::Bevel => effectcraft_path::Join::Bevel,
}
}
/// One paint pass of a glyph: fill (false) or stroke (true).
type Pass = (usize, bool);
@@ -919,7 +930,7 @@ fn raster_pass(g: &PlacedGlyph, stroke: bool, paths: &[BezPath], m: &Mat3, rect:
}
outer
} else if stroke {
let st = StrokeStyle { width: g.stroke_width, join: effectcraft_path::Join::Round, ..Default::default() };
let st = StrokeStyle { width: g.stroke_width, join: g.join, ..Default::default() };
effectcraft_path::stroke_coverage(paths, &st, &mm, w, h)
} else {
grown_coverage(paths, &mm, w, h, bold)
+2
View File
@@ -598,6 +598,7 @@ fn touching_glyphs_join_without_a_seam() {
fill,
stroke: [0.0; 4],
stroke_width: 0.0,
join: effectcraft_path::Join::Miter,
bold: 0.0,
apply_fill: true,
char_index: 0,
@@ -668,6 +669,7 @@ fn faux_bold_under_a_non_uniform_scale() {
fill: [1.0; 4],
stroke: [0.0; 4],
stroke_width: 0.0,
join: effectcraft_path::Join::Miter,
bold: 2.0,
apply_fill: true,
char_index: 0,
+1 -1
View File
@@ -572,7 +572,7 @@ pub fn extruded_meshes(ctx: &EvalCtx, layer: &Layer, p: &model::extrude::Extrude
groups.push((vec![g.local.clone()], c, g.m, usize::from(!stroke_on_top), g.xf.surface_colors(c)));
}
if g.stroke_width > 0.0 && g.stroke[3] * op > 0.0 {
let st = effectcraft_path::StrokeStyle { width: g.stroke_width, join: effectcraft_path::Join::Round, ..Default::default() };
let st = effectcraft_path::StrokeStyle { width: g.stroke_width, join: g.join, ..Default::default() };
if let Some(region) = crate::shapes::stroke_region(std::slice::from_ref(&g.local), &st) {
let c = [g.stroke[0], g.stroke[1], g.stroke[2], g.stroke[3] * op];
groups.push((vec![region], c, g.m, usize::from(stroke_on_top), g.xf.surface_colors(c)));