diff --git a/src/eval/state.rs b/src/eval/state.rs index 2037c695e..b6c0c9af8 100644 --- a/src/eval/state.rs +++ b/src/eval/state.rs @@ -119,13 +119,6 @@ impl Default for ParState { /// Defines font properties. #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct FontState { - /// Whether 300 extra font weight should be added to what is defined by the - /// `variant`. - pub strong: bool, - /// Whether the the font style defined by the `variant` should be inverted. - pub emph: bool, - /// Whether a monospace font should be preferred. - pub monospace: bool, /// The font size. pub size: Length, /// The selected font variant (the final variant also depends on `strong` @@ -140,6 +133,15 @@ pub struct FontState { /// A list of font families with generic class definitions (the final /// family list also depends on `monospace`). pub families: Rc, + /// Whether 300 extra font weight should be added to what is defined by the + /// `variant`. + pub strong: bool, + /// Whether the the font style defined by the `variant` should be inverted. + pub emph: bool, + /// Whether a monospace font should be preferred. + pub monospace: bool, + /// Whether font fallback to a base list should occur. + pub fallback: bool, } impl FontState { @@ -164,10 +166,11 @@ impl FontState { /// The resolved family iterator. pub fn families(&self) -> impl Iterator + Clone { - let head = self - .monospace - .then(|| self.families.monospace.as_slice()) - .unwrap_or_default(); + let head = if self.monospace { + self.families.monospace.as_slice() + } else { + &[] + }; let core = self.families.list.iter().flat_map(move |family| { match family { @@ -178,10 +181,13 @@ impl FontState { } }); - head.iter() - .chain(core) - .chain(self.families.base.iter()) - .map(String::as_str) + let tail = if self.fallback { + self.families.base.as_slice() + } else { + &[] + }; + + head.iter().chain(core).chain(tail).map(String::as_str) } /// Access the `families` state mutably. @@ -193,19 +199,20 @@ impl FontState { impl Default for FontState { fn default() -> Self { Self { - families: Rc::new(FamilyState::default()), + size: Length::pt(11.0), variant: FontVariant { style: FontStyle::Normal, weight: FontWeight::REGULAR, stretch: FontStretch::NORMAL, }, - strong: false, - emph: false, - monospace: false, - size: Length::pt(11.0), top_edge: VerticalFontMetric::CapHeight, bottom_edge: VerticalFontMetric::Baseline, fill: Paint::Color(Color::Rgba(RgbaColor::BLACK)), + families: Rc::new(FamilyState::default()), + strong: false, + emph: false, + monospace: false, + fallback: true, } } } diff --git a/src/library/text.rs b/src/library/text.rs index f3e086c81..f12794aa8 100644 --- a/src/library/text.rs +++ b/src/library/text.rs @@ -19,6 +19,7 @@ pub fn font(ctx: &mut EvalContext, args: &mut Arguments) -> TypResult { let serif = args.named("serif")?; let sans_serif = args.named("sans-serif")?; let monospace = args.named("monospace")?; + let fallback = args.named("fallback")?; ctx.template.modify(move |state| { let font = state.font_mut(); @@ -66,6 +67,10 @@ pub fn font(ctx: &mut EvalContext, args: &mut Arguments) -> TypResult { if let Some(FamilyDef(monospace)) = &monospace { font.families_mut().monospace = monospace.clone(); } + + if let Some(fallback) = fallback { + font.fallback = fallback; + } }); Ok(Value::None) diff --git a/tests/ref/text/font.png b/tests/ref/text/font.png index 44183b3ac..b8e0775a6 100644 Binary files a/tests/ref/text/font.png and b/tests/ref/text/font.png differ diff --git a/tests/typ/text/font.typ b/tests/typ/text/font.typ index fbb999f8f..ecc078869 100644 --- a/tests/typ/text/font.typ +++ b/tests/typ/text/font.typ @@ -33,6 +33,18 @@ Emoji: 🐪, 🌋, 🏞 This is [#font(fill: rgb("FA644B")) way more] colorful. ] +// Disable font fallback beyond the user-specified list. +// Without disabling, Latin Modern Math would come to the rescue. +#font("PT Sans", "Twitter Color Emoji", fallback: false) +2π = 𝛼 + 𝛽. ✅ + +--- +// Test class definitions. +#font(sans-serif: "PT Sans") +[#font(family: sans-serif) Sans-serif.] \ +[#font(monospace) Monospace.] \ +[#font(monospace, monospace: ("Nope", "Latin Modern Math")) Math.] + --- // Test top and bottom edge. @@ -47,13 +59,6 @@ Emoji: 🐪, 🌋, 🏞 #try(cap-height, baseline) #try(x-height, baseline) ---- -// Test class definitions. -#font(sans-serif: "PT Sans") -[#font(family: sans-serif) Sans-serif.] \ -[#font(monospace) Monospace.] \ -[#font(monospace, monospace: ("Nope", "Latin Modern Math")) Math.] - --- // Error: 7-12 unexpected argument #font(false)