From d25f9cd4bda7b84e1a61d7684e1d58ac89456d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Tue, 2 Sep 2025 15:03:46 +0200 Subject: [PATCH 1/5] :recycle: Move auto_width and auto_height to their own textlayout module --- render-wasm/src/main.rs | 1 + render-wasm/src/shapes/modifiers.rs | 16 ++++----- render-wasm/src/shapes/text.rs | 53 +---------------------------- render-wasm/src/textlayout.rs | 53 +++++++++++++++++++++++++++++ render-wasm/src/wasm/text.rs | 7 ++-- 5 files changed, 66 insertions(+), 64 deletions(-) create mode 100644 render-wasm/src/textlayout.rs diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index 756d23336e..8a9a5fab30 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -7,6 +7,7 @@ mod performance; mod render; mod shapes; mod state; +mod textlayout; mod tiles; mod utils; mod uuid; diff --git a/render-wasm/src/shapes/modifiers.rs b/render-wasm/src/shapes/modifiers.rs index 4c8e00682f..6f70d32975 100644 --- a/render-wasm/src/shapes/modifiers.rs +++ b/render-wasm/src/shapes/modifiers.rs @@ -1,20 +1,20 @@ use std::collections::{HashMap, HashSet, VecDeque}; -pub mod common; + mod constraints; mod flex_layout; + +pub mod common; pub mod grid_layout; +use crate::math::{self as math, bools, identitish, Bounds, Matrix, Point}; use common::GetBounds; -use crate::math::bools; -use crate::math::{self as math, identitish, Bounds, Matrix, Point}; - use crate::shapes::{ - auto_height, ConstraintH, ConstraintV, Frame, Group, GrowType, Layout, Modifier, Shape, - StructureEntry, TransformEntry, Type, + ConstraintH, ConstraintV, Frame, Group, GrowType, Layout, Modifier, Shape, StructureEntry, + TransformEntry, Type, }; -use crate::state::ShapesPool; -use crate::state::State; +use crate::state::{ShapesPool, State}; +use crate::textlayout::auto_height; use crate::uuid::Uuid; #[allow(clippy::too_many_arguments)] diff --git a/render-wasm/src/shapes/text.rs b/render-wasm/src/shapes/text.rs index 825a3c24e7..acbca475b3 100644 --- a/render-wasm/src/shapes/text.rs +++ b/render-wasm/src/shapes/text.rs @@ -13,6 +13,7 @@ use std::collections::HashSet; use super::FontFamily; use crate::shapes::{self, merge_fills, set_paint_fill, Stroke, StrokeKind}; +use crate::textlayout::{auto_height, auto_width}; use crate::utils::{get_fallback_fonts, get_font_collection, uuid_from_u32}; use crate::wasm::fills::parse_fills_from_bytes; use crate::Uuid; @@ -42,30 +43,6 @@ pub struct TextContent { pub grow_type: GrowType, } -pub fn build_paragraphs_with_width( - paragraphs: &mut [Vec], - width: f32, -) -> Vec> { - paragraphs - .iter_mut() - .map(|builders| { - builders - .iter_mut() - .map(|builder| { - let mut paragraph = builder.build(); - // For auto-width, always layout with infinite width first to get intrinsic width - paragraph.layout(f32::MAX); - let intrinsic_width = paragraph.max_intrinsic_width().ceil(); - // Use the larger of the requested width or intrinsic width to prevent line breaks - let final_width = f32::max(width, intrinsic_width); - paragraph.layout(final_width); - paragraph - }) - .collect() - }) - .collect() -} - impl TextContent { pub fn new(bounds: Rect, grow_type: GrowType) -> Self { Self { @@ -742,34 +719,6 @@ impl From<&Vec> for RawTextData { } } -pub fn get_built_paragraphs( - paragraphs: &mut [Vec], - width: f32, -) -> Vec> { - build_paragraphs_with_width(paragraphs, width) -} - -pub fn auto_width(paragraphs: &mut [Vec], width: f32) -> f32 { - let built_paragraphs = get_built_paragraphs(paragraphs, width); - - built_paragraphs - .iter() - .flatten() - .fold(0.0, |auto_width, p| { - f32::max(p.max_intrinsic_width(), auto_width) - }) -} - -pub fn auto_height(paragraphs: &mut [Vec], width: f32) -> f32 { - paragraphs.iter_mut().fold(0.0, |auto_height, p| { - p.iter_mut().fold(auto_height, |auto_height, paragraph| { - let mut paragraph = paragraph.build(); - paragraph.layout(width); - auto_height + paragraph.height() - }) - }) -} - fn get_text_stroke_paints_with_shadows( stroke: &Stroke, blur: Option<&ImageFilter>, diff --git a/render-wasm/src/textlayout.rs b/render-wasm/src/textlayout.rs new file mode 100644 index 0000000000..23ce4e6ebc --- /dev/null +++ b/render-wasm/src/textlayout.rs @@ -0,0 +1,53 @@ +use skia_safe::textlayout::ParagraphBuilder; + +pub fn auto_width(paragraphs: &mut [Vec], width: f32) -> f32 { + let built_paragraphs = get_built_paragraphs(paragraphs, width); + + built_paragraphs + .iter() + .flatten() + .fold(0.0, |auto_width, p| { + f32::max(p.max_intrinsic_width(), auto_width) + }) +} + +pub fn auto_height(paragraphs: &mut [Vec], width: f32) -> f32 { + paragraphs.iter_mut().fold(0.0, |auto_height, p| { + p.iter_mut().fold(auto_height, |auto_height, paragraph| { + let mut paragraph = paragraph.build(); + paragraph.layout(width); + auto_height + paragraph.height() + }) + }) +} + +pub fn build_paragraphs_with_width( + paragraphs: &mut [Vec], + width: f32, +) -> Vec> { + paragraphs + .iter_mut() + .map(|builders| { + builders + .iter_mut() + .map(|builder| { + let mut paragraph = builder.build(); + // For auto-width, always layout with infinite width first to get intrinsic width + paragraph.layout(f32::MAX); + let intrinsic_width = paragraph.max_intrinsic_width().ceil(); + // Use the larger of the requested width or intrinsic width to prevent line breaks + let final_width = f32::max(width, intrinsic_width); + paragraph.layout(final_width); + paragraph + }) + .collect() + }) + .collect() +} + +fn get_built_paragraphs( + paragraphs: &mut [Vec], + width: f32, +) -> Vec> { + build_paragraphs_with_width(paragraphs, width) +} diff --git a/render-wasm/src/wasm/text.rs b/render-wasm/src/wasm/text.rs index 28976c66ff..886449dd5d 100644 --- a/render-wasm/src/wasm/text.rs +++ b/render-wasm/src/wasm/text.rs @@ -1,8 +1,7 @@ use crate::mem; -use crate::shapes::{auto_height, build_paragraphs_with_width, GrowType, RawTextData, Type}; - -use crate::STATE; -use crate::{with_current_shape, with_current_shape_mut}; +use crate::shapes::{GrowType, RawTextData, Type}; +use crate::textlayout::{auto_height, build_paragraphs_with_width}; +use crate::{with_current_shape, with_current_shape_mut, STATE}; #[no_mangle] pub extern "C" fn clear_shape_text() { From 50b9e8c6e681455c46bd12ef483afecbfb1f0c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Tue, 2 Sep 2025 15:07:13 +0200 Subject: [PATCH 2/5] :recycle: Rename TextContent::get_width to TextContent::width --- render-wasm/src/render/text.rs | 2 +- render-wasm/src/shapes/modifiers.rs | 2 +- render-wasm/src/shapes/text.rs | 11 +++-------- render-wasm/src/wasm/text.rs | 2 +- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/render-wasm/src/render/text.rs b/render-wasm/src/render/text.rs index 593dd008ff..25e4a58c76 100644 --- a/render-wasm/src/render/text.rs +++ b/render-wasm/src/render/text.rs @@ -19,7 +19,7 @@ pub fn render( // Width let paragraph_width = if let crate::shapes::Type::Text(text_content) = &shape.shape_type { - text_content.get_width() + text_content.width() } else { shape.width() }; diff --git a/render-wasm/src/shapes/modifiers.rs b/render-wasm/src/shapes/modifiers.rs index 6f70d32975..d1be0a4180 100644 --- a/render-wasm/src/shapes/modifiers.rs +++ b/render-wasm/src/shapes/modifiers.rs @@ -212,7 +212,7 @@ fn propagate_transform( transform.post_concat(&resize_transform); } GrowType::AutoWidth => { - let paragraph_width = content.get_width(); + let paragraph_width = content.width(); let mut paragraphs = content.to_paragraphs(None, None, None); let height = auto_height(&mut paragraphs, paragraph_width); let resize_transform = math::resize_matrix( diff --git a/render-wasm/src/shapes/text.rs b/render-wasm/src/shapes/text.rs index acbca475b3..e2f362b312 100644 --- a/render-wasm/src/shapes/text.rs +++ b/render-wasm/src/shapes/text.rs @@ -66,11 +66,6 @@ impl TextContent { self.bounds = Rect::from_xywh(x, y, w, h); } - #[allow(dead_code)] - pub fn width(&self) -> f32 { - self.bounds.width() - } - #[allow(dead_code)] pub fn x(&self) -> f32 { self.bounds.x() @@ -178,13 +173,13 @@ impl TextContent { paragraph_group } - pub fn get_width(&self) -> f32 { + pub fn width(&self) -> f32 { if self.grow_type() == GrowType::AutoWidth { let temp_paragraphs = self.to_paragraphs(None, None, None); let mut temp_paragraphs = temp_paragraphs; auto_width(&mut temp_paragraphs, f32::MAX).ceil() } else { - self.width() + self.bounds.width() } } @@ -197,7 +192,7 @@ impl TextContent { } pub fn visual_bounds(&self) -> (f32, f32) { - let paragraph_width = self.get_width(); + let paragraph_width = self.width(); let mut paragraphs = self.to_paragraphs(None, None, None); let paragraph_height = auto_height(&mut paragraphs, paragraph_width); (paragraph_width, paragraph_height) diff --git a/render-wasm/src/wasm/text.rs b/render-wasm/src/wasm/text.rs index 886449dd5d..6f5e71c2b5 100644 --- a/render-wasm/src/wasm/text.rs +++ b/render-wasm/src/wasm/text.rs @@ -43,7 +43,7 @@ pub extern "C" fn get_text_dimensions() -> *mut u8 { if let Type::Text(content) = &shape.shape_type { // 1. Reset Paragraphs - let paragraph_width = content.get_width(); + let paragraph_width = content.width(); let mut paragraphs = content.to_paragraphs(None, None, None); let built_paragraphs = build_paragraphs_with_width(&mut paragraphs, paragraph_width); From d40b68c004ebc9afa8725960c627f4bcaac2a6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Tue, 2 Sep 2025 15:22:05 +0200 Subject: [PATCH 3/5] :recycle: Refactor and rename ParagraphBuilder instantiating from TextContent --- render-wasm/src/render.rs | 28 ++- render-wasm/src/shapes/modifiers.rs | 6 +- render-wasm/src/shapes/text.rs | 299 ++------------------------- render-wasm/src/shapes/text_paths.rs | 4 +- render-wasm/src/textlayout.rs | 286 ++++++++++++++++++++++++- render-wasm/src/wasm/text.rs | 10 +- 6 files changed, 332 insertions(+), 301 deletions(-) diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index f4e48e05a7..ca176758eb 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -24,6 +24,7 @@ pub use surfaces::{SurfaceId, Surfaces}; use crate::performance; use crate::shapes::{Blur, BlurType, Corners, Fill, Shape, StructureEntry, Type}; use crate::state::ShapesPool; +use crate::textlayout::{paragraph_builders_from_text, stroke_paragraph_builders_from_text}; use crate::tiles::{self, PendingTiles, TileRect}; use crate::uuid::Uuid; use crate::view::Viewbox; @@ -541,13 +542,18 @@ impl RenderState { let inner_shadows = shape.inner_shadow_paints(); let blur_filter = shape.image_filter(1.); let blur_mask = shape.mask_filter(1.); - let mut paragraphs = - text_content.to_paragraphs(blur_filter.as_ref(), blur_mask.as_ref(), None); + let mut paragraphs = paragraph_builders_from_text( + &text_content, + blur_filter.as_ref(), + blur_mask.as_ref(), + None, + ); // Render all drop shadows if there are no visible strokes if !shape.has_visible_strokes() && !drop_shadows.is_empty() { for drop_shadow in &drop_shadows { - let mut paragraphs_with_drop_shadows = text_content.to_paragraphs( + let mut paragraphs_with_drop_shadows = paragraph_builders_from_text( + &text_content, blur_filter.as_ref(), blur_mask.as_ref(), Some(drop_shadow), @@ -564,8 +570,9 @@ impl RenderState { text::render(self, &shape, &mut paragraphs, None); for stroke in shape.visible_strokes().rev() { for drop_shadow in &drop_shadows { - let mut stroke_paragraphs_with_drop_shadows = text_content - .to_stroke_paragraphs( + let mut stroke_paragraphs_with_drop_shadows = + stroke_paragraph_builders_from_text( + &text_content, stroke, &shape.selrect(), blur_filter.as_ref(), @@ -580,7 +587,8 @@ impl RenderState { ); } - let mut stroke_paragraphs = text_content.to_stroke_paragraphs( + let mut stroke_paragraphs = stroke_paragraph_builders_from_text( + &text_content, stroke, &shape.selrect(), blur_filter.as_ref(), @@ -600,8 +608,9 @@ impl RenderState { ); for inner_shadow in &inner_shadows { - let mut stroke_paragraphs_with_inner_shadows = text_content - .to_stroke_paragraphs( + let mut stroke_paragraphs_with_inner_shadows = + stroke_paragraph_builders_from_text( + &text_content, stroke, &shape.selrect(), blur_filter.as_ref(), @@ -618,7 +627,8 @@ impl RenderState { } for inner_shadow in &inner_shadows { - let mut paragraphs_with_inner_shadows = text_content.to_paragraphs( + let mut paragraphs_with_inner_shadows = paragraph_builders_from_text( + &text_content, blur_filter.as_ref(), blur_mask.as_ref(), Some(inner_shadow), diff --git a/render-wasm/src/shapes/modifiers.rs b/render-wasm/src/shapes/modifiers.rs index d1be0a4180..c150e4ba61 100644 --- a/render-wasm/src/shapes/modifiers.rs +++ b/render-wasm/src/shapes/modifiers.rs @@ -14,7 +14,7 @@ use crate::shapes::{ TransformEntry, Type, }; use crate::state::{ShapesPool, State}; -use crate::textlayout::auto_height; +use crate::textlayout::{auto_height, paragraph_builders_from_text}; use crate::uuid::Uuid; #[allow(clippy::too_many_arguments)] @@ -200,7 +200,7 @@ fn propagate_transform( match content.grow_type() { GrowType::AutoHeight => { let paragraph_width = shape_bounds_after.width(); - let mut paragraphs = content.to_paragraphs(None, None, None); + let mut paragraphs = paragraph_builders_from_text(content, None, None, None); let height = auto_height(&mut paragraphs, paragraph_width); let resize_transform = math::resize_matrix( &shape_bounds_after, @@ -213,7 +213,7 @@ fn propagate_transform( } GrowType::AutoWidth => { let paragraph_width = content.width(); - let mut paragraphs = content.to_paragraphs(None, None, None); + let mut paragraphs = paragraph_builders_from_text(content, None, None, None); let height = auto_height(&mut paragraphs, paragraph_width); let resize_transform = math::resize_matrix( &shape_bounds_after, diff --git a/render-wasm/src/shapes/text.rs b/render-wasm/src/shapes/text.rs index e2f362b312..bce3fda8c3 100644 --- a/render-wasm/src/shapes/text.rs +++ b/render-wasm/src/shapes/text.rs @@ -1,20 +1,16 @@ use crate::{ math::{Matrix, Rect}, - render::{default_font, filters::compose_filters, DEFAULT_EMOJI_FONT}, + render::{default_font, DEFAULT_EMOJI_FONT}, + textlayout::paragraph_builders_from_text, }; -use skia_safe::{ - self as skia, - paint::Paint, - textlayout::{ParagraphBuilder, ParagraphStyle}, - ImageFilter, MaskFilter, -}; +use skia_safe::{self as skia, paint::Paint, textlayout::ParagraphStyle, ImageFilter, MaskFilter}; use std::collections::HashSet; use super::FontFamily; -use crate::shapes::{self, merge_fills, set_paint_fill, Stroke, StrokeKind}; +use crate::shapes::{self, merge_fills}; use crate::textlayout::{auto_height, auto_width}; -use crate::utils::{get_fallback_fonts, get_font_collection, uuid_from_u32}; +use crate::utils::uuid_from_u32; use crate::wasm::fills::parse_fills_from_bytes; use crate::Uuid; @@ -62,6 +58,10 @@ impl TextContent { } } + pub fn bounds(&self) -> Rect { + self.bounds + } + pub fn set_xywh(&mut self, x: f32, y: f32, w: f32, h: f32) { self.bounds = Rect::from_xywh(x, y, w, h); } @@ -80,102 +80,13 @@ impl TextContent { self.paragraphs.push(paragraph); } - pub fn to_paragraphs( - &self, - blur: Option<&ImageFilter>, - blur_mask: Option<&MaskFilter>, - shadow: Option<&Paint>, - ) -> Vec> { - let fonts = get_font_collection(); - let fallback_fonts = get_fallback_fonts(); - let mut paragraph_group = Vec::new(); - - for paragraph in &self.paragraphs { - let paragraph_style = paragraph.paragraph_to_style(); - let mut builder = ParagraphBuilder::new(¶graph_style, fonts); - for leaf in ¶graph.children { - let text_style = - leaf.to_style(&self.bounds, fallback_fonts, blur, blur_mask, shadow); - let text = leaf.apply_text_transform(); - builder.push_style(&text_style); - builder.add_text(&text); - } - paragraph_group.push(vec![builder]); - } - - paragraph_group - } - - pub fn to_stroke_paragraphs( - &self, - stroke: &Stroke, - bounds: &Rect, - blur: Option<&ImageFilter>, - blur_mask: Option<&MaskFilter>, - shadow: Option<&Paint>, - count_inner_strokes: usize, - ) -> Vec> { - let fallback_fonts = get_fallback_fonts(); - let fonts = get_font_collection(); - let mut paragraph_group = Vec::new(); - - for paragraph in &self.paragraphs { - let mut stroke_paragraphs_map: std::collections::HashMap = - std::collections::HashMap::new(); - - for leaf in paragraph.children.iter() { - let mut text_paint = merge_fills(&leaf.fills, *bounds); - if let Some(blur_mask) = blur_mask { - text_paint.set_mask_filter(blur_mask.clone()); - } - - let stroke_paints = if shadow.is_some() { - get_text_stroke_paints_with_shadows( - stroke, - blur, - blur_mask, - shadow, - leaf.is_transparent(), - ) - } else { - get_text_stroke_paints( - stroke, - bounds, - &text_paint, - blur, - blur_mask, - count_inner_strokes, - ) - }; - - 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_paint = stroke_paint.clone(); - let stroke_style = - leaf.to_stroke_style(&stroke_paint, fallback_fonts, blur, blur_mask, None); - builder.push_style(&stroke_style); - builder.add_text(&text); - } - } - - let stroke_paragraphs: Vec = (0..stroke_paragraphs_map.len()) - .map(|i| stroke_paragraphs_map.remove(&i).unwrap()) - .collect(); - - paragraph_group.push(stroke_paragraphs); - } - - paragraph_group + pub fn paragraphs(&self) -> &Vec { + &self.paragraphs } pub fn width(&self) -> f32 { if self.grow_type() == GrowType::AutoWidth { - let temp_paragraphs = self.to_paragraphs(None, None, None); + let temp_paragraphs = paragraph_builders_from_text(self, None, None, None); let mut temp_paragraphs = temp_paragraphs; auto_width(&mut temp_paragraphs, f32::MAX).ceil() } else { @@ -193,7 +104,7 @@ impl TextContent { pub fn visual_bounds(&self) -> (f32, f32) { let paragraph_width = self.width(); - let mut paragraphs = self.to_paragraphs(None, None, None); + let mut paragraphs = paragraph_builders_from_text(self, None, None, None); let paragraph_height = auto_height(&mut paragraphs, paragraph_width); (paragraph_width, paragraph_height) } @@ -390,6 +301,10 @@ impl TextLeaf { } } + pub fn fills(&self) -> &[shapes::Fill] { + &self.fills + } + pub fn to_style( &self, content_bounds: &Rect, @@ -713,183 +628,3 @@ impl From<&Vec> for RawTextData { Self { paragraph } } } - -fn get_text_stroke_paints_with_shadows( - stroke: &Stroke, - blur: Option<&ImageFilter>, - blur_mask: Option<&MaskFilter>, - shadow: Option<&Paint>, - is_transparent: bool, -) -> Vec { - let mut paints = Vec::new(); - - match stroke.kind { - StrokeKind::Inner => { - let mut paint = skia_safe::Paint::default(); - paint.set_style(skia::PaintStyle::Fill); - paint.set_anti_alias(true); - - if let Some(blur) = blur { - paint.set_image_filter(blur.clone()); - } - - if let Some(shadow) = shadow { - paint.set_image_filter(shadow.image_filter()); - } - - paints.push(paint.clone()); - - if is_transparent { - let image_filter = skia_safe::image_filters::erode( - (stroke.width, stroke.width), - paint.image_filter(), - None, - ); - paint.set_image_filter(image_filter); - paint.set_blend_mode(skia::BlendMode::DstOut); - paints.push(paint.clone()); - } - } - StrokeKind::Center => { - let mut paint = skia_safe::Paint::default(); - paint.set_anti_alias(true); - paint.set_stroke_width(stroke.width); - - if let Some(blur) = blur { - paint.set_image_filter(blur.clone()); - } - - if let Some(shadow) = shadow { - paint.set_image_filter(shadow.image_filter()); - } - - if is_transparent { - paint.set_style(skia::PaintStyle::Stroke); - } else { - paint.set_style(skia::PaintStyle::StrokeAndFill); - } - - paints.push(paint); - } - StrokeKind::Outer => { - let mut paint = skia_safe::Paint::default(); - paint.set_style(skia::PaintStyle::StrokeAndFill); - paint.set_anti_alias(true); - paint.set_stroke_width(stroke.width * 2.0); - - if let Some(blur_mask) = blur_mask { - paint.set_mask_filter(blur_mask.clone()); - } - - if let Some(shadow) = shadow { - paint.set_image_filter(shadow.image_filter()); - } - - paints.push(paint.clone()); - - if is_transparent { - let image_filter = skia_safe::image_filters::erode( - (stroke.width, stroke.width), - paint.image_filter(), - None, - ); - paint.set_image_filter(image_filter); - paint.set_blend_mode(skia::BlendMode::DstOut); - paints.push(paint.clone()); - } - } - } - paints -} - -fn get_text_stroke_paints( - stroke: &Stroke, - bounds: &Rect, - text_paint: &Paint, - blur: Option<&ImageFilter>, - blur_mask: Option<&MaskFilter>, - count_inner_strokes: usize, -) -> Vec { - let mut paints = Vec::new(); - - match stroke.kind { - StrokeKind::Inner => { - let shader = text_paint.shader(); - let mut is_opaque = true; - - if shader.is_some() { - is_opaque = shader.unwrap().is_opaque(); - } - - if is_opaque && count_inner_strokes == 1 { - let mut paint = text_paint.clone(); - paint.set_style(skia::PaintStyle::Fill); - paint.set_anti_alias(true); - if let Some(blur) = blur { - paint.set_image_filter(blur.clone()); - } - 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); - if let Some(blur) = blur { - paint.set_image_filter(blur.clone()); - } - paints.push(paint); - } else { - let mut paint = text_paint.clone(); - paint.set_style(skia::PaintStyle::Fill); - paint.set_anti_alias(false); - set_paint_fill(&mut paint, &stroke.fill, bounds); - paints.push(paint); - - let mut paint = skia::Paint::default(); - let image_filter = - skia_safe::image_filters::erode((stroke.width, stroke.width), None, None); - - let filter = compose_filters(blur, image_filter.as_ref()); - paint.set_image_filter(filter); - paint.set_anti_alias(false); - paint.set_blend_mode(skia::BlendMode::DstOut); - paints.push(paint); - } - } - StrokeKind::Center => { - let mut paint = skia::Paint::default(); - paint.set_style(skia::PaintStyle::Stroke); - paint.set_anti_alias(true); - paint.set_stroke_width(stroke.width); - - set_paint_fill(&mut paint, &stroke.fill, bounds); - if let Some(blur) = blur { - paint.set_image_filter(blur.clone()); - } - - paints.push(paint); - } - StrokeKind::Outer => { - let mut paint = skia::Paint::default(); - paint.set_style(skia::PaintStyle::Stroke); - paint.set_blend_mode(skia::BlendMode::DstOver); - paint.set_anti_alias(true); - paint.set_stroke_width(stroke.width * 2.0); - set_paint_fill(&mut paint, &stroke.fill, bounds); - if let Some(blur_mask) = blur_mask { - paint.set_mask_filter(blur_mask.clone()); - } - paints.push(paint); - - let mut paint = skia::Paint::default(); - paint.set_style(skia::PaintStyle::Fill); - paint.set_blend_mode(skia::BlendMode::Clear); - paint.set_color(skia::Color::TRANSPARENT); - paint.set_anti_alias(true); - paints.push(paint); - } - } - - paints -} diff --git a/render-wasm/src/shapes/text_paths.rs b/render-wasm/src/shapes/text_paths.rs index 9c12b86a83..7749313d77 100644 --- a/render-wasm/src/shapes/text_paths.rs +++ b/render-wasm/src/shapes/text_paths.rs @@ -1,4 +1,4 @@ -use crate::shapes::text::TextContent; +use crate::{shapes::text::TextContent, textlayout::paragraph_builders_from_text}; use skia_safe::{ self as skia, textlayout::Paragraph as SkiaParagraph, FontMetrics, Point, Rect, TextBlob, }; @@ -20,7 +20,7 @@ impl TextPaths { let mut paths = Vec::new(); let mut offset_y = self.bounds.y(); - let mut paragraphs = self.to_paragraphs(None, None, None); + let mut paragraphs = paragraph_builders_from_text(&self.0, None, None, None); for paragraphs in paragraphs.iter_mut() { for paragraph_builder in paragraphs.iter_mut() { diff --git a/render-wasm/src/textlayout.rs b/render-wasm/src/textlayout.rs index 23ce4e6ebc..29c45d119c 100644 --- a/render-wasm/src/textlayout.rs +++ b/render-wasm/src/textlayout.rs @@ -1,4 +1,10 @@ -use skia_safe::textlayout::ParagraphBuilder; +use skia_safe::{self as skia, textlayout::ParagraphBuilder, ImageFilter, MaskFilter, Paint, Rect}; + +use crate::{ + render::filters::compose_filters, + shapes::{merge_fills, set_paint_fill, Stroke, StrokeKind, TextContent}, + utils::{get_fallback_fonts, get_font_collection}, +}; pub fn auto_width(paragraphs: &mut [Vec], width: f32) -> f32 { let built_paragraphs = get_built_paragraphs(paragraphs, width); @@ -45,9 +51,287 @@ pub fn build_paragraphs_with_width( .collect() } +pub fn paragraph_builders_from_text( + text_content: &TextContent, + blur: Option<&ImageFilter>, + blur_mask: Option<&MaskFilter>, + shadow: Option<&Paint>, +) -> Vec> { + let fonts = get_font_collection(); + let fallback_fonts = get_fallback_fonts(); + let mut paragraph_group = Vec::new(); + + for paragraph in text_content.paragraphs() { + let paragraph_style = paragraph.paragraph_to_style(); + let mut builder = ParagraphBuilder::new(¶graph_style, fonts); + for leaf in paragraph.get_children() { + let text_style = leaf.to_style( + &text_content.bounds(), + fallback_fonts, + blur, + blur_mask, + shadow, + ); + let text = leaf.apply_text_transform(); + builder.push_style(&text_style); + builder.add_text(&text); + } + paragraph_group.push(vec![builder]); + } + + paragraph_group +} + +pub fn stroke_paragraph_builders_from_text( + text_content: &TextContent, + stroke: &Stroke, + bounds: &Rect, + blur: Option<&ImageFilter>, + blur_mask: Option<&MaskFilter>, + shadow: Option<&Paint>, + count_inner_strokes: usize, +) -> Vec> { + let fallback_fonts = get_fallback_fonts(); + let fonts = get_font_collection(); + let mut paragraph_group = Vec::new(); + + for paragraph in text_content.paragraphs() { + let mut stroke_paragraphs_map: std::collections::HashMap = + std::collections::HashMap::new(); + + for leaf in paragraph.get_children().iter() { + let mut text_paint = merge_fills(leaf.fills(), *bounds); + if let Some(blur_mask) = blur_mask { + text_paint.set_mask_filter(blur_mask.clone()); + } + + let stroke_paints = if shadow.is_some() { + get_text_stroke_paints_with_shadows( + stroke, + blur, + blur_mask, + shadow, + leaf.is_transparent(), + ) + } else { + get_text_stroke_paints( + stroke, + bounds, + &text_paint, + blur, + blur_mask, + count_inner_strokes, + ) + }; + + 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_paint = stroke_paint.clone(); + let stroke_style = + leaf.to_stroke_style(&stroke_paint, fallback_fonts, blur, blur_mask, None); + builder.push_style(&stroke_style); + builder.add_text(&text); + } + } + + let stroke_paragraphs: Vec = (0..stroke_paragraphs_map.len()) + .map(|i| stroke_paragraphs_map.remove(&i).unwrap()) + .collect(); + + paragraph_group.push(stroke_paragraphs); + } + + paragraph_group +} + fn get_built_paragraphs( paragraphs: &mut [Vec], width: f32, ) -> Vec> { build_paragraphs_with_width(paragraphs, width) } + +fn get_text_stroke_paints_with_shadows( + stroke: &Stroke, + blur: Option<&ImageFilter>, + blur_mask: Option<&MaskFilter>, + shadow: Option<&Paint>, + is_transparent: bool, +) -> Vec { + let mut paints = Vec::new(); + + match stroke.kind { + StrokeKind::Inner => { + let mut paint = Paint::default(); + paint.set_style(skia::PaintStyle::Fill); + paint.set_anti_alias(true); + + if let Some(blur) = blur { + paint.set_image_filter(blur.clone()); + } + + if let Some(shadow) = shadow { + paint.set_image_filter(shadow.image_filter()); + } + + paints.push(paint.clone()); + + if is_transparent { + let image_filter = skia_safe::image_filters::erode( + (stroke.width, stroke.width), + paint.image_filter(), + None, + ); + paint.set_image_filter(image_filter); + paint.set_blend_mode(skia::BlendMode::DstOut); + paints.push(paint.clone()); + } + } + StrokeKind::Center => { + let mut paint = skia_safe::Paint::default(); + paint.set_anti_alias(true); + paint.set_stroke_width(stroke.width); + + if let Some(blur) = blur { + paint.set_image_filter(blur.clone()); + } + + if let Some(shadow) = shadow { + paint.set_image_filter(shadow.image_filter()); + } + + if is_transparent { + paint.set_style(skia::PaintStyle::Stroke); + } else { + paint.set_style(skia::PaintStyle::StrokeAndFill); + } + + paints.push(paint); + } + StrokeKind::Outer => { + let mut paint = skia_safe::Paint::default(); + paint.set_style(skia::PaintStyle::StrokeAndFill); + paint.set_anti_alias(true); + paint.set_stroke_width(stroke.width * 2.0); + + if let Some(blur_mask) = blur_mask { + paint.set_mask_filter(blur_mask.clone()); + } + + if let Some(shadow) = shadow { + paint.set_image_filter(shadow.image_filter()); + } + + paints.push(paint.clone()); + + if is_transparent { + let image_filter = skia_safe::image_filters::erode( + (stroke.width, stroke.width), + paint.image_filter(), + None, + ); + paint.set_image_filter(image_filter); + paint.set_blend_mode(skia::BlendMode::DstOut); + paints.push(paint.clone()); + } + } + } + paints +} + +fn get_text_stroke_paints( + stroke: &Stroke, + bounds: &Rect, + text_paint: &Paint, + blur: Option<&ImageFilter>, + blur_mask: Option<&MaskFilter>, + count_inner_strokes: usize, +) -> Vec { + let mut paints = Vec::new(); + + match stroke.kind { + StrokeKind::Inner => { + let shader = text_paint.shader(); + let mut is_opaque = true; + + if shader.is_some() { + is_opaque = shader.unwrap().is_opaque(); + } + + if is_opaque && count_inner_strokes == 1 { + let mut paint = text_paint.clone(); + paint.set_style(skia::PaintStyle::Fill); + paint.set_anti_alias(true); + if let Some(blur) = blur { + paint.set_image_filter(blur.clone()); + } + 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); + if let Some(blur) = blur { + paint.set_image_filter(blur.clone()); + } + paints.push(paint); + } else { + let mut paint = text_paint.clone(); + paint.set_style(skia::PaintStyle::Fill); + paint.set_anti_alias(false); + set_paint_fill(&mut paint, &stroke.fill, bounds); + paints.push(paint); + + let mut paint = skia::Paint::default(); + let image_filter = + skia_safe::image_filters::erode((stroke.width, stroke.width), None, None); + + let filter = compose_filters(blur, image_filter.as_ref()); + paint.set_image_filter(filter); + paint.set_anti_alias(false); + paint.set_blend_mode(skia::BlendMode::DstOut); + paints.push(paint); + } + } + StrokeKind::Center => { + let mut paint = skia::Paint::default(); + paint.set_style(skia::PaintStyle::Stroke); + paint.set_anti_alias(true); + paint.set_stroke_width(stroke.width); + + set_paint_fill(&mut paint, &stroke.fill, bounds); + if let Some(blur) = blur { + paint.set_image_filter(blur.clone()); + } + + paints.push(paint); + } + StrokeKind::Outer => { + let mut paint = skia::Paint::default(); + paint.set_style(skia::PaintStyle::Stroke); + paint.set_blend_mode(skia::BlendMode::DstOver); + paint.set_anti_alias(true); + paint.set_stroke_width(stroke.width * 2.0); + set_paint_fill(&mut paint, &stroke.fill, bounds); + if let Some(blur_mask) = blur_mask { + paint.set_mask_filter(blur_mask.clone()); + } + paints.push(paint); + + let mut paint = skia::Paint::default(); + paint.set_style(skia::PaintStyle::Fill); + paint.set_blend_mode(skia::BlendMode::Clear); + paint.set_color(skia::Color::TRANSPARENT); + paint.set_anti_alias(true); + paints.push(paint); + } + } + + paints +} diff --git a/render-wasm/src/wasm/text.rs b/render-wasm/src/wasm/text.rs index 6f5e71c2b5..5c075573d1 100644 --- a/render-wasm/src/wasm/text.rs +++ b/render-wasm/src/wasm/text.rs @@ -1,6 +1,6 @@ use crate::mem; use crate::shapes::{GrowType, RawTextData, Type}; -use crate::textlayout::{auto_height, build_paragraphs_with_width}; +use crate::textlayout::{auto_height, build_paragraphs_with_width, paragraph_builders_from_text}; use crate::{with_current_shape, with_current_shape_mut, STATE}; #[no_mangle] @@ -44,7 +44,7 @@ pub extern "C" fn get_text_dimensions() -> *mut u8 { if let Type::Text(content) = &shape.shape_type { // 1. Reset Paragraphs let paragraph_width = content.width(); - let mut paragraphs = content.to_paragraphs(None, None, None); + let mut paragraphs = paragraph_builders_from_text(content, None, None, None); let built_paragraphs = build_paragraphs_with_width(&mut paragraphs, paragraph_width); // 2. Max Width Calculation @@ -56,12 +56,14 @@ pub extern "C" fn get_text_dimensions() -> *mut u8 { // 3. Width and Height Calculation match content.grow_type() { GrowType::AutoHeight => { - let mut paragraph_height = content.to_paragraphs(None, None, None); + let mut paragraph_height = + paragraph_builders_from_text(content, None, None, None); height = auto_height(&mut paragraph_height, paragraph_width).ceil(); } GrowType::AutoWidth => { width = paragraph_width; - let mut paragraph_height = content.to_paragraphs(None, None, None); + let mut paragraph_height = + paragraph_builders_from_text(content, None, None, None); height = auto_height(&mut paragraph_height, paragraph_width).ceil(); } GrowType::Fixed => {} From 1cf0de395cb6b1088b374f52ebf5cb25e2931a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Tue, 2 Sep 2025 15:30:54 +0200 Subject: [PATCH 4/5] :recycle: Rename get_children to children (Paragraph) --- render-wasm/src/shapes/text.rs | 5 ++--- render-wasm/src/textlayout.rs | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/render-wasm/src/shapes/text.rs b/render-wasm/src/shapes/text.rs index bce3fda8c3..d56d2e6f28 100644 --- a/render-wasm/src/shapes/text.rs +++ b/render-wasm/src/shapes/text.rs @@ -80,7 +80,7 @@ impl TextContent { self.paragraphs.push(paragraph); } - pub fn paragraphs(&self) -> &Vec { + pub fn paragraphs(&self) -> &[Paragraph] { &self.paragraphs } @@ -194,8 +194,7 @@ impl Paragraph { self.children = children; } - #[allow(dead_code)] - pub fn get_children(&self) -> &Vec { + pub fn children(&self) -> &[TextLeaf] { &self.children } diff --git a/render-wasm/src/textlayout.rs b/render-wasm/src/textlayout.rs index 29c45d119c..3be44c1d85 100644 --- a/render-wasm/src/textlayout.rs +++ b/render-wasm/src/textlayout.rs @@ -64,7 +64,7 @@ pub fn paragraph_builders_from_text( for paragraph in text_content.paragraphs() { let paragraph_style = paragraph.paragraph_to_style(); let mut builder = ParagraphBuilder::new(¶graph_style, fonts); - for leaf in paragraph.get_children() { + for leaf in paragraph.children() { let text_style = leaf.to_style( &text_content.bounds(), fallback_fonts, @@ -99,7 +99,7 @@ pub fn stroke_paragraph_builders_from_text( let mut stroke_paragraphs_map: std::collections::HashMap = std::collections::HashMap::new(); - for leaf in paragraph.get_children().iter() { + for leaf in paragraph.children().iter() { let mut text_paint = merge_fills(leaf.fills(), *bounds); if let Some(blur_mask) = blur_mask { text_paint.set_mask_filter(blur_mask.clone()); From 3e02dc550fb289793106d3d2c833779f71cd2367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Tue, 2 Sep 2025 15:32:10 +0200 Subject: [PATCH 5/5] :recycle: Create type alias for ParagraphBuilderGroup --- render-wasm/src/render.rs | 16 +++++++++------- render-wasm/src/shapes/modifiers.rs | 6 +++--- render-wasm/src/shapes/text.rs | 6 +++--- render-wasm/src/shapes/text_paths.rs | 4 ++-- render-wasm/src/textlayout.rs | 10 ++++++---- render-wasm/src/wasm/text.rs | 10 ++++++---- 6 files changed, 29 insertions(+), 23 deletions(-) diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index ca176758eb..8ab8338cbd 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -24,7 +24,9 @@ pub use surfaces::{SurfaceId, Surfaces}; use crate::performance; use crate::shapes::{Blur, BlurType, Corners, Fill, Shape, StructureEntry, Type}; use crate::state::ShapesPool; -use crate::textlayout::{paragraph_builders_from_text, stroke_paragraph_builders_from_text}; +use crate::textlayout::{ + paragraph_builder_group_from_text, stroke_paragraph_builder_group_from_text, +}; use crate::tiles::{self, PendingTiles, TileRect}; use crate::uuid::Uuid; use crate::view::Viewbox; @@ -542,7 +544,7 @@ impl RenderState { let inner_shadows = shape.inner_shadow_paints(); let blur_filter = shape.image_filter(1.); let blur_mask = shape.mask_filter(1.); - let mut paragraphs = paragraph_builders_from_text( + let mut paragraphs = paragraph_builder_group_from_text( &text_content, blur_filter.as_ref(), blur_mask.as_ref(), @@ -552,7 +554,7 @@ impl RenderState { // Render all drop shadows if there are no visible strokes if !shape.has_visible_strokes() && !drop_shadows.is_empty() { for drop_shadow in &drop_shadows { - let mut paragraphs_with_drop_shadows = paragraph_builders_from_text( + let mut paragraphs_with_drop_shadows = paragraph_builder_group_from_text( &text_content, blur_filter.as_ref(), blur_mask.as_ref(), @@ -571,7 +573,7 @@ impl RenderState { for stroke in shape.visible_strokes().rev() { for drop_shadow in &drop_shadows { let mut stroke_paragraphs_with_drop_shadows = - stroke_paragraph_builders_from_text( + stroke_paragraph_builder_group_from_text( &text_content, stroke, &shape.selrect(), @@ -587,7 +589,7 @@ impl RenderState { ); } - let mut stroke_paragraphs = stroke_paragraph_builders_from_text( + let mut stroke_paragraphs = stroke_paragraph_builder_group_from_text( &text_content, stroke, &shape.selrect(), @@ -609,7 +611,7 @@ impl RenderState { for inner_shadow in &inner_shadows { let mut stroke_paragraphs_with_inner_shadows = - stroke_paragraph_builders_from_text( + stroke_paragraph_builder_group_from_text( &text_content, stroke, &shape.selrect(), @@ -627,7 +629,7 @@ impl RenderState { } for inner_shadow in &inner_shadows { - let mut paragraphs_with_inner_shadows = paragraph_builders_from_text( + let mut paragraphs_with_inner_shadows = paragraph_builder_group_from_text( &text_content, blur_filter.as_ref(), blur_mask.as_ref(), diff --git a/render-wasm/src/shapes/modifiers.rs b/render-wasm/src/shapes/modifiers.rs index c150e4ba61..a74f201c3e 100644 --- a/render-wasm/src/shapes/modifiers.rs +++ b/render-wasm/src/shapes/modifiers.rs @@ -14,7 +14,7 @@ use crate::shapes::{ TransformEntry, Type, }; use crate::state::{ShapesPool, State}; -use crate::textlayout::{auto_height, paragraph_builders_from_text}; +use crate::textlayout::{auto_height, paragraph_builder_group_from_text}; use crate::uuid::Uuid; #[allow(clippy::too_many_arguments)] @@ -200,7 +200,7 @@ fn propagate_transform( match content.grow_type() { GrowType::AutoHeight => { let paragraph_width = shape_bounds_after.width(); - let mut paragraphs = paragraph_builders_from_text(content, None, None, None); + let mut paragraphs = paragraph_builder_group_from_text(content, None, None, None); let height = auto_height(&mut paragraphs, paragraph_width); let resize_transform = math::resize_matrix( &shape_bounds_after, @@ -213,7 +213,7 @@ fn propagate_transform( } GrowType::AutoWidth => { let paragraph_width = content.width(); - let mut paragraphs = paragraph_builders_from_text(content, None, None, None); + let mut paragraphs = paragraph_builder_group_from_text(content, None, None, None); let height = auto_height(&mut paragraphs, paragraph_width); let resize_transform = math::resize_matrix( &shape_bounds_after, diff --git a/render-wasm/src/shapes/text.rs b/render-wasm/src/shapes/text.rs index d56d2e6f28..35fb4b42a8 100644 --- a/render-wasm/src/shapes/text.rs +++ b/render-wasm/src/shapes/text.rs @@ -1,7 +1,7 @@ use crate::{ math::{Matrix, Rect}, render::{default_font, DEFAULT_EMOJI_FONT}, - textlayout::paragraph_builders_from_text, + textlayout::paragraph_builder_group_from_text, }; use skia_safe::{self as skia, paint::Paint, textlayout::ParagraphStyle, ImageFilter, MaskFilter}; @@ -86,7 +86,7 @@ impl TextContent { pub fn width(&self) -> f32 { if self.grow_type() == GrowType::AutoWidth { - let temp_paragraphs = paragraph_builders_from_text(self, None, None, None); + let temp_paragraphs = paragraph_builder_group_from_text(self, None, None, None); let mut temp_paragraphs = temp_paragraphs; auto_width(&mut temp_paragraphs, f32::MAX).ceil() } else { @@ -104,7 +104,7 @@ impl TextContent { pub fn visual_bounds(&self) -> (f32, f32) { let paragraph_width = self.width(); - let mut paragraphs = paragraph_builders_from_text(self, None, None, None); + let mut paragraphs = paragraph_builder_group_from_text(self, None, None, None); let paragraph_height = auto_height(&mut paragraphs, paragraph_width); (paragraph_width, paragraph_height) } diff --git a/render-wasm/src/shapes/text_paths.rs b/render-wasm/src/shapes/text_paths.rs index 7749313d77..0cf874cdb2 100644 --- a/render-wasm/src/shapes/text_paths.rs +++ b/render-wasm/src/shapes/text_paths.rs @@ -1,4 +1,4 @@ -use crate::{shapes::text::TextContent, textlayout::paragraph_builders_from_text}; +use crate::{shapes::text::TextContent, textlayout::paragraph_builder_group_from_text}; use skia_safe::{ self as skia, textlayout::Paragraph as SkiaParagraph, FontMetrics, Point, Rect, TextBlob, }; @@ -20,7 +20,7 @@ impl TextPaths { let mut paths = Vec::new(); let mut offset_y = self.bounds.y(); - let mut paragraphs = paragraph_builders_from_text(&self.0, None, None, None); + let mut paragraphs = paragraph_builder_group_from_text(&self.0, None, None, None); for paragraphs in paragraphs.iter_mut() { for paragraph_builder in paragraphs.iter_mut() { diff --git a/render-wasm/src/textlayout.rs b/render-wasm/src/textlayout.rs index 3be44c1d85..fc69b4cc6e 100644 --- a/render-wasm/src/textlayout.rs +++ b/render-wasm/src/textlayout.rs @@ -51,12 +51,14 @@ pub fn build_paragraphs_with_width( .collect() } -pub fn paragraph_builders_from_text( +type ParagraphBuilderGroup = Vec; + +pub fn paragraph_builder_group_from_text( text_content: &TextContent, blur: Option<&ImageFilter>, blur_mask: Option<&MaskFilter>, shadow: Option<&Paint>, -) -> Vec> { +) -> Vec { let fonts = get_font_collection(); let fallback_fonts = get_fallback_fonts(); let mut paragraph_group = Vec::new(); @@ -82,7 +84,7 @@ pub fn paragraph_builders_from_text( paragraph_group } -pub fn stroke_paragraph_builders_from_text( +pub fn stroke_paragraph_builder_group_from_text( text_content: &TextContent, stroke: &Stroke, bounds: &Rect, @@ -90,7 +92,7 @@ pub fn stroke_paragraph_builders_from_text( blur_mask: Option<&MaskFilter>, shadow: Option<&Paint>, count_inner_strokes: usize, -) -> Vec> { +) -> Vec { let fallback_fonts = get_fallback_fonts(); let fonts = get_font_collection(); let mut paragraph_group = Vec::new(); diff --git a/render-wasm/src/wasm/text.rs b/render-wasm/src/wasm/text.rs index 5c075573d1..e6cd77ded5 100644 --- a/render-wasm/src/wasm/text.rs +++ b/render-wasm/src/wasm/text.rs @@ -1,6 +1,8 @@ use crate::mem; use crate::shapes::{GrowType, RawTextData, Type}; -use crate::textlayout::{auto_height, build_paragraphs_with_width, paragraph_builders_from_text}; +use crate::textlayout::{ + auto_height, build_paragraphs_with_width, paragraph_builder_group_from_text, +}; use crate::{with_current_shape, with_current_shape_mut, STATE}; #[no_mangle] @@ -44,7 +46,7 @@ pub extern "C" fn get_text_dimensions() -> *mut u8 { if let Type::Text(content) = &shape.shape_type { // 1. Reset Paragraphs let paragraph_width = content.width(); - let mut paragraphs = paragraph_builders_from_text(content, None, None, None); + let mut paragraphs = paragraph_builder_group_from_text(content, None, None, None); let built_paragraphs = build_paragraphs_with_width(&mut paragraphs, paragraph_width); // 2. Max Width Calculation @@ -57,13 +59,13 @@ pub extern "C" fn get_text_dimensions() -> *mut u8 { match content.grow_type() { GrowType::AutoHeight => { let mut paragraph_height = - paragraph_builders_from_text(content, None, None, None); + paragraph_builder_group_from_text(content, None, None, None); height = auto_height(&mut paragraph_height, paragraph_width).ceil(); } GrowType::AutoWidth => { width = paragraph_width; let mut paragraph_height = - paragraph_builders_from_text(content, None, None, None); + paragraph_builder_group_from_text(content, None, None, None); height = auto_height(&mut paragraph_height, paragraph_width).ceil(); } GrowType::Fixed => {}