mirror of
https://github.com/penpot/penpot.git
synced 2026-05-06 00:28:43 +00:00
⚡ Reduce per-render text layout work
This commit is contained in:
parent
4a0cd0b7ce
commit
e950ec56eb
@ -26,7 +26,7 @@ use crate::error::{Error, Result};
|
||||
use crate::performance;
|
||||
use crate::shapes::{
|
||||
all_with_ancestors, radius_to_sigma, Blur, BlurType, Corners, Fill, Shadow, Shape, SolidColor,
|
||||
Stroke, StrokeKind, Type,
|
||||
Stroke, StrokeKind, TextContent, Type,
|
||||
};
|
||||
use crate::state::{ShapesPoolMutRef, ShapesPoolRef};
|
||||
use crate::tiles::{self, PendingTiles, TileRect};
|
||||
@ -1229,12 +1229,23 @@ impl RenderState {
|
||||
}
|
||||
}
|
||||
|
||||
Type::Text(text_content) => {
|
||||
Type::Text(stored_text_content) => {
|
||||
self.surfaces.apply_mut(surface_ids, |s| {
|
||||
s.canvas().concat(&matrix);
|
||||
});
|
||||
|
||||
let text_content = text_content.new_bounds(shape.selrect());
|
||||
// Skip the paragraph-cloning `new_bounds` when shape size is unchanged.
|
||||
let selrect = shape.selrect();
|
||||
let stored_bounds = stored_text_content.bounds();
|
||||
let bounds_match = (stored_bounds.width() - selrect.width()).abs() < 0.01
|
||||
&& (stored_bounds.height() - selrect.height()).abs() < 0.01;
|
||||
let rebound_text_content = if bounds_match {
|
||||
None
|
||||
} else {
|
||||
Some(stored_text_content.new_bounds(selrect))
|
||||
};
|
||||
let text_content: &TextContent =
|
||||
rebound_text_content.as_ref().unwrap_or(stored_text_content);
|
||||
let count_inner_strokes = shape.count_visible_inner_strokes();
|
||||
// Erode the main text fill by 1px when there are inner strokes, to avoid a visible seam at the glyph edge.
|
||||
let text_fill_inset = (count_inner_strokes > 0).then(|| 1.0 / self.get_scale());
|
||||
@ -1248,7 +1259,7 @@ impl RenderState {
|
||||
.rev()
|
||||
.map(|stroke| {
|
||||
text::stroke_paragraph_builder_group_from_text(
|
||||
&text_content,
|
||||
text_content,
|
||||
stroke,
|
||||
&shape.selrect(),
|
||||
None,
|
||||
@ -1324,7 +1335,7 @@ impl RenderState {
|
||||
.rev()
|
||||
.map(|stroke| {
|
||||
text::stroke_paragraph_builder_group_from_text(
|
||||
&text_content,
|
||||
text_content,
|
||||
stroke,
|
||||
&shape.selrect(),
|
||||
Some(true),
|
||||
@ -1357,7 +1368,7 @@ impl RenderState {
|
||||
&parent_shadows,
|
||||
&blur_filter,
|
||||
&stroke_kinds,
|
||||
&text_content,
|
||||
text_content,
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
@ -1401,7 +1412,7 @@ impl RenderState {
|
||||
&drop_shadows,
|
||||
&blur_filter,
|
||||
&stroke_kinds,
|
||||
&text_content,
|
||||
text_content,
|
||||
)?;
|
||||
|
||||
// 4. Stroke fills
|
||||
@ -1453,7 +1464,7 @@ impl RenderState {
|
||||
&inner_shadows,
|
||||
&blur_filter,
|
||||
&stroke_kinds,
|
||||
&text_content,
|
||||
text_content,
|
||||
)?;
|
||||
|
||||
// 6. Fill Inner shadows
|
||||
|
||||
@ -1424,11 +1424,14 @@ pub fn calculate_text_layout_data(
|
||||
let mut previous_line_height = text_content.normalized_line_height();
|
||||
let text_paragraphs = text_content.paragraphs();
|
||||
|
||||
// 1. Calculate paragraph heights
|
||||
// 1. Build + layout each paragraph once, recording heights as we go.
|
||||
let mut paragraph_heights: Vec<f32> = Vec::new();
|
||||
let mut built_groups: Vec<Vec<skia::textlayout::Paragraph>> =
|
||||
Vec::with_capacity(paragraph_builder_groups.len());
|
||||
for paragraph_builder_group in paragraph_builder_groups.iter_mut() {
|
||||
let group_len = paragraph_builder_group.len();
|
||||
let mut paragraph_offset_y = previous_line_height;
|
||||
let mut group_paragraphs: Vec<skia::textlayout::Paragraph> = Vec::with_capacity(group_len);
|
||||
for (builder_index, paragraph_builder) in paragraph_builder_group.iter_mut().enumerate() {
|
||||
let mut skia_paragraph = paragraph_builder.build();
|
||||
skia_paragraph.layout(text_width);
|
||||
@ -1442,11 +1445,13 @@ pub fn calculate_text_layout_data(
|
||||
if builder_index == 0 {
|
||||
paragraph_heights.push(skia_paragraph.height());
|
||||
}
|
||||
group_paragraphs.push(skia_paragraph);
|
||||
}
|
||||
previous_line_height = paragraph_offset_y;
|
||||
built_groups.push(group_paragraphs);
|
||||
}
|
||||
|
||||
// 2. Calculate vertical offset and build paragraphs with positions
|
||||
// 2. Position each built paragraph using the heights from step 1.
|
||||
let total_text_height: f32 = paragraph_heights.iter().sum();
|
||||
let vertical_offset = match shape.vertical_align() {
|
||||
VerticalAlign::Center => (selrect_height - total_text_height) / 2.0,
|
||||
@ -1455,12 +1460,9 @@ pub fn calculate_text_layout_data(
|
||||
};
|
||||
let mut paragraph_layouts: Vec<ParagraphLayout> = Vec::new();
|
||||
let mut y_accum = base_y + vertical_offset;
|
||||
for (i, paragraph_builder_group) in paragraph_builder_groups.iter_mut().enumerate() {
|
||||
for (i, group_paragraphs) in built_groups.into_iter().enumerate() {
|
||||
// For each paragraph in the group (e.g., fill, stroke, etc.)
|
||||
for paragraph_builder in paragraph_builder_group.iter_mut() {
|
||||
let mut skia_paragraph = paragraph_builder.build();
|
||||
skia_paragraph.layout(text_width);
|
||||
|
||||
for skia_paragraph in group_paragraphs.into_iter() {
|
||||
let spans = if let Some(text_para) = text_paragraphs.get(i) {
|
||||
text_para.children().to_vec()
|
||||
} else {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user