🔧 Fix text align selrect and update regression tests

This commit is contained in:
Elena Torro 2025-10-22 15:02:54 +02:00
parent 140290cd60
commit a30315c91c
16 changed files with 94 additions and 5633 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 KiB

After

Width:  |  Height:  |  Size: 322 KiB

View File

@ -255,8 +255,8 @@ test("Renders a file with different text leaves decoration", async ({
); );
await workspace.goToWorkspace({ await workspace.goToWorkspace({
id: "15b74473-2908-8094-8006-bdb4fbd2c6a3", id: "15b74473-2908-8094-8006-bda76b230c6a",
pageId: "15b74473-2908-8094-8006-bdb4fbd2c6a4", pageId: "b4cb802d-4245-807d-8006-b4a4b90b79cd",
}); });
await workspace.waitForFirstRender(); await workspace.waitForFirstRender();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 KiB

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 521 KiB

After

Width:  |  Height:  |  Size: 523 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 325 KiB

After

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 124 KiB

View File

@ -616,6 +616,7 @@ impl RenderState {
text_content.paragraph_builder_group_from_text(Some(true)); text_content.paragraph_builder_group_from_text(Some(true));
let mut stroke_paragraphs_list = shape let mut stroke_paragraphs_list = shape
.visible_strokes() .visible_strokes()
.rev()
.map(|stroke| { .map(|stroke| {
text::stroke_paragraph_builder_group_from_text( text::stroke_paragraph_builder_group_from_text(
&text_content, &text_content,
@ -629,6 +630,7 @@ impl RenderState {
let mut stroke_paragraphs_with_shadows_list = shape let mut stroke_paragraphs_with_shadows_list = shape
.visible_strokes() .visible_strokes()
.rev()
.map(|stroke| { .map(|stroke| {
text::stroke_paragraph_builder_group_from_text( text::stroke_paragraph_builder_group_from_text(
&text_content, &text_content,

View File

@ -200,47 +200,45 @@ fn draw_text(
shape: &Shape, shape: &Shape,
paragraph_builder_groups: &mut [Vec<ParagraphBuilder>], paragraph_builder_groups: &mut [Vec<ParagraphBuilder>],
) { ) {
let container_height = if let crate::shapes::Type::Text(text_content) = &shape.shape_type { let text_content = shape.get_text_content();
text_content.size.height // FIXME: this does not always return the height we need
} else { // let text_height = text_content.size.height;
shape.selrect().height() let text_width = text_content.get_width();
}; let text_height = text_content.get_height(text_width);
let selrect_height = shape.selrect().height();
let paragraph_width = shape.selrect().width();
let total_content_height =
calculate_all_paragraphs_height(paragraph_builder_groups, paragraph_width);
let mut global_offset_y = match shape.vertical_align() { let mut global_offset_y = match shape.vertical_align() {
VerticalAlign::Center => (container_height - total_content_height) / 2.0, VerticalAlign::Center => (selrect_height - text_height) / 2.0,
VerticalAlign::Bottom => container_height - total_content_height, VerticalAlign::Bottom => selrect_height - text_height,
_ => 0.0, _ => 0.0,
}; };
let layer_rec = SaveLayerRec::default(); let layer_rec = SaveLayerRec::default();
canvas.save_layer(&layer_rec); canvas.save_layer(&layer_rec);
for paragraph_builder_group in paragraph_builder_groups { for paragraph_builder_group in paragraph_builder_groups.iter_mut() {
let mut group_offset_y = global_offset_y; let mut group_offset_y = global_offset_y;
let total_paragraphs = paragraph_builder_group.len();
for (paragraph_index, paragraph_builder) in paragraph_builder_group.iter_mut().enumerate() { for (paragraph_index, paragraph_builder) in paragraph_builder_group.iter_mut().enumerate() {
let mut paragraph = paragraph_builder.build(); let mut paragraph = paragraph_builder.build();
paragraph.layout(paragraph_width); paragraph.layout(text_width);
let _paragraph_height = paragraph.height(); let _paragraph_height = paragraph.height();
// FIXME: I've kept the _paragraph_height variable to have // FIXME: I've kept the _paragraph_height variable to have
// a reminder in the future to keep digging why the ideographic_baseline // a reminder in the future to keep digging why the ideographic_baseline
// works so well and not the paragraph_height. I think we should test // works so well and not the paragraph_height. I think we should test
// this more. // this more.
if paragraph_index == 0 { let xy = (shape.selrect().x(), shape.selrect().y() + group_offset_y);
paragraph.paint(canvas, xy);
if paragraph_index == total_paragraphs - 1 {
group_offset_y += paragraph.ideographic_baseline(); group_offset_y += paragraph.ideographic_baseline();
} }
let xy = (shape.selrect().x(), shape.selrect().y() + global_offset_y);
paragraph.paint(canvas, xy);
for line_metrics in paragraph.get_line_metrics().iter() { for line_metrics in paragraph.get_line_metrics().iter() {
render_text_decoration(canvas, &paragraph, paragraph_builder, line_metrics, xy); render_text_decoration(canvas, &paragraph, paragraph_builder, line_metrics, xy);
} }
} }
global_offset_y += group_offset_y; global_offset_y = group_offset_y;
} }
} }
@ -415,6 +413,7 @@ fn render_text_decoration(
} }
} }
#[allow(dead_code)]
fn calculate_total_paragraphs_height(paragraphs: &mut [ParagraphBuilder], width: f32) -> f32 { fn calculate_total_paragraphs_height(paragraphs: &mut [ParagraphBuilder], width: f32) -> f32 {
paragraphs paragraphs
.iter_mut() .iter_mut()
@ -426,6 +425,7 @@ fn calculate_total_paragraphs_height(paragraphs: &mut [ParagraphBuilder], width:
.sum() .sum()
} }
#[allow(dead_code)]
fn calculate_all_paragraphs_height( fn calculate_all_paragraphs_height(
paragraph_groups: &mut [Vec<ParagraphBuilder>], paragraph_groups: &mut [Vec<ParagraphBuilder>],
width: f32, width: f32,

View File

@ -684,6 +684,13 @@ impl Shape {
.get_or_init(|| self.calculate_extrect(shapes_pool, modifiers)) .get_or_init(|| self.calculate_extrect(shapes_pool, modifiers))
} }
pub fn get_text_content(&self) -> &TextContent {
match &self.shape_type {
crate::shapes::Type::Text(text_content) => text_content,
_ => panic!("Shape is not of type Text"),
}
}
/// Calculates the bounding rectangle for a selrect shape's shadow, taking into account /// Calculates the bounding rectangle for a selrect shape's shadow, taking into account
/// stroke widths and shadow properties. /// stroke widths and shadow properties.
/// ///

View File

@ -16,7 +16,7 @@ use std::collections::HashSet;
use super::FontFamily; use super::FontFamily;
use crate::math::Point; use crate::math::Point;
use crate::shapes::{self, merge_fills, Shape}; use crate::shapes::{self, merge_fills, Shape, VerticalAlign};
use crate::utils::{get_fallback_fonts, get_font_collection}; use crate::utils::{get_fallback_fonts, get_font_collection};
use crate::Uuid; use crate::Uuid;
@ -239,20 +239,32 @@ impl TextContent {
} }
pub fn calculate_bounds(&self, shape: &Shape) -> Bounds { pub fn calculate_bounds(&self, shape: &Shape) -> Bounds {
let (x, y, transform, center) = ( let (x, mut y, transform, center) = (
shape.selrect.x(), shape.selrect.x(),
shape.selrect.y(), shape.selrect.y(),
&shape.transform, &shape.transform,
&shape.center(), &shape.center(),
); );
let width = shape.selrect.width(); let width = if self.grow_type() == GrowType::AutoWidth {
self.size.width
} else {
shape.selrect().width()
};
let height = if self.size.width.round() != width.round() { let height = if self.size.width.round() != width.round() {
self.get_height(width) self.get_height(width)
} else { } else {
self.size.height self.size.height
}; };
let offset_y = match shape.vertical_align() {
VerticalAlign::Center => (shape.selrect().height() - height) / 2.0,
VerticalAlign::Bottom => shape.selrect().height() - height,
_ => 0.0,
};
y += offset_y;
let text_rect = Rect::from_xywh(x, y, width, height); let text_rect = Rect::from_xywh(x, y, width, height);
let mut bounds = Bounds::new( let mut bounds = Bounds::new(
Point::new(text_rect.x(), text_rect.y()), Point::new(text_rect.x(), text_rect.y()),
@ -435,7 +447,15 @@ impl TextContent {
TextContentLayoutResult(paragraph_builders, paragraphs, size) TextContentLayoutResult(paragraph_builders, paragraphs, size)
} }
fn get_height(&self, width: f32) -> f32 { pub fn get_width(&self) -> f32 {
if self.grow_type() == GrowType::AutoWidth {
self.size.width
} else {
self.bounds.width()
}
}
pub fn get_height(&self, width: f32) -> f32 {
let mut paragraph_builders = self.paragraph_builder_group_from_text(None); let mut paragraph_builders = self.paragraph_builder_group_from_text(None);
let paragraphs = let paragraphs =
self.build_paragraphs_from_paragraph_builders(&mut paragraph_builders, width); self.build_paragraphs_from_paragraph_builders(&mut paragraph_builders, width);