Skip to content

Commit d89e0e1

Browse files
committed
Calculate minimum and maximum content width
1 parent e1bf8e1 commit d89e0e1

File tree

5 files changed

+104
-0
lines changed

5 files changed

+104
-0
lines changed

parley/src/layout/data.rs

+50
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ pub(crate) struct LayoutData<B: Brush> {
195195
pub(crate) text_len: usize,
196196
pub(crate) width: f32,
197197
pub(crate) full_width: f32,
198+
pub(crate) min_content_width: f32,
199+
pub(crate) max_content_width: f32,
198200
pub(crate) height: f32,
199201
pub(crate) fonts: Vec<Font>,
200202
pub(crate) coords: Vec<i16>,
@@ -223,6 +225,8 @@ impl<B: Brush> Default for LayoutData<B> {
223225
text_len: 0,
224226
width: 0.,
225227
full_width: 0.,
228+
min_content_width: 0.,
229+
max_content_width: 0.,
226230
height: 0.,
227231
fonts: Vec::new(),
228232
coords: Vec::new(),
@@ -246,6 +250,8 @@ impl<B: Brush> LayoutData<B> {
246250
self.text_len = 0;
247251
self.width = 0.;
248252
self.full_width = 0.;
253+
self.min_content_width = 0.;
254+
self.max_content_width = 0.;
249255
self.height = 0.;
250256
self.fonts.clear();
251257
self.coords.clear();
@@ -444,6 +450,11 @@ impl<B: Brush> LayoutData<B> {
444450
}
445451

446452
pub(crate) fn finish(&mut self) {
453+
self.apply_spacing();
454+
self.calculate_content_widths();
455+
}
456+
457+
fn apply_spacing(&mut self) {
447458
for run in &self.runs {
448459
let word = run.word_spacing;
449460
let letter = run.letter_spacing;
@@ -470,4 +481,43 @@ impl<B: Brush> LayoutData<B> {
470481
}
471482
}
472483
}
484+
485+
fn calculate_content_widths(&mut self) {
486+
let mut max_width = 0.0;
487+
for item in &self.items {
488+
match item.kind {
489+
LayoutItemKind::TextRun => {
490+
let run = &self.runs[item.index];
491+
let mut min_width = 0.0;
492+
let mut trailing_whitespace = 0.0;
493+
for cluster in &self.clusters[run.cluster_range.clone()] {
494+
let boundary = cluster.info.boundary();
495+
if matches!(boundary, Boundary::Line | Boundary::Mandatory) {
496+
self.min_content_width =
497+
self.min_content_width.max(min_width - trailing_whitespace);
498+
min_width = 0.0;
499+
if boundary == Boundary::Mandatory {
500+
max_width = 0.0;
501+
}
502+
}
503+
min_width += cluster.advance;
504+
trailing_whitespace = if cluster.info.whitespace().is_space_or_nbsp() {
505+
cluster.advance
506+
} else {
507+
0.0
508+
};
509+
}
510+
self.min_content_width =
511+
self.min_content_width.max(min_width - trailing_whitespace);
512+
max_width += run.advance - trailing_whitespace;
513+
}
514+
LayoutItemKind::InlineBox => {
515+
let ibox = &self.inline_boxes[item.index];
516+
self.min_content_width = self.min_content_width.max(ibox.width);
517+
max_width += ibox.width;
518+
}
519+
}
520+
self.max_content_width = self.max_content_width.max(max_width);
521+
}
522+
}
473523
}

parley/src/layout/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,18 @@ impl<B: Brush> Layout<B> {
8181
self.data.full_width
8282
}
8383

84+
/// Returns the minimum content width of the layout. This is the width of the layout if _all_
85+
/// soft line-breaking opportunities are taken.
86+
pub fn min_content_width(&self) -> f32 {
87+
self.data.min_content_width
88+
}
89+
90+
/// Returns the maximum content width of the layout. This is the width of the layout if _no_
91+
/// soft line-breaking opportunities are taken.
92+
pub fn max_content_width(&self) -> f32 {
93+
self.data.max_content_width
94+
}
95+
8496
/// Returns the height of the layout.
8597
pub fn height(&self) -> f32 {
8698
self.data.height

parley/src/tests/test_basic.rs

+36
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,39 @@ fn trailing_whitespace() {
127127

128128
env.check_layout_snapshot(&layout);
129129
}
130+
131+
#[test]
132+
fn content_widths() {
133+
let mut env = testenv!();
134+
135+
let text = "Hello world!\nLonger line with a looooooooong word.";
136+
let mut builder = env.builder(text);
137+
138+
let mut layout = builder.build(text);
139+
140+
layout.break_all_lines(Some(layout.min_content_width()));
141+
layout.align(None, Alignment::Start, false);
142+
env.with_name("min").check_layout_snapshot(&layout);
143+
144+
layout.break_all_lines(Some(layout.max_content_width()));
145+
layout.align(None, Alignment::Start, false);
146+
env.with_name("max").check_layout_snapshot(&layout);
147+
}
148+
149+
#[test]
150+
fn inbox_content_width() {
151+
let mut env = testenv!();
152+
153+
let text = "Hello world!";
154+
let mut builder = env.builder(text);
155+
builder.push_inline_box(InlineBox {
156+
id: 0,
157+
index: 3,
158+
width: 100.0,
159+
height: 10.0,
160+
});
161+
let mut layout = builder.build(text);
162+
layout.break_all_lines(Some(layout.min_content_width()));
163+
layout.align(None, Alignment::Start, false);
164+
env.check_layout_snapshot(&layout);
165+
}
Loading
Loading

0 commit comments

Comments
 (0)