Skip to content

Commit 7c8983c

Browse files
authored
Account for inline boxes when collapsing after newlines (#280)
Followup (small bug fix) to #254 which didn't take inline boxes into account. That PR was checking whether "the last character is whitespace" without checking whether the last thing pushed into the layout was text. So if the sequence of items pushed to a layout was something like: - inline box - whitespace - inline box - whitespace - inline box - whitespace - inline box (an example which would be "status badges" in Github readme's which are typically images separated by whitespace characters) Then all but the first "whitespace" would get collapsed as it would be incorrectly detected as directly adjacent to the preceding whitespace (even though it shouldn't because there is an inline box in between). This PR fixes this issue by tracking the kind of the last item pushed. --------- Signed-off-by: Nico Burns <[email protected]>
1 parent 5f3988b commit 7c8983c

File tree

4 files changed

+65
-5
lines changed

4 files changed

+65
-5
lines changed

parley/src/builder.rs

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use alloc::string::String;
1313
use core::ops::RangeBounds;
1414

1515
use crate::inline_box::InlineBox;
16+
use crate::resolve::tree::ItemKind;
1617

1718
/// Builder for constructing a text layout with ranged attributes.
1819
pub struct RangedBuilder<'a, B: Brush> {
@@ -102,6 +103,9 @@ impl<B: Brush> TreeBuilder<'_, B> {
102103
pub fn push_inline_box(&mut self, mut inline_box: InlineBox) {
103104
self.lcx.tree_style_builder.push_uncommitted_text(false);
104105
self.lcx.tree_style_builder.set_is_span_first(false);
106+
self.lcx
107+
.tree_style_builder
108+
.set_last_item_kind(ItemKind::InlineBox);
105109
// TODO: arrange type better here to factor out the index
106110
inline_box.index = self.lcx.tree_style_builder.current_text_len();
107111
self.lcx.inline_boxes.push(inline_box);

parley/src/resolve/tree.rs

+20-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ struct StyleTreeNode<B: Brush> {
1515
style: ResolvedStyle<B>,
1616
}
1717

18+
#[derive(Clone, Copy, PartialEq)]
19+
pub(crate) enum ItemKind {
20+
None,
21+
InlineBox,
22+
TextRun,
23+
}
24+
1825
/// Builder for constructing a tree of styles
1926
#[derive(Clone)]
2027
pub(crate) struct TreeStyleBuilder<B: Brush> {
@@ -25,6 +32,7 @@ pub(crate) struct TreeStyleBuilder<B: Brush> {
2532
uncommitted_text: String,
2633
current_span: usize,
2734
is_span_first: bool,
35+
last_item_kind: ItemKind,
2836
}
2937

3038
impl<B: Brush> TreeStyleBuilder<B> {
@@ -43,6 +51,7 @@ impl<B: Brush> Default for TreeStyleBuilder<B> {
4351
uncommitted_text: String::new(),
4452
current_span: usize::MAX,
4553
is_span_first: false,
54+
last_item_kind: ItemKind::None,
4655
}
4756
}
4857
}
@@ -72,18 +81,23 @@ impl<B: Brush> TreeStyleBuilder<B> {
7281
self.is_span_first = is_span_first;
7382
}
7483

84+
pub(crate) fn set_last_item_kind(&mut self, item_kind: ItemKind) {
85+
self.last_item_kind = item_kind;
86+
}
87+
7588
pub(crate) fn push_uncommitted_text(&mut self, is_span_last: bool) {
7689
let span_text: Cow<'_, str> = match self.white_space_collapse {
7790
WhiteSpaceCollapse::Preserve => Cow::from(&self.uncommitted_text),
7891
WhiteSpaceCollapse::Collapse => {
7992
let mut span_text = self.uncommitted_text.as_str();
8093

8194
if self.is_span_first
82-
|| self
83-
.text
84-
.chars()
85-
.last()
86-
.is_some_and(|c| c.is_ascii_whitespace())
95+
|| (self.last_item_kind == ItemKind::TextRun
96+
&& self
97+
.text
98+
.chars()
99+
.last()
100+
.is_some_and(|c| c.is_ascii_whitespace()))
87101
{
88102
span_text = span_text.trim_start();
89103
}
@@ -129,6 +143,7 @@ impl<B: Brush> TreeStyleBuilder<B> {
129143
self.text.push_str(span_text);
130144
self.uncommitted_text.clear();
131145
self.is_span_first = false;
146+
self.last_item_kind = ItemKind::TextRun;
132147
}
133148

134149
pub(crate) fn current_text_len(&self) -> usize {

parley/src/tests/test_basic.rs

+38
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,44 @@ fn full_width_inbox() {
9696
}
9797
}
9898

99+
#[test]
100+
fn inbox_separated_by_whitespace() {
101+
let mut env = testenv!();
102+
103+
let mut builder = env.tree_builder();
104+
builder.push_inline_box(InlineBox {
105+
id: 0,
106+
index: 0,
107+
width: 10.,
108+
height: 10.0,
109+
});
110+
builder.push_text(" ");
111+
builder.push_inline_box(InlineBox {
112+
id: 1,
113+
index: 1,
114+
width: 10.0,
115+
height: 10.0,
116+
});
117+
builder.push_text(" ");
118+
builder.push_inline_box(InlineBox {
119+
id: 2,
120+
index: 2,
121+
width: 10.0,
122+
height: 10.0,
123+
});
124+
builder.push_text(" ");
125+
builder.push_inline_box(InlineBox {
126+
id: 3,
127+
index: 3,
128+
width: 10.0,
129+
height: 10.0,
130+
});
131+
let (mut layout, _text) = builder.build();
132+
layout.break_all_lines(Some(100.));
133+
layout.align(None, Alignment::Start, AlignmentOptions::default());
134+
env.check_layout_snapshot(&layout);
135+
}
136+
99137
#[test]
100138
fn trailing_whitespace() {
101139
let mut env = testenv!();
Loading

0 commit comments

Comments
 (0)