Skip to content

Commit 64bf726

Browse files
fix: empty lines use span metrics
1 parent f31b9d8 commit 64bf726

File tree

3 files changed

+79
-1
lines changed

3 files changed

+79
-1
lines changed

examples/rich-text/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fn set_buffer_text(buffer: &mut BorrowedWithFontSystem<'_, Buffer>) {
3232
attrs.clone().metrics(Metrics::relative(64.0, 1.2)),
3333
),
3434
(
35-
"Font size 8 ",
35+
"\n\nFont size 8 \n\n",
3636
attrs.clone().metrics(Metrics::relative(8.0, 1.2)),
3737
),
3838
(

src/buffer.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,11 @@ impl Buffer {
845845
if *attrs != attrs_list.defaults() {
846846
attrs_list.add_span(text_start..text_end, attrs);
847847
}
848+
} else if line_string.is_empty() && attrs.metrics_opt.is_some() {
849+
// reset the attrs list with the span's attrs so the line height
850+
// matches the span's font size rather than falling back to
851+
// the buffer default
852+
attrs_list = attrs_list.reset(attrs);
848853
}
849854

850855
// we know that at the end of a line,

tests/richtext_layout.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use cosmic_text::{Attrs, Buffer, FontSystem, Metrics, Shaping};
2+
3+
// Test for https://github.com/pop-os/cosmic-text/issues/364
4+
//
5+
// Empty lines at the start/end of a span should use that span's line height,
6+
// not the buffer's default line height.
7+
#[test]
8+
fn empty_lines_use_span_metrics() {
9+
let mut font_system = FontSystem::new();
10+
11+
let metrics = Metrics::new(32.0, 44.0);
12+
let mut buffer = Buffer::new(&mut font_system, metrics);
13+
let mut buffer = buffer.borrow_with(&mut font_system);
14+
15+
let attrs = Attrs::new();
16+
let small_attrs = attrs.clone().metrics(Metrics::relative(8.0, 1.2));
17+
18+
// The empty lines from \n\n at start and end should use 8.0 * 1.2 = 9.6 line height.
19+
// All newlines are inside the small_attrs span so the empty lines are clearly within it.
20+
buffer.set_rich_text(
21+
[
22+
("Before", attrs.clone()),
23+
("\n\n\nSmall\n\n", small_attrs),
24+
("After", attrs.clone()),
25+
],
26+
&attrs,
27+
Shaping::Advanced,
28+
None,
29+
);
30+
buffer.set_size(Some(500.0), Some(500.0));
31+
buffer.shape_until_scroll(false);
32+
33+
let line_heights: Vec<f32> = buffer.layout_runs().map(|run| run.line_height).collect();
34+
35+
// line_heights should be:
36+
// [0] "Before" -> 44.0 (buffer default)
37+
// [1] "" (empty) -> 9.6 (small span metrics: 8.0 * 1.2)
38+
// [2] "" (empty) -> 9.6 (small span metrics: 8.0 * 1.2)
39+
// [3] "Small" -> 9.6 (small span metrics from glyphs)
40+
// [4] "" (empty) -> 9.6 (small span metrics: 8.0 * 1.2)
41+
// [5] "After" -> 44.0 (buffer default)
42+
assert_eq!(
43+
line_heights.len(),
44+
6,
45+
"expected 6 layout runs, got {}",
46+
line_heights.len()
47+
);
48+
assert!(
49+
(line_heights[0] - 44.0).abs() < 0.1,
50+
"line 0 should use buffer default: {}",
51+
line_heights[0]
52+
);
53+
assert!(
54+
(line_heights[1] - 9.6).abs() < 0.1,
55+
"line 1 (empty) should use span metrics: {}",
56+
line_heights[1]
57+
);
58+
assert!(
59+
(line_heights[2] - 9.6).abs() < 0.1,
60+
"line 2 (empty) should use span metrics: {}",
61+
line_heights[2]
62+
);
63+
assert!(
64+
(line_heights[4] - 9.6).abs() < 0.1,
65+
"line 4 (empty) should use span metrics: {}",
66+
line_heights[4]
67+
);
68+
assert!(
69+
(line_heights[5] - 44.0).abs() < 0.1,
70+
"line 5 should use buffer default: {}",
71+
line_heights[5]
72+
);
73+
}

0 commit comments

Comments
 (0)