Merge pull request #7029 from penpot/elenatorro-11691-fix-default-text-fill

🔧 Fix text default color and inner stroke opacity
This commit is contained in:
Alejandro Alonso
2025-08-13 12:52:14 +02:00
committed by GitHub
5 changed files with 74 additions and 37 deletions

View File

@@ -499,18 +499,6 @@ impl RenderState {
text::render(self, &shape, &mut paragraphs, None, None);
if shape.has_visible_inner_strokes() {
// Inner strokes paints need the text fill to apply correctly their blend modes
// (e.g., SrcATop, DstOver)
text::render(
self,
&shape,
&mut paragraphs,
Some(SurfaceId::Strokes),
None,
);
}
for stroke in shape.visible_strokes().rev() {
let mut stroke_paragraphs =
text_content.get_skia_stroke_paragraphs(stroke, &shape.selrect());

View File

@@ -24,6 +24,9 @@ pub fn render(
_ => 0.0,
};
let layer_rec = skia_safe::canvas::SaveLayerRec::default();
canvas.save_layer(&layer_rec);
for group in paragraphs {
let mut group_offset_y = global_offset_y;
let group_len = group.len();
@@ -36,15 +39,7 @@ pub fn render(
let mut paragraph_builder =
ParagraphBuilder::new(&builder.get_paragraph_style(), fonts);
let mut text_style: skia_safe::Handle<_> = builder.peek_style();
let current_paint = text_style.foreground().clone();
let blend_mode = current_paint.as_blend_mode();
let mut new_paint = paint.unwrap().clone();
if blend_mode != Some(skia_safe::BlendMode::SrcIn) {
new_paint.set_stroke_width(current_paint.stroke_width());
new_paint.set_style(skia_safe::PaintStyle::StrokeAndFill);
}
new_paint.set_anti_alias(true);
text_style.set_foreground_paint(&new_paint);
text_style.set_foreground_paint(paint.unwrap());
paragraph_builder.reset();
paragraph_builder.push_style(&text_style);
paragraph_builder.add_text(&text);
@@ -138,6 +133,8 @@ pub fn render(
global_offset_y = group_offset_y;
}
}
canvas.restore();
}
pub fn calculate_text_decoration_rect(

View File

@@ -1072,6 +1072,7 @@ impl Shape {
self.visible_strokes().next().is_some()
}
#[allow(dead_code)]
pub fn has_visible_inner_strokes(&self) -> bool {
self.visible_strokes().any(|s| s.kind == StrokeKind::Inner)
}

View File

@@ -230,6 +230,11 @@ pub fn merge_fills(fills: &[Fill], bounding_box: Rect) -> skia::Paint {
let mut combined_shader: Option<skia::Shader> = None;
let mut fills_paint = skia::Paint::default();
if fills.is_empty() {
fills_paint.set_color(skia::Color::TRANSPARENT);
return fills_paint;
}
for fill in fills {
let shader = get_fill_shader(fill, &bounding_box);

View File

@@ -118,24 +118,35 @@ impl TextContent {
bounds: &Rect,
) -> Vec<Vec<ParagraphBuilder>> {
let fallback_fonts = get_fallback_fonts();
let stroke_paints = get_text_stroke_paints(stroke, bounds);
let fonts = get_font_collection();
let mut paragraph_group = Vec::new();
for paragraph in &self.paragraphs {
let mut stroke_paragraphs = Vec::new();
for stroke_paint in &stroke_paints {
let paragraph_style = paragraph.paragraph_to_style();
let mut builder = ParagraphBuilder::new(&paragraph_style, fonts);
for leaf in &paragraph.children {
let mut stroke_paragraphs_map: std::collections::HashMap<usize, ParagraphBuilder> =
std::collections::HashMap::new();
for leaf in paragraph.children.iter() {
let text_paint = merge_fills(&leaf.fills, *bounds);
let stroke_paints = get_text_stroke_paints(stroke, bounds, &text_paint);
let text: String = leaf.apply_text_transform();
for (paint_idx, stroke_paint) in stroke_paints.iter().enumerate() {
let builder = stroke_paragraphs_map.entry(paint_idx).or_insert_with(|| {
let paragraph_style = paragraph.paragraph_to_style();
ParagraphBuilder::new(&paragraph_style, fonts)
});
let stroke_style =
leaf.to_stroke_style(paragraph, stroke_paint, fallback_fonts);
let text: String = leaf.apply_text_transform();
builder.push_style(&stroke_style);
builder.add_text(&text);
}
stroke_paragraphs.push(builder);
}
let stroke_paragraphs: Vec<ParagraphBuilder> = (0..stroke_paragraphs_map.len())
.map(|i| stroke_paragraphs_map.remove(&i).unwrap())
.collect();
paragraph_group.push(stroke_paragraphs);
}
@@ -703,20 +714,55 @@ pub fn auto_height(paragraphs: &mut [Vec<ParagraphBuilder>], width: f32) -> f32
})
}
fn get_text_stroke_paints(stroke: &Stroke, bounds: &Rect) -> Vec<Paint> {
fn get_text_stroke_paints(stroke: &Stroke, bounds: &Rect, text_paint: &Paint) -> Vec<Paint> {
let mut paints = Vec::new();
match stroke.kind {
StrokeKind::Inner => {
let mut paint = skia::Paint::default();
paint.set_style(skia::PaintStyle::Stroke);
paint.set_blend_mode(skia::BlendMode::SrcIn);
paint.set_anti_alias(true);
paint.set_stroke_width(stroke.width * 2.0);
let shader = text_paint.shader();
let mut is_opaque = true;
set_paint_fill(&mut paint, &stroke.fill, bounds);
if shader.is_some() {
is_opaque = shader.unwrap().is_opaque();
}
paints.push(paint);
if is_opaque {
let mut paint = text_paint.clone();
paint.set_style(skia::PaintStyle::Fill);
paint.set_anti_alias(true);
paints.push(paint);
let mut paint = skia::Paint::default();
paint.set_style(skia::PaintStyle::Stroke);
paint.set_blend_mode(skia::BlendMode::SrcIn);
paint.set_anti_alias(true);
paint.set_stroke_width(stroke.width * 2.0);
set_paint_fill(&mut paint, &stroke.fill, bounds);
paints.push(paint);
} else {
// outer
let mut paint = skia::Paint::default();
paint.set_style(skia::PaintStyle::Stroke);
paint.set_blend_mode(skia::BlendMode::DstATop);
paint.set_anti_alias(true);
paint.set_stroke_width(stroke.width * 2.0);
paints.push(paint);
let mut paint = skia::Paint::default();
paint.set_style(skia::PaintStyle::Fill);
paint.set_blend_mode(skia::BlendMode::Clear);
paint.set_anti_alias(true);
paints.push(paint);
// inner
let mut paint = skia::Paint::default();
paint.set_style(skia::PaintStyle::Stroke);
paint.set_stroke_width(stroke.width * 2.0);
paint.set_blend_mode(skia::BlendMode::Xor);
paint.set_anti_alias(true);
set_paint_fill(&mut paint, &stroke.fill, bounds);
paints.push(paint);
}
}
StrokeKind::Center => {
let mut paint = skia::Paint::default();