Merge pull request #8383 from penpot/superalex-fix-text-stroke-bounds

🐛 Fix text stroke bounds
This commit is contained in:
Elena Torró 2026-02-17 17:35:38 +01:00 committed by GitHub
commit fb80c8f45b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 38 additions and 4 deletions

View File

@ -831,6 +831,8 @@ impl RenderState {
let text_content = text_content.new_bounds(shape.selrect()); let text_content = text_content.new_bounds(shape.selrect());
let count_inner_strokes = shape.count_visible_inner_strokes(); let count_inner_strokes = shape.count_visible_inner_strokes();
let text_stroke_blur_outset =
Stroke::max_bounds_width(shape.visible_strokes(), false);
let mut paragraph_builders = text_content.paragraph_builder_group_from_text(None); let mut paragraph_builders = text_content.paragraph_builder_group_from_text(None);
let mut stroke_paragraphs_list = shape let mut stroke_paragraphs_list = shape
.visible_strokes() .visible_strokes()
@ -858,7 +860,7 @@ impl RenderState {
); );
for stroke_paragraphs in stroke_paragraphs_list.iter_mut() { for stroke_paragraphs in stroke_paragraphs_list.iter_mut() {
text::render( text::render_with_bounds_outset(
Some(self), Some(self),
None, None,
&shape, &shape,
@ -866,6 +868,7 @@ impl RenderState {
Some(strokes_surface_id), Some(strokes_surface_id),
None, None,
None, None,
text_stroke_blur_outset,
); );
} }
} else { } else {
@ -957,7 +960,7 @@ impl RenderState {
// 4. Stroke fills // 4. Stroke fills
for stroke_paragraphs in stroke_paragraphs_list.iter_mut() { for stroke_paragraphs in stroke_paragraphs_list.iter_mut() {
text::render( text::render_with_bounds_outset(
Some(self), Some(self),
None, None,
&shape, &shape,
@ -965,6 +968,7 @@ impl RenderState {
Some(strokes_surface_id), Some(strokes_surface_id),
None, None,
blur_filter.as_ref(), blur_filter.as_ref(),
text_stroke_blur_outset,
); );
} }

View File

@ -156,7 +156,8 @@ fn get_text_stroke_paints(
paints paints
} }
pub fn render( #[allow(clippy::too_many_arguments)]
pub fn render_with_bounds_outset(
render_state: Option<&mut RenderState>, render_state: Option<&mut RenderState>,
canvas: Option<&Canvas>, canvas: Option<&Canvas>,
shape: &Shape, shape: &Shape,
@ -164,12 +165,20 @@ pub fn render(
surface_id: Option<SurfaceId>, surface_id: Option<SurfaceId>,
shadow: Option<&Paint>, shadow: Option<&Paint>,
blur: Option<&ImageFilter>, blur: Option<&ImageFilter>,
stroke_bounds_outset: f32,
) { ) {
if let Some(render_state) = render_state { if let Some(render_state) = render_state {
let target_surface = surface_id.unwrap_or(SurfaceId::Fills); let target_surface = surface_id.unwrap_or(SurfaceId::Fills);
if let Some(blur_filter) = blur { if let Some(blur_filter) = blur {
let bounds = blur_filter.compute_fast_bounds(shape.selrect); let mut text_bounds = shape
.get_text_content()
.calculate_bounds(shape, false)
.to_rect();
if stroke_bounds_outset > 0.0 {
text_bounds.inset((-stroke_bounds_outset, -stroke_bounds_outset));
}
let bounds = blur_filter.compute_fast_bounds(text_bounds);
if bounds.is_finite() && bounds.width() > 0.0 && bounds.height() > 0.0 { if bounds.is_finite() && bounds.width() > 0.0 && bounds.height() > 0.0 {
let blur_filter_clone = blur_filter.clone(); let blur_filter_clone = blur_filter.clone();
if filters::render_with_filter_surface( if filters::render_with_filter_surface(
@ -202,6 +211,27 @@ pub fn render(
} }
} }
pub fn render(
render_state: Option<&mut RenderState>,
canvas: Option<&Canvas>,
shape: &Shape,
paragraph_builders: &mut [Vec<ParagraphBuilder>],
surface_id: Option<SurfaceId>,
shadow: Option<&Paint>,
blur: Option<&ImageFilter>,
) {
render_with_bounds_outset(
render_state,
canvas,
shape,
paragraph_builders,
surface_id,
shadow,
blur,
0.0,
);
}
fn render_text_on_canvas( fn render_text_on_canvas(
canvas: &Canvas, canvas: &Canvas,
shape: &Shape, shape: &Shape,