133 lines
4.7 KiB
Rust
133 lines
4.7 KiB
Rust
use cosmic_text::{
|
|
fontdb, Align, Attrs, AttrsList, BidiParagraphs, Buffer, Family, FontSystem, LayoutLine,
|
|
Metrics, ShapeLine, Shaping, Weight, Wrap,
|
|
};
|
|
|
|
// Test for https://github.com/pop-os/cosmic-text/issues/134
|
|
//
|
|
// Being able to get the same wrapping when feeding the measured width back into ShapeLine::layout
|
|
// as the new width limit is very useful for certain UI layout use cases.
|
|
#[test]
|
|
fn stable_wrap() {
|
|
let font_size = 18.0;
|
|
let attrs = AttrsList::new(
|
|
Attrs::new()
|
|
.family(Family::Name("FiraMono"))
|
|
.weight(Weight::MEDIUM),
|
|
);
|
|
let mut font_system =
|
|
FontSystem::new_with_locale_and_db("en-US".into(), fontdb::Database::new());
|
|
let font = std::fs::read("fonts/FiraMono-Medium.ttf").unwrap();
|
|
font_system.db_mut().load_font_data(font);
|
|
|
|
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_opt, wrap, align_opt, None);
|
|
let max_width = layout_unbounded.iter().map(|l| l.w).fold(0.0, f32::max);
|
|
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, 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:
|
|
// dbg_layout_lines(text, &layout_unbounded);
|
|
// dbg_layout_lines(text, &layout_bounded);
|
|
|
|
assert_eq!(
|
|
(max_width, layout_unbounded.len()),
|
|
(bounded_max_width, layout_bounded.len()),
|
|
"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:?} and align \"{align_opt:?}\" with text: \"{text}\"",
|
|
);
|
|
}
|
|
};
|
|
|
|
let hello_sample = std::fs::read_to_string("sample/hello.txt").unwrap();
|
|
let cases = [
|
|
"(6) SomewhatBoringDisplayTransform",
|
|
"",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
]
|
|
.into_iter()
|
|
// This has several cases where the line would wrap when the computed width was used as the
|
|
// width limit.
|
|
.chain(BidiParagraphs::new(&hello_sample));
|
|
|
|
for text in cases {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn wrap_extra_line() {
|
|
let mut font_system = FontSystem::new();
|
|
let metrics = Metrics::new(14.0, 20.0);
|
|
|
|
let mut buffer = Buffer::new(&mut font_system, metrics);
|
|
|
|
let mut buffer = buffer.borrow_with(&mut font_system);
|
|
|
|
// Add some text!
|
|
buffer.set_wrap(Wrap::Word);
|
|
buffer.set_text("Lorem ipsum dolor sit amet, qui minim labore adipisicing\n\nweeewoooo minim sint cillum sint consectetur cupidatat.", Attrs::new().family(cosmic_text::Family::Name("Inter")), Shaping::Advanced);
|
|
|
|
// Set a size for the text buffer, in pixels
|
|
buffer.set_size(Some(50.0), Some(1000.0));
|
|
|
|
// Perform shaping as desired
|
|
buffer.shape_until_scroll(false);
|
|
|
|
let empty_lines = buffer.layout_runs().filter(|x| x.line_w == 0.).count();
|
|
let overflow_lines = buffer.layout_runs().filter(|x| x.line_w > 50.).count();
|
|
|
|
assert_eq!(empty_lines, 1);
|
|
assert_eq!(overflow_lines, 4);
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
fn dbg_layout_lines(text: &str, lines: &[LayoutLine]) {
|
|
for line in lines {
|
|
let mut s = String::new();
|
|
for glyph in line.glyphs.iter() {
|
|
s.push_str(&text[glyph.start..glyph.end]);
|
|
}
|
|
println!("\"{s}\"");
|
|
}
|
|
}
|