Merge pull request #7748 from penpot/elenatorro-12586-fix-offset-y-on-new-lines

🐛 Fix new lines spacing between paragraphs
This commit is contained in:
Alejandro Alonso
2025-11-18 09:23:22 +01:00
committed by GitHub
6 changed files with 234 additions and 20 deletions

File diff suppressed because one or more lines are too long

View File

@@ -347,6 +347,23 @@ test("Renders a file with texts with with text spans of different sizes", async
await expect(workspace.canvas).toHaveScreenshot();
});
test("Renders a file with texts with paragraphs and breaking lines", async ({
page,
}) => {
const workspace = new WasmWorkspacePage(page);
await workspace.setupEmptyFile();
await workspace.mockGetFile(
"render-wasm/get-file-text-paragraph-new-lines.json",
);
await workspace.goToWorkspace({
id: "a5f238bd-dd8a-8164-8007-1bc3481eaf05",
pageId: "a5f238bd-dd8a-8164-8007-1bc3481eaf06",
});
await workspace.waitForFirstRender();
await expect(workspace.canvas).toHaveScreenshot();
});
// TODO: enable this test once we use the wasm renderer in the new editor
test.skip("Renders a file with texts with tabs", async ({ page }) => {
const workspace = new WasmWorkspacePage(page);

View File

@@ -119,13 +119,6 @@
[paragraph]
(some #(not= "" (:text % "")) (:children paragraph)))
(defn should-filter-empty-paragraph?
[paragraphs index]
(and (not (has-content? (nth paragraphs index)))
(< index (count paragraphs))
(some has-content? (drop (inc index) paragraphs))
(every? #(not (has-content? %)) (take (inc index) paragraphs))))
(defn create-inline
[inline paragraph]
(create-element
@@ -150,7 +143,6 @@
paragraphs (get-in root [:children 0 :children])
filtered-paragraphs (->> paragraphs
(map-indexed vector)
(remove (fn [[index _]] (should-filter-empty-paragraph? paragraphs index)))
(mapv second))]
(create-element
"div"

View File

@@ -217,6 +217,7 @@ fn draw_text(
let layer_rec = SaveLayerRec::default();
canvas.save_layer(&layer_rec);
let mut normalized_line_height = text_content.normalized_line_height();
for paragraph_builder_group in paragraph_builder_groups {
let mut group_offset_y = global_offset_y;
@@ -228,8 +229,14 @@ fn draw_text(
let xy = (shape.selrect().x(), shape.selrect().y() + group_offset_y);
paragraph.paint(canvas, xy);
let line_metrics = paragraph.get_line_metrics();
if paragraph_index == group_len - 1 {
group_offset_y += paragraph.ideographic_baseline();
if line_metrics.is_empty() {
group_offset_y += normalized_line_height;
} else {
normalized_line_height = paragraph.ideographic_baseline();
group_offset_y += paragraph.ideographic_baseline() * line_metrics.len() as f32;
}
}
for line_metrics in paragraph.get_line_metrics().iter() {

View File

@@ -38,6 +38,7 @@ pub struct TextContentSize {
pub width: f32,
pub height: f32,
pub max_width: f32,
pub normalized_line_height: f32,
}
const DEFAULT_TEXT_CONTENT_SIZE: f32 = 0.01;
@@ -48,14 +49,7 @@ impl TextContentSize {
width: DEFAULT_TEXT_CONTENT_SIZE,
height: DEFAULT_TEXT_CONTENT_SIZE,
max_width: DEFAULT_TEXT_CONTENT_SIZE,
}
}
pub fn new(width: f32, height: f32, max_width: f32) -> Self {
Self {
width,
height,
max_width,
normalized_line_height: 0.0,
}
}
@@ -64,6 +58,21 @@ impl TextContentSize {
width,
height,
max_width: DEFAULT_TEXT_CONTENT_SIZE,
normalized_line_height: 0.0,
}
}
pub fn new_with_normalized_line_height(
width: f32,
height: f32,
max_width: f32,
normalized_line_height: f32,
) -> Self {
Self {
width,
height,
max_width,
normalized_line_height,
}
}
@@ -93,6 +102,9 @@ impl TextContentSize {
} else {
self.height = default_height;
}
if f32::is_finite(size.normalized_line_height) {
self.normalized_line_height = size.normalized_line_height;
}
}
}
@@ -232,6 +244,10 @@ impl TextContent {
self.size.width
}
pub fn normalized_line_height(&self) -> f32 {
self.size.normalized_line_height
}
pub fn grow_type(&self) -> GrowType {
self.grow_type
}
@@ -400,9 +416,33 @@ impl TextContent {
paragraphs
}
/// Calculate the normalized line height from paragraph builders
fn calculate_normalized_line_height(
&self,
paragraph_builders: &mut [ParagraphBuilderGroup],
width: f32,
) -> f32 {
let mut normalized_line_height = 0.0;
for paragraph_builder_group in paragraph_builders.iter_mut() {
for paragraph_builder in paragraph_builder_group.iter_mut() {
let mut paragraph = paragraph_builder.build();
paragraph.layout(width);
let baseline = paragraph.ideographic_baseline();
if baseline > normalized_line_height {
normalized_line_height = baseline;
}
}
}
normalized_line_height
}
/// Performs an Auto Width text layout.
fn text_layout_auto_width(&self) -> TextContentLayoutResult {
let mut paragraph_builders = self.paragraph_builder_group_from_text(None);
let normalized_line_height =
self.calculate_normalized_line_height(&mut paragraph_builders, f32::MAX);
let paragraphs =
self.build_paragraphs_from_paragraph_builders(&mut paragraph_builders, f32::MAX);
@@ -417,7 +457,12 @@ impl TextContent {
)
});
let size = TextContentSize::new(width.ceil(), height.ceil(), width.ceil());
let size = TextContentSize::new_with_normalized_line_height(
width.ceil(),
height.ceil(),
width.ceil(),
normalized_line_height,
);
TextContentLayoutResult(paragraph_builders, paragraphs, size)
}
@@ -426,6 +471,10 @@ impl TextContent {
fn text_layout_auto_height(&self) -> TextContentLayoutResult {
let width = self.width();
let mut paragraph_builders = self.paragraph_builder_group_from_text(None);
let normalized_line_height =
self.calculate_normalized_line_height(&mut paragraph_builders, width);
let paragraphs =
self.build_paragraphs_from_paragraph_builders(&mut paragraph_builders, width);
let height = paragraphs
@@ -434,7 +483,12 @@ impl TextContent {
.fold(0.0, |auto_height, paragraph| {
auto_height + paragraph.height()
});
let size = TextContentSize::new_with_size(width.ceil(), height.ceil());
let size = TextContentSize::new_with_normalized_line_height(
width,
height.ceil(),
DEFAULT_TEXT_CONTENT_SIZE,
normalized_line_height,
);
TextContentLayoutResult(paragraph_builders, paragraphs, size)
}
@@ -442,6 +496,10 @@ impl TextContent {
fn text_layout_fixed(&self) -> TextContentLayoutResult {
let width = self.width();
let mut paragraph_builders = self.paragraph_builder_group_from_text(None);
let normalized_line_height =
self.calculate_normalized_line_height(&mut paragraph_builders, width);
let paragraphs =
self.build_paragraphs_from_paragraph_builders(&mut paragraph_builders, width);
let paragraph_height = paragraphs
@@ -451,7 +509,12 @@ impl TextContent {
auto_height + paragraph.height()
});
let size = TextContentSize::new_with_size(width.ceil(), paragraph_height.ceil());
let size = TextContentSize::new_with_normalized_line_height(
width,
paragraph_height.ceil(),
DEFAULT_TEXT_CONTENT_SIZE,
normalized_line_height,
);
TextContentLayoutResult(paragraph_builders, paragraphs, size)
}