Merge pull request #1900 from imachus/pr/ja-whitespace-fallback

Type: whitespace the primary font doesn't map takes the fallback face too (#1844)
This commit is contained in:
BFlat
2026-10-16 06:36:58 +07:00
committed by GitHub
2 changed files with 24 additions and 1 deletions
+4 -1
View File
@@ -374,7 +374,10 @@ pub(crate) fn shape_range(
// Digits are drawn in the style's numeral system: the font must cover that digit.
let c = st.digits.map(c);
let level = level_at(i);
let covered = c.is_whitespace() || c.is_control() || pmap.as_ref().is_none_or(|m| m.map(c).is_some());
// Whitespace the primary font doesn't map goes to the fallback face like any other
// character (#1844): an ideographic space set at zero width would remove an indent.
// What the layout handles itself (tab, line and paragraph breaks) stays.
let covered = c.is_control() || pmap.as_ref().is_none_or(|m| m.map(c).is_some());
let face = if covered {
primary.clone()
} else if let Some((_, f)) = cache.iter().find(|(k, _)| *k == c) {
+20
View File
@@ -405,6 +405,26 @@ fn fallback_font_per_character() {
assert_eq!(l.glyphs[2].font_id, primary.id());
}
/// A space the primary font doesn't map goes to the fallback face like any other character
/// (#1844): an ideographic space in a face without U+3000 keeps its em, so an indent made with it
/// isn't lost. A tab, which the layout handles itself, stays with the primary face. Needs a bundled
/// face with U+3000 and あ (craft-fonts; skipped without it).
#[test]
fn whitespace_the_primary_font_lacks_takes_the_fallback_face() {
let primary = db().face("Source Sans 3", "Regular").unwrap();
assert!(!primary.covers('\u{3000}'));
if ['\u{3000}', 'あ'].iter().any(|&c| db().fallback_for(c, primary.id()).is_none()) {
eprintln!("skipped: built without craft-fonts (set CRAFT_FONTS_DIR to a craft-fonts checkout to run it)");
return;
}
let l = layout(db(), &point("あ\u{3000}あ", style(20.0)));
let width: f64 = l.glyphs.iter().map(|g| g.advance).sum();
assert!((width - 60.0).abs() < 0.01, "あ あ sets at 3 em: {:?}", l.glyphs.iter().map(|g| g.advance).collect::<Vec<_>>());
assert_ne!(l.glyphs[1].font_id, primary.id());
let l = layout(db(), &point("a\tb", style(20.0)));
assert!(l.glyphs.iter().all(|g| g.font_id == primary.id()));
}
#[test]
fn multiple_runs_and_styles() {
let mut t = point("", style(10.0));