use kui_core::{Core, FontFeatures, NodeSpec, QuadKind, Size, TextStyle};
#[test]
fn the_spelling_round_trips() {
let f = FontFeatures::parse("liga=0, calt=0 tnum -dlig +ss01");
let got: Vec<(String, u32)> = f
.iter()
.map(|(t, v)| (String::from_utf8_lossy(t).trim_end().to_string(), v))
.collect();
assert_eq!(
got,
[
("liga".to_string(), 0),
("calt".to_string(), 0),
("tnum".to_string(), 1),
("dlig".to_string(), 0),
("ss01".to_string(), 1),
]
);
assert_eq!(f.to_string_spelling(), "liga=0 calt=0 tnum=1 dlig=0 ss01=1");
assert_eq!(FontFeatures::parse(f.to_string_spelling().as_str()), f);
let f = FontFeatures::new().set("liga", 1).set("liga", 0);
assert_eq!(f.len(), 1);
let many = (0..10).fold(FontFeatures::new(), |f, i| f.set(&format!("ss{i:02}"), 1));
assert_eq!(many.len(), FontFeatures::MAX);
assert!(FontFeatures::parse("").is_empty());
}
#[test]
fn features_are_part_of_what_a_text_is_shaped_as() {
let mut core = Core::new();
let mut ui = core.frame(Size::new(300.0, 100.0), 1.0);
ui.configure_root(NodeSpec::column().fill());
ui.text("fi ->", TextStyle::new(16.0));
ui.text(
"fi ->",
TextStyle::new(16.0).features(FontFeatures::parse("liga=0 calt=0")),
);
ui.text("fi ->", TextStyle::new(16.0));
ui.finish();
assert_eq!(core.text_cache_len(), 2);
}
#[test]
fn ligatures_come_apart_when_asked() {
let mut core = Core::new();
let Some(id) = ["Fira Code", "Cascadia Code", "JetBrains Mono"]
.iter()
.find_map(|name| core.add_system_font(name))
else {
eprintln!("skipped: no ligature font installed");
return;
};
let glyphs = |core: &mut Core, features: &str| {
let mut ui = core.frame(Size::new(300.0, 100.0), 1.0);
ui.configure_root(NodeSpec::column().fill());
ui.text(
"-> != www",
TextStyle::new(24.0)
.font(id)
.features(FontFeatures::parse(features)),
);
ui.finish();
let (dl, _) = core.output();
dl.quads
.iter()
.filter(|q| matches!(q.kind, QuadKind::GlyphMask | QuadKind::GlyphSubpixel))
.count()
};
let joined = glyphs(&mut core, "");
let apart = glyphs(&mut core, "liga=0 calt=0 dlig=0");
assert!(
apart > joined,
"the ligatures hold by default ({joined} glyphs) and come apart with the features off ({apart})"
);
}
#[test]
fn the_fixture_font_s_ligature_holds_by_default_and_comes_apart_with_liga_off() {
let mut core = Core::new();
let id = core
.add_font_data(kui_core::testing::liga_font())
.expect("the fixture face registers");
assert_eq!(core.font_family(id), Some("Kui Liga"));
let glyphs = |core: &mut Core, text: &str, features: &str| {
let mut ui = core.frame(Size::new(300.0, 100.0), 1.0);
ui.configure_root(NodeSpec::column().fill());
ui.text(
text,
TextStyle::new(24.0)
.font(id)
.features(FontFeatures::parse(features)),
);
ui.finish();
let (dl, _) = core.output();
dl.quads
.iter()
.filter(|q| matches!(q.kind, QuadKind::GlyphMask | QuadKind::GlyphSubpixel))
.count()
};
assert_eq!(glyphs(&mut core, "fi", ""), 1, "f + i joined by default");
assert_eq!(
glyphs(&mut core, "fi", "liga=0"),
2,
"and apart with liga off"
);
assert_eq!(glyphs(&mut core, "if", ""), 2, "the ligature is ordered");
assert_eq!(
glyphs(&mut core, "fifi", ""),
2,
"and applies at every match"
);
}