diff --git a/crates/text/src/shape.rs b/crates/text/src/shape.rs index 0447b03c4..650c3fc3c 100644 --- a/crates/text/src/shape.rs +++ b/crates/text/src/shape.rs @@ -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) { diff --git a/crates/text/src/tests.rs b/crates/text/src/tests.rs index 8796791db..d7c52af75 100644 --- a/crates/text/src/tests.rs +++ b/crates/text/src/tests.rs @@ -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::>()); + 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));