pub static ROBOTO_REGULAR: &[u8] = include_bytes!("../fonts/Roboto-Regular.ttf");
pub static ROBOTO_BOLD: &[u8] = include_bytes!("../fonts/Roboto-Bold.ttf");
pub static ROBOTO_ITALIC: &[u8] = include_bytes!("../fonts/Roboto-Italic.ttf");
pub static ROBOTO_BOLD_ITALIC: &[u8] = include_bytes!("../fonts/Roboto-BoldItalic.ttf");
pub static PT_ROOT_UI_VF: &[u8] = include_bytes!("../fonts/PTRootUI-VF.ttf");
pub static JETBRAINS_MONO_REGULAR: &[u8] =
include_bytes!("../fonts/JetBrainsMono-Regular.ttf");
pub static JETBRAINS_MONO_BOLD: &[u8] =
include_bytes!("../fonts/JetBrainsMono-Bold.ttf");
pub static NOTO_SANS_SYMBOLS2: &[u8] =
include_bytes!("../fonts/NotoSansSymbols2-Regular.ttf");
pub static NOTO_EMOJI: &[u8] = include_bytes!("../fonts/NotoEmoji-Regular.ttf");
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum FontFamily {
#[default]
Roboto,
PtRootUi,
JetBrainsMono,
}
#[derive(Clone, Debug)]
pub struct FontInfo {
pub size: f32,
pub bold: bool,
pub italic: bool,
pub family: FontFamily,
}
impl Default for FontInfo {
fn default() -> Self {
Self {
size: 12.0,
bold: false,
italic: false,
family: FontFamily::Roboto,
}
}
}
fn is_pt_root_ui(font_str_lower: &str) -> bool {
font_str_lower.contains("pt root ui")
|| font_str_lower.contains("pt-root-ui")
|| font_str_lower.contains("ptrootui")
}
fn is_monospace(font_str_lower: &str) -> bool {
font_str_lower.contains("jetbrains")
|| font_str_lower.contains("jb mono")
|| font_str_lower.contains("monospace")
|| font_str_lower.contains("consolas")
|| font_str_lower.contains("courier")
|| font_str_lower.contains("cascadia")
|| font_str_lower.contains("fira code")
|| font_str_lower.contains("fira mono")
}
pub fn resolve_family(family_str: &str) -> FontFamily {
let lower = family_str.to_ascii_lowercase();
if is_monospace(&lower) {
FontFamily::JetBrainsMono
} else if is_pt_root_ui(&lower) {
FontFamily::PtRootUi
} else {
FontFamily::Roboto
}
}
pub fn parse_css_font(font_str: &str) -> FontInfo {
let lower = font_str.to_ascii_lowercase();
let mut info = FontInfo::default();
let mut family_parts: Vec<&str> = Vec::new();
for part in lower.split_whitespace() {
match part {
"bold" => info.bold = true,
"italic" => info.italic = true,
s if s.ends_with("px") => {
if let Ok(sz) = s.trim_end_matches("px").parse::<f32>() {
info.size = sz;
}
}
other => family_parts.push(other),
}
}
if !family_parts.is_empty() {
info.family = resolve_family(&family_parts.join(" "));
}
info
}
pub fn font_bytes(family: FontFamily, bold: bool, italic: bool) -> &'static [u8] {
match family {
FontFamily::Roboto => match (bold, italic) {
(true, true ) => ROBOTO_BOLD_ITALIC,
(true, false) => ROBOTO_BOLD,
(false, true ) => ROBOTO_ITALIC,
(false, false) => ROBOTO_REGULAR,
},
FontFamily::PtRootUi => PT_ROOT_UI_VF,
FontFamily::JetBrainsMono => {
let _ = italic; if bold { JETBRAINS_MONO_BOLD } else { JETBRAINS_MONO_REGULAR }
}
}
}
pub fn family_from_css_font(font_str: &str) -> FontFamily {
parse_css_font(font_str).family
}