From c2ae58bf0861b342d9ad4c28c7de0dc02cfce352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Torr=C3=B3?= Date: Thu, 24 Apr 2025 12:19:41 +0200 Subject: [PATCH] :tada: Add text shadows (#6335) --- render-wasm/src/render.rs | 7 +++- render-wasm/src/render/shadows.rs | 61 ++++++++++++++++++++++++++++++- render-wasm/src/render/text.rs | 22 ++++++++--- render-wasm/src/shapes.rs | 1 + render-wasm/src/shapes/text.rs | 9 +++++ 5 files changed, 93 insertions(+), 7 deletions(-) diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index b2bddb0a0..e7e77db65 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -371,7 +371,12 @@ impl RenderState { self.surfaces.apply_mut(&[SurfaceId::Fills], |s| { s.canvas().concat(&matrix); }); - text::render(self, &shape, text_content); + + let paragraphs = text_content.to_skia_paragraphs(&self.fonts.font_collection()); + + shadows::render_text_drop_shadows(self, &shape, ¶graphs, antialias); + text::render(self, &shape, ¶graphs, None, None); + shadows::render_text_inner_shadows(self, &shape, ¶graphs, antialias); } _ => { self.surfaces.apply_mut( diff --git a/render-wasm/src/render/shadows.rs b/render-wasm/src/render/shadows.rs index b61dea596..d7a9e637e 100644 --- a/render-wasm/src/render/shadows.rs +++ b/render-wasm/src/render/shadows.rs @@ -1,7 +1,8 @@ use super::{RenderState, SurfaceId}; use crate::render::strokes; +use crate::render::text::{self}; use crate::shapes::{Shadow, Shape, Stroke, Type}; -use skia_safe::Paint; +use skia_safe::{textlayout::Paragraph, Paint}; // Fill Shadows pub fn render_fill_drop_shadows(render_state: &mut RenderState, shape: &Shape, antialias: bool) { @@ -82,6 +83,64 @@ pub fn render_stroke_inner_shadows( } } +pub fn render_text_drop_shadows( + render_state: &mut RenderState, + shape: &Shape, + paragraphs: &[Paragraph], + antialias: bool, +) { + for shadow in shape.drop_shadows().rev().filter(|s| !s.hidden()) { + render_text_drop_shadow(render_state, &shape, &shadow, ¶graphs, antialias); + } +} + +pub fn render_text_drop_shadow( + render_state: &mut RenderState, + shape: &Shape, + shadow: &Shadow, + paragraphs: &[Paragraph], + antialias: bool, +) { + let paint = &shadow.get_drop_shadow_paint(antialias); + + text::render( + render_state, + shape, + ¶graphs, + Some(SurfaceId::DropShadows), + Some(paint), + ); +} + +pub fn render_text_inner_shadows( + render_state: &mut RenderState, + shape: &Shape, + paragraphs: &[Paragraph], + antialias: bool, +) { + for shadow in shape.inner_shadows().rev().filter(|s| !s.hidden()) { + render_text_inner_shadow(render_state, &shape, &shadow, ¶graphs, antialias); + } +} + +pub fn render_text_inner_shadow( + render_state: &mut RenderState, + shape: &Shape, + shadow: &Shadow, + paragraphs: &[Paragraph], + antialias: bool, +) { + let paint = &shadow.get_inner_shadow_paint(antialias); + + text::render( + render_state, + shape, + ¶graphs, + Some(SurfaceId::InnerShadows), + Some(paint), + ); +} + fn render_shadow_paint( render_state: &mut RenderState, shape: &Shape, diff --git a/render-wasm/src/render/text.rs b/render-wasm/src/render/text.rs index a3b7e50d8..9ef6cdb1d 100644 --- a/render-wasm/src/render/text.rs +++ b/render-wasm/src/render/text.rs @@ -1,13 +1,25 @@ use super::{RenderState, Shape, SurfaceId}; -use crate::shapes::TextContent; +use skia_safe::{self as skia, canvas::SaveLayerRec, paint, textlayout::Paragraph}; -pub fn render(render_state: &mut RenderState, shape: &Shape, text: &TextContent) { +pub fn render( + render_state: &mut RenderState, + shape: &Shape, + paragraphs: &[Paragraph], + surface_id: Option, + paint: Option<&paint::Paint>, +) { let mut offset_y = 0.0; - for mut skia_paragraph in text.to_paragraphs(&render_state.fonts().font_collection()) { - skia_paragraph.layout(shape.width()); + let default_paint = skia::Paint::default(); + let mask = SaveLayerRec::default().paint(&paint.unwrap_or(&default_paint)); + let canvas = render_state + .surfaces + .canvas(surface_id.unwrap_or(SurfaceId::Fills)); + canvas.save_layer(&mask); + for skia_paragraph in paragraphs { let xy = (shape.selrect().x(), shape.selrect.y() + offset_y); - skia_paragraph.paint(render_state.surfaces.canvas(SurfaceId::Fills), xy); + skia_paragraph.paint(canvas, xy); offset_y += skia_paragraph.height(); } + canvas.restore(); } diff --git a/render-wasm/src/shapes.rs b/render-wasm/src/shapes.rs index 75cd72360..caf9056c8 100644 --- a/render-wasm/src/shapes.rs +++ b/render-wasm/src/shapes.rs @@ -549,6 +549,7 @@ impl Shape { self.hidden } + #[allow(dead_code)] pub fn width(&self) -> f32 { self.selrect.width() } diff --git a/render-wasm/src/shapes/text.rs b/render-wasm/src/shapes/text.rs index 1ece55e8c..0e338f62e 100644 --- a/render-wasm/src/shapes/text.rs +++ b/render-wasm/src/shapes/text.rs @@ -65,6 +65,15 @@ impl TextContent { }) .collect() } + + pub fn to_skia_paragraphs(&self, fonts: &FontCollection) -> Vec { + let mut paragraphs = Vec::new(); + for mut skia_paragraph in self.to_paragraphs(fonts) { + skia_paragraph.layout(self.width()); + paragraphs.push(skia_paragraph); + } + paragraphs + } } impl Default for TextContent {