use crate::types::{Mode, ParseError, ParseErrorKind};
const WIDE_LATIN_LETTER_DATA: [(&str, &str, &str); 26] = [
("mathbf", "textbf", "Main-Bold"), ("mathbf", "textbf", "Main-Bold"), ("mathnormal", "textit", "Math-Italic"), ("mathnormal", "textit", "Math-Italic"), ("boldsymbol", "boldsymbol", "Main-BoldItalic"), ("boldsymbol", "boldsymbol", "Main-BoldItalic"), ("mathscr", "textscr", "Script-Regular"), ("", "", ""), ("", "", ""), ("", "", ""), ("mathfrak", "textfrak", "Fraktur-Regular"), ("mathfrak", "textfrak", "Fraktur-Regular"), ("mathbb", "textbb", "AMS-Regular"), ("mathbb", "textbb", "AMS-Regular"), ("mathboldfrak", "textboldfrak", "Fraktur-Regular"), ("mathboldfrak", "textboldfrak", "Fraktur-Regular"), ("mathsf", "textsf", "SansSerif-Regular"), ("mathsf", "textsf", "SansSerif-Regular"), ("mathboldsf", "textboldsf", "SansSerif-Bold"), ("mathboldsf", "textboldsf", "SansSerif-Bold"), ("mathitsf", "textitsf", "SansSerif-Italic"), ("mathitsf", "textitsf", "SansSerif-Italic"), ("", "", ""), ("", "", ""), ("mathtt", "texttt", "Typewriter-Regular"), ("mathtt", "texttt", "Typewriter-Regular"), ];
const WIDE_NUMERAL_DATA: [(&str, &str, &str); 5] = [
("mathbf", "textbf", "Main-Bold"), ("", "", ""), ("mathsf", "textsf", "SansSerif-Regular"), ("mathboldsf", "textboldsf", "SansSerif-Bold"), ("mathtt", "texttt", "Typewriter-Regular"), ];
pub fn wide_character_font_from_char(
wide_char: char,
mode: Mode,
) -> Result<(&'static str, &'static str), ParseError> {
let code_point = wide_char as u32;
let css_col = i32::from(mode != Mode::Math);
if (0x1D400..0x1D6A4).contains(&code_point) {
let i = ((code_point - 0x1D400) / 26) as usize;
let (math_cls, text_cls, font_name) = WIDE_LATIN_LETTER_DATA[i];
let css_class = if css_col == 0 { math_cls } else { text_cls };
Ok((font_name, css_class))
} else if (0x1D7CE..=0x1D7FF).contains(&code_point) {
let i = ((code_point - 0x1D7CE) / 10) as usize;
let (math_cls, text_cls, font_name) = WIDE_NUMERAL_DATA[i];
let css_class = if css_col == 0 { math_cls } else { text_cls };
Ok((font_name, css_class))
} else if code_point == 0x1D6A5 || code_point == 0x1D6A6 {
let (math_cls, text_cls, font_name) = WIDE_LATIN_LETTER_DATA[0];
let css_class = if css_col == 0 { math_cls } else { text_cls };
Ok((font_name, css_class))
} else if (0x1D6A7..0x1D7CE).contains(&code_point) {
Ok(("", ""))
} else {
Err(ParseError::new(ParseErrorKind::UnsupportedWideCharacter {
character: wide_char.to_string(),
}))
}
}
pub fn get_wide_character_font(
wide_char: &str,
mode: Mode,
) -> Result<(&'static str, &'static str), ParseError> {
wide_char.chars().next().map_or_else(
|| Err(ParseError::new(ParseErrorKind::EmptyWideCharacterInput)),
|ch| wide_character_font_from_char(ch, mode),
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bold_capital_a() {
let ch = char::from_u32(0x1D400).unwrap();
let (font, class) = wide_character_font_from_char(ch, Mode::Math).unwrap();
assert_eq!(font, "Main-Bold");
assert_eq!(class, "mathbf");
}
#[test]
fn test_bold_digit_zero() {
let ch = char::from_u32(0x1D7CE).unwrap();
let (font, class) = wide_character_font_from_char(ch, Mode::Math).unwrap();
assert_eq!(font, "Main-Bold");
assert_eq!(class, "mathbf");
}
#[test]
fn test_dotless_i_j() {
for cp in [0x1D6A5u32, 0x1D6A6u32] {
let ch = char::from_u32(cp).unwrap();
let (font, class) = wide_character_font_from_char(ch, Mode::Text).unwrap();
assert_eq!(font, "Main-Bold");
assert_eq!(class, "textbf");
}
}
#[test]
fn test_greek_block_unsupported_returns_empty() {
let ch = char::from_u32(0x1D6B5).unwrap();
let (font, class) = wide_character_font_from_char(ch, Mode::Math).unwrap();
assert_eq!(font, "");
assert_eq!(class, "");
}
#[test]
fn test_outside_block_errors() {
let res = wide_character_font_from_char('A', Mode::Math);
assert!(res.is_err());
}
}