mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 21:14:18 +00:00
Merge pull request #5701 from dotCooCoo/fix/glyph-cluster-ligature
Glyphs: a consonant's ligature in a cluster with its vowel sign is its glyph
This commit is contained in:
@@ -1153,7 +1153,9 @@ fn glyph_target(t: &TextObject, p: &Value, c: &str) -> Result<(char, std::ops::R
|
||||
/// text; `None` when the character is not laid out (overflowing text). A character that starts a
|
||||
/// longer grapheme (a letter and its combining marks) is drawn in the grapheme's cluster. Of a
|
||||
/// cluster of several glyphs (a mark, a vowel sign drawn before the letter), the character's glyph
|
||||
/// is its default glyph or one of its alternates; `Some(None)` when the cluster holds neither.
|
||||
/// is its default glyph or one of its alternates, else the first glyph that is not the default glyph
|
||||
/// or an alternate of another character of the grapheme (a ligature of the letter and a mark);
|
||||
/// `Some(None)` when the cluster holds none of these.
|
||||
fn own_glyph(
|
||||
plain: &str,
|
||||
lay: &vectorcraft_text::TextLayout,
|
||||
@@ -1172,8 +1174,20 @@ fn own_glyph(
|
||||
Some(match cluster[..] {
|
||||
[one] => Some(one),
|
||||
_ => {
|
||||
let (default, listed) = (face.glyph_for(ch), face.alternates(ch));
|
||||
cluster.into_iter().find(|&g| g == default || listed.iter().any(|a| a.gid == g))
|
||||
// The glyphs of each character are looked up once: a grapheme can repeat a mark.
|
||||
let glyphs_of = |c: char| face.alternates(c).iter().map(|a| a.gid).chain([face.glyph_for(c)]).collect::<Vec<u32>>();
|
||||
let default = face.glyph_for(ch);
|
||||
let listed = || {
|
||||
let own = glyphs_of(ch);
|
||||
cluster.iter().copied().find(|g| own.contains(g))
|
||||
};
|
||||
cluster.iter().copied().find(|&g| g == default).or_else(listed).or_else(|| {
|
||||
let mut others: Vec<char> = plain.get(bytes.end..bytes.start + grapheme).unwrap_or_default().chars().collect();
|
||||
others.sort_unstable();
|
||||
others.dedup();
|
||||
let theirs: Vec<u32> = others.into_iter().flat_map(glyphs_of).collect();
|
||||
cluster.iter().copied().find(|g| !theirs.contains(g))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2589,6 +2589,28 @@ fn the_glyph_of_a_consonant_after_its_vowel_sign_is_reported() {
|
||||
assert_eq!(s.execute("text.glyphAlternates", &json!({"id": id.0, "start": 0})).unwrap()["chosen"], json!(g('a')));
|
||||
}
|
||||
|
||||
/// Ka with a nukta and the vowel sign I is one cluster: the vowel sign drawn first, then the
|
||||
/// ligature of Ka and the nukta, which is neither Ka's default glyph nor one of its alternates. The
|
||||
/// glyph reported for Ka is the ligature, not the vowel sign.
|
||||
#[test]
|
||||
fn the_ligature_of_a_consonant_after_its_vowel_sign_is_reported() {
|
||||
use vectorcraft_text::test_fonts::{MATRA_FAMILY, matra_font, source_sans_gid};
|
||||
let _fonts = crate::adding_fonts();
|
||||
let db = vectorcraft_text::FontDb::global();
|
||||
db.add_font(matra_font().expect("the test font builds"));
|
||||
let g = |c| u32::from(source_sans_gid(c).expect("a Source Sans glyph"));
|
||||
let mut s = session();
|
||||
let text = "क\u{93C}\u{93F}";
|
||||
let r = s.execute("text.create", &json!({"x": 100, "y": 100, "text": text, "size": 20, "font": MATRA_FAMILY})).unwrap();
|
||||
let id = NodeId(r["id"].as_u64().unwrap());
|
||||
let gids: Vec<_> = vectorcraft_text::layout(db, &obj(&s, id)).glyphs.iter().map(|gl| (gl.gid, gl.byte, gl.len)).collect();
|
||||
assert_eq!(gids, [(g('i'), 0, 9), (g('N'), 0, 9)], "the vowel sign is drawn first, then the ligature");
|
||||
|
||||
assert_eq!(s.execute("text.glyphAlternates", &json!({"id": id.0, "start": 0})).unwrap()["chosen"], json!(g('N')));
|
||||
let r = s.execute("text.setGlyphAlternate", &json!({"id": id.0, "start": 0, "gid": null})).unwrap();
|
||||
assert_eq!(r["gid"], json!(g('N')), "the ligature is drawn for Ka");
|
||||
}
|
||||
|
||||
/// A character that overflows its area is shaped with its grapheme: the nukta after Ka makes the
|
||||
/// font's `nukt` ligature, which `salt` does not change, so `gid: null` reports the ligature as it
|
||||
/// does for the laid-out text.
|
||||
|
||||
Reference in New Issue
Block a user