mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
🔧 Improve text strokes blending
This commit is contained in:
@@ -470,18 +470,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());
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -980,6 +980,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)
|
||||
}
|
||||
|
||||
@@ -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(¶graph_style, fonts);
|
||||
for leaf in ¶graph.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(¶graph_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);
|
||||
}
|
||||
|
||||
@@ -693,20 +704,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();
|
||||
|
||||
Reference in New Issue
Block a user