Allow layout to be calculated without specifying width
This commit is contained in:
parent
a3a6262e5d
commit
b288de13ae
4 changed files with 66 additions and 32 deletions
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -226,7 +226,7 @@ impl BufferLine {
|
|||
&mut ShapeBuffer::default(),
|
||||
font_system,
|
||||
font_size,
|
||||
width,
|
||||
width_opt,
|
||||
wrap,
|
||||
match_mono_width,
|
||||
tab_width,
|
||||
|
|
@ -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,
|
||||
|
|
@ -251,7 +251,7 @@ impl BufferLine {
|
|||
shape.layout_to_buffer(
|
||||
scratch,
|
||||
font_size,
|
||||
width,
|
||||
width_opt,
|
||||
wrap,
|
||||
align,
|
||||
&mut layout,
|
||||
|
|
|
|||
37
src/shape.rs
37
src/shape.rs
|
|
@ -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>,
|
||||
|
|
@ -1001,7 +1001,7 @@ impl ShapeLine {
|
|||
self.layout_to_buffer(
|
||||
&mut ShapeBuffer::default(),
|
||||
font_size,
|
||||
line_width,
|
||||
width_opt,
|
||||
wrap,
|
||||
align,
|
||||
&mut lines,
|
||||
|
|
@ -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>,
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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,
|
||||
|
|
@ -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;
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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,
|
||||
|
|
@ -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;
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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}\"",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue