mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-31 15:49:48 +00:00
M7: CSS system font names draw in macOS's System Font
`system-ui`, `-apple-system`, `BlinkMacSystemFont` and `.AppleSystemUIFont` join the names `apple_alias` resolves to the installed System Font, as SF Pro and SF UI already do. SVG import keeps a family the SVG lists when a font answers to its name, so on a Mac `font-family="-apple-system, system-ui, sans-serif"` keeps `-apple-system` and draws in System Font; elsewhere the generic stand-ins apply as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
90054a89c4
commit
2ff69183d7
4 files changed
+59
-18
No files matched your search
@@ -28,8 +28,11 @@ impl Fonts {
|
||||
fn load() -> Self {
|
||||
Fonts(figcraft_text::fontdb::family_names().into_iter().map(|f| f.to_lowercase()).collect())
|
||||
}
|
||||
/// Installed under this name, or under the family it names (`system-ui` on a Mac is its
|
||||
/// System Font, see `fontdb::apple_alias`).
|
||||
fn has(&self, family: &str) -> bool {
|
||||
self.0.contains(&family.to_lowercase())
|
||||
let key = family.to_lowercase();
|
||||
self.0.contains(&key) || figcraft_text::fontdb::apple_alias(&key).is_some_and(|target| self.0.contains(target))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,8 +70,9 @@ fn generic(name: &str) -> Option<&'static [&'static str]> {
|
||||
})
|
||||
}
|
||||
|
||||
/// The family to use: the first the SVG lists that's installed, else the first it names, else the
|
||||
/// default.
|
||||
/// The family to use: the first the SVG lists that's installed (a generic family as the first of
|
||||
/// its installed stand-ins, unless a font answers to its name: `system-ui` on a Mac), else the
|
||||
/// first it names, else the default.
|
||||
fn family(list: &[FontFamily], fonts: &Fonts) -> String {
|
||||
let name = |f: &FontFamily| match f {
|
||||
FontFamily::Serif => "serif".to_string(),
|
||||
@@ -80,14 +84,11 @@ fn family(list: &[FontFamily], fonts: &Fonts) -> String {
|
||||
};
|
||||
for f in list {
|
||||
let n = name(f);
|
||||
match generic(&n) {
|
||||
Some(cands) => {
|
||||
if let Some(c) = cands.iter().find(|c| fonts.has(c)) {
|
||||
return (*c).to_string();
|
||||
}
|
||||
}
|
||||
None if fonts.has(&n) => return n,
|
||||
None => {}
|
||||
if fonts.has(&n) {
|
||||
return n;
|
||||
}
|
||||
if let Some(c) = generic(&n).and_then(|cands| cands.iter().find(|c| fonts.has(c))) {
|
||||
return (*c).to_string();
|
||||
}
|
||||
}
|
||||
list.iter().map(name).find(|n| generic(n).is_none() && !n.is_empty()).unwrap_or_else(|| TextStyle::default().font_family)
|
||||
@@ -339,3 +340,7 @@ fn add_layer(
|
||||
}
|
||||
cx.add(n, parent);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "text_tests.rs"]
|
||||
mod tests;
|
||||
@@ -0,0 +1,32 @@
|
||||
//! Which family an SVG's `font-family` list gives a text layer.
|
||||
|
||||
use usvg::FontFamily;
|
||||
|
||||
use super::{Fonts, family};
|
||||
|
||||
fn fonts(installed: &[&str]) -> Fonts {
|
||||
Fonts(installed.iter().map(|f| f.to_lowercase()).collect())
|
||||
}
|
||||
|
||||
fn named(list: &[&str]) -> Vec<FontFamily> {
|
||||
list.iter()
|
||||
.map(|n| match *n {
|
||||
"sans-serif" => FontFamily::SansSerif,
|
||||
n => FontFamily::Named(n.to_string()),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// The names CSS gives the system font keep their name on a Mac, where they draw in its System
|
||||
/// Font, and fall back as before without it.
|
||||
#[test]
|
||||
fn css_system_font_names_keep_their_name_where_the_system_font_is() {
|
||||
let mac = fonts(&["System Font", "Inter", "Helvetica"]);
|
||||
assert_eq!(family(&named(&["-apple-system", "BlinkMacSystemFont", "system-ui", "sans-serif"]), &mac), "-apple-system");
|
||||
assert_eq!(family(&named(&["BlinkMacSystemFont", "sans-serif"]), &mac), "BlinkMacSystemFont");
|
||||
assert_eq!(family(&named(&["system-ui", "sans-serif"]), &mac), "system-ui");
|
||||
assert_eq!(family(&named(&["Helvetica", "system-ui"]), &mac), "Helvetica", "an installed family the SVG lists first still wins");
|
||||
let elsewhere = fonts(&["Inter", "DejaVu Sans"]);
|
||||
assert_eq!(family(&named(&["-apple-system", "BlinkMacSystemFont", "system-ui", "sans-serif"]), &elsewhere), "Inter");
|
||||
assert_eq!(family(&named(&["-apple-system"]), &elsewhere), "-apple-system", "nothing installed: the first name it gives");
|
||||
}
|
||||
@@ -1069,12 +1069,12 @@ fn public_family(family: &str) -> Option<String> {
|
||||
|
||||
/// The family Apple's system fonts are installed under, for the names designs use for them
|
||||
/// (lowercase): SF Pro and SF UI are the variable `SFNS.ttf` ("System Font"), its text and display
|
||||
/// cuts its optical sizes.
|
||||
fn apple_alias(key: &str) -> Option<&'static str> {
|
||||
/// cuts its optical sizes, as are the names CSS gives the system font (`system-ui`,
|
||||
/// `-apple-system`, `BlinkMacSystemFont`, `.AppleSystemUIFont`).
|
||||
pub fn apple_alias(key: &str) -> Option<&'static str> {
|
||||
Some(match key.trim_start_matches('.') {
|
||||
"sf pro" | "sf pro text" | "sf pro display" | "sf ui text" | "sf ui display" | "sf ns" | "sf ns text" | "sf ns display" | "san francisco" => {
|
||||
"system font"
|
||||
}
|
||||
"sf pro" | "sf pro text" | "sf pro display" | "sf ui text" | "sf ui display" | "sf ns" | "sf ns text" | "sf ns display" | "san francisco"
|
||||
| "system-ui" | "-apple-system" | "blinkmacsystemfont" | "applesystemuifont" => "system font",
|
||||
"sf compact text" | "sf compact display" => "sf compact",
|
||||
_ => return None,
|
||||
})
|
||||
|
||||
@@ -340,8 +340,8 @@ fn font_bytes_load_into_the_db() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Apple's system font answers to the names designs use for it (SF Pro, SF UI Text, …), unless a
|
||||
/// font of that name is installed.
|
||||
/// Apple's system font answers to the names designs and CSS use for it (SF Pro, SF UI Text,
|
||||
/// system-ui, …), unless a font of that name is installed.
|
||||
#[test]
|
||||
fn apple_system_font_names_find_the_system_font() {
|
||||
let mut db = FontDb::default();
|
||||
@@ -352,7 +352,11 @@ fn apple_system_font_names_find_the_system_font() {
|
||||
for name in ["SF Pro", "SF Pro Text", "SF Pro Display", "SF UI Text", "SF UI Display", ".SF NS Text", "San Francisco"] {
|
||||
assert!(db.has_family(name), "{name}");
|
||||
}
|
||||
for name in ["system-ui", "-apple-system", "BlinkMacSystemFont", ".AppleSystemUIFont"] {
|
||||
assert_eq!(db.key(name), "system font", "{name}");
|
||||
}
|
||||
assert!(!db.has_family("SF Mono"));
|
||||
assert!(!db.has_family("ui-monospace"));
|
||||
db.pending.insert("sf pro".into(), ("SF Pro".into(), Vec::new()));
|
||||
assert_eq!(db.key("SF Pro"), "sf pro", "an installed SF Pro is itself");
|
||||
assert_eq!(db.key("SF UI Text"), "system font");
|
||||
|
||||
Reference in new issue
Block a user