Skip to content

Commit

Permalink
Allow layout to be calculated without specifying width
Browse files Browse the repository at this point in the history
  • Loading branch information
jackpot51 committed Jun 11, 2024
1 parent a3a6262 commit 7ea6a0d
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 32 deletions.
4 changes: 2 additions & 2 deletions src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ impl Buffer {
&mut self.scratch,
font_system,
self.metrics.font_size,
self.width,
Some(self.width),
self.wrap,
self.monospace_width,
self.tab_width,
Expand Down Expand Up @@ -528,7 +528,7 @@ impl Buffer {
&mut self.scratch,
font_system,
self.metrics.font_size,
self.width,
Some(self.width),
self.wrap,
self.monospace_width,
self.tab_width,
Expand Down
8 changes: 4 additions & 4 deletions src/buffer_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ impl BufferLine {
&mut self,
font_system: &mut FontSystem,
font_size: f32,
width: f32,
width_opt: Option<f32>,
wrap: Wrap,
match_mono_width: Option<f32>,
tab_width: u16,
Expand All @@ -226,7 +226,7 @@ impl BufferLine {
&mut ShapeBuffer::default(),
font_system,
font_size,
width,
width_opt,
wrap,
match_mono_width,
tab_width,
Expand All @@ -239,7 +239,7 @@ impl BufferLine {
scratch: &mut ShapeBuffer,
font_system: &mut FontSystem,
font_size: f32,
width: f32,
width_opt: Option<f32>,
wrap: Wrap,
match_mono_width: Option<f32>,
tab_width: u16,
Expand All @@ -251,7 +251,7 @@ impl BufferLine {
shape.layout_to_buffer(
scratch,
font_size,
width,
width_opt,
wrap,
align,
&mut layout,
Expand Down
37 changes: 24 additions & 13 deletions src/shape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,7 @@ impl ShapeLine {
pub fn layout(
&self,
font_size: f32,
line_width: f32,
width_opt: Option<f32>,
wrap: Wrap,
align: Option<Align>,
match_mono_width: Option<f32>,
Expand All @@ -1001,7 +1001,7 @@ impl ShapeLine {
self.layout_to_buffer(
&mut ShapeBuffer::default(),
font_size,
line_width,
width_opt,
wrap,
align,
&mut lines,
Expand All @@ -1014,7 +1014,7 @@ impl ShapeLine {
&self,
scratch: &mut ShapeBuffer,
font_size: f32,
line_width: f32,
width_opt: Option<f32>,
wrap: Wrap,
align: Option<Align>,
layout_lines: &mut Vec<LayoutLine>,
Expand Down Expand Up @@ -1089,11 +1089,11 @@ impl ShapeLine {
// relayouts with that width as the `line_width` will produce the same
// wrapping results.
if current_visual_line.w + (word_range_width + word_width)
<= line_width
<= width_opt.unwrap_or(f32::INFINITY)
// Include one blank word over the width limit since it won't be
// counted in the final width
|| (word.blank
&& (current_visual_line.w + word_range_width) <= line_width)
&& (current_visual_line.w + word_range_width) <= width_opt.unwrap_or(f32::INFINITY))
{
// fits
if word.blank {
Expand All @@ -1104,12 +1104,12 @@ impl ShapeLine {
continue;
} else if wrap == Wrap::Glyph
// Make sure that the word is able to fit on it's own line, if not, fall back to Glyph wrapping.
|| (wrap == Wrap::WordOrGlyph && word_width > line_width)
|| (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
{
// Commit the current line so that the word starts on the next line.
if word_range_width > 0.
&& wrap == Wrap::WordOrGlyph
&& word_width > line_width
&& word_width > width_opt.unwrap_or(f32::INFINITY)
{
add_to_visual_line(
&mut current_visual_line,
Expand All @@ -1132,7 +1132,7 @@ impl ShapeLine {
for (glyph_i, glyph) in word.glyphs.iter().enumerate().rev() {
let glyph_width = glyph.width(font_size);
if current_visual_line.w + (word_range_width + glyph_width)
<= line_width
<= width_opt.unwrap_or(f32::INFINITY)
{
word_range_width += glyph_width;
continue;
Expand Down Expand Up @@ -1213,11 +1213,11 @@ impl ShapeLine {
for (i, word) in span.words.iter().enumerate() {
let word_width = word.width(font_size);
if current_visual_line.w + (word_range_width + word_width)
<= line_width
<= width_opt.unwrap_or(f32::INFINITY)
// Include one blank word over the width limit since it won't be
// counted in the final width.
|| (word.blank
&& (current_visual_line.w + word_range_width) <= line_width)
&& (current_visual_line.w + word_range_width) <= width_opt.unwrap_or(f32::INFINITY))
{
// fits
if word.blank {
Expand All @@ -1228,12 +1228,12 @@ impl ShapeLine {
continue;
} else if wrap == Wrap::Glyph
// Make sure that the word is able to fit on it's own line, if not, fall back to Glyph wrapping.
|| (wrap == Wrap::WordOrGlyph && word_width > line_width)
|| (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
{
// Commit the current line so that the word starts on the next line.
if word_range_width > 0.
&& wrap == Wrap::WordOrGlyph
&& word_width > line_width
&& word_width > width_opt.unwrap_or(f32::INFINITY)
{
add_to_visual_line(
&mut current_visual_line,
Expand All @@ -1256,7 +1256,7 @@ impl ShapeLine {
for (glyph_i, glyph) in word.glyphs.iter().enumerate() {
let glyph_width = glyph.width(font_size);
if current_visual_line.w + (word_range_width + glyph_width)
<= line_width
<= width_opt.unwrap_or(f32::INFINITY)
{
word_range_width += glyph_width;
continue;
Expand Down Expand Up @@ -1346,6 +1346,17 @@ impl ShapeLine {
}
});

let line_width = match width_opt {
Some(width) => width,
None => {
let mut width: f32 = 0.0;
for visual_line in visual_lines.iter() {
width = width.max(visual_line.w);
}
width
}
};

let start_x = if self.rtl { line_width } else { 0.0 };

let number_of_visual_lines = visual_lines.len();
Expand Down
49 changes: 36 additions & 13 deletions tests/wrap_stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@ fn stable_wrap() {
let font = std::fs::read("fonts/FiraMono-Medium.ttf").unwrap();
font_system.db_mut().load_font_data(font);

let mut check_wrap = |text: &_, wrap, start_width| {
let mut check_wrap = |text: &_, wrap, align_opt, start_width_opt| {
let line = ShapeLine::new(&mut font_system, text, &attrs, Shaping::Advanced, 8);

let layout_unbounded = line.layout(font_size, start_width, wrap, Some(Align::Left), None);
let layout_unbounded = line.layout(font_size, start_width_opt, wrap, align_opt, None);
let max_width = layout_unbounded.iter().map(|l| l.w).fold(0.0, f32::max);
let new_limit = f32::min(start_width, max_width);
let new_limit = match start_width_opt {
Some(start_width) => f32::min(start_width, max_width),
None => max_width,
};

let layout_bounded = line.layout(font_size, new_limit, wrap, Some(Align::Left), None);
let layout_bounded = line.layout(font_size, Some(new_limit), wrap, align_opt, None);
let bounded_max_width = layout_bounded.iter().map(|l| l.w).fold(0.0, f32::max);

// For debugging:
Expand All @@ -37,10 +40,13 @@ fn stable_wrap() {
assert_eq!(
(max_width, layout_unbounded.len()),
(bounded_max_width, layout_bounded.len()),
"Wrap \"{wrap:?}\" with text: \"{text}\"",
"Wrap \"{wrap:?}\" and align \"{align_opt:?}\" with text: \"{text}\"",
);
for (u, b) in layout_unbounded[1..].iter().zip(layout_bounded[1..].iter()) {
assert_eq!(u.w, b.w, "Wrap {wrap:?} with text: \"{text}\"",);
assert_eq!(
u.w, b.w,
"Wrap {wrap:?} and align \"{align_opt:?}\" with text: \"{text}\"",
);
}
};

Expand All @@ -59,13 +65,30 @@ fn stable_wrap() {
.chain(BidiParagraphs::new(&hello_sample));

for text in cases {
for wrap in [Wrap::Word, Wrap::Glyph] {
for start_width in [f32::MAX, 80.0, 198.2132, 20.0, 4.0, 300.0] {
check_wrap(text, wrap, start_width);
let with_spaces = format!("{text} ");
check_wrap(&with_spaces, wrap, start_width);
let with_spaces_2 = format!("{text} ");
check_wrap(&with_spaces_2, wrap, start_width);
for wrap in [Wrap::None, Wrap::Glyph, Wrap::Word, Wrap::WordOrGlyph] {
for align_opt in [
None,
Some(Align::Left),
Some(Align::Right),
Some(Align::Center),
//TODO: Align::Justified
Some(Align::End),
] {
for start_width_opt in [
None,
Some(f32::MAX),
Some(80.0),
Some(198.2132),
Some(20.0),
Some(4.0),
Some(300.0),
] {
check_wrap(text, wrap, align_opt, start_width_opt);
let with_spaces = format!("{text} ");
check_wrap(&with_spaces, wrap, align_opt, start_width_opt);
let with_spaces_2 = format!("{text} ");
check_wrap(&with_spaces_2, wrap, align_opt, start_width_opt);
}
}
}
}
Expand Down

0 comments on commit 7ea6a0d

Please sign in to comment.