Another project
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 3.8 kB View raw
1use parley::FontWeight as ParleyFontWeight; 2use serde::{Deserialize, Serialize}; 3use swash::FontRef; 4 5pub(crate) const SANS_DATA: &[u8] = include_bytes!("../../../assets/DejaVuSans.ttf"); 6pub(crate) const MONO_DATA: &[u8] = include_bytes!("../../../assets/DejaVuSansMono.ttf"); 7 8pub(crate) const SANS_FAMILY: &str = "DejaVu Sans"; 9pub(crate) const MONO_FAMILY: &str = "DejaVu Sans Mono"; 10 11#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] 12pub enum FontFace { 13 Sans, 14 Mono, 15} 16 17#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] 18pub enum FontWeight { 19 Regular, 20 Medium, 21 Semibold, 22 Bold, 23} 24 25#[must_use] 26pub fn load_font(face: FontFace) -> FontRef<'static> { 27 let bytes = data_for(face); 28 let label = family_for(face); 29 let Some(font) = FontRef::from_index(bytes, 0) else { 30 panic!("bundled font {label} failed to parse; binary asset is broken"); 31 }; 32 font 33} 34 35pub(crate) const fn data_for(face: FontFace) -> &'static [u8] { 36 match face { 37 FontFace::Sans => SANS_DATA, 38 FontFace::Mono => MONO_DATA, 39 } 40} 41 42pub(crate) const fn family_for(face: FontFace) -> &'static str { 43 match face { 44 FontFace::Sans => SANS_FAMILY, 45 FontFace::Mono => MONO_FAMILY, 46 } 47} 48 49pub(crate) const fn parley_weight(weight: FontWeight) -> ParleyFontWeight { 50 match weight { 51 FontWeight::Regular => ParleyFontWeight::NORMAL, 52 FontWeight::Medium => ParleyFontWeight::MEDIUM, 53 FontWeight::Semibold => ParleyFontWeight::SEMI_BOLD, 54 FontWeight::Bold => ParleyFontWeight::BOLD, 55 } 56} 57 58#[cfg(test)] 59mod tests { 60 use super::{ 61 FontFace, FontWeight, MONO_DATA, MONO_FAMILY, SANS_DATA, SANS_FAMILY, data_for, family_for, 62 load_font, parley_weight, 63 }; 64 use parley::FontWeight as ParleyFontWeight; 65 66 #[test] 67 fn sans_and_mono_data_are_distinct_bundled_assets() { 68 assert!(!SANS_DATA.is_empty()); 69 assert!(!MONO_DATA.is_empty()); 70 assert_ne!(SANS_DATA, MONO_DATA); 71 } 72 73 #[test] 74 fn data_for_resolves_face_to_its_asset() { 75 assert_eq!(data_for(FontFace::Sans), SANS_DATA); 76 assert_eq!(data_for(FontFace::Mono), MONO_DATA); 77 } 78 79 #[test] 80 fn family_for_resolves_face_to_its_family_name() { 81 assert_eq!(family_for(FontFace::Sans), SANS_FAMILY); 82 assert_eq!(family_for(FontFace::Mono), MONO_FAMILY); 83 } 84 85 #[test] 86 fn load_font_returns_valid_fontref_for_each_face() { 87 let sans = load_font(FontFace::Sans); 88 let mono = load_font(FontFace::Mono); 89 assert!(sans.charmap().map(u32::from('A')) > 0); 90 assert!(mono.charmap().map(u32::from('A')) > 0); 91 } 92 93 #[test] 94 fn bundled_fonts_cover_arabic_baseline_for_complex_script_dim_labels() { 95 let sans = load_font(FontFace::Sans); 96 let mono = load_font(FontFace::Mono); 97 ['\u{0627}', '\u{0644}', '\u{0637}', '\u{0648}', '\u{0645}'] 98 .into_iter() 99 .for_each(|ch| { 100 let cp = u32::from(ch); 101 assert!( 102 sans.charmap().map(cp) > 0, 103 "sans must cover arabic codepoint U+{cp:04X}", 104 ); 105 assert!( 106 mono.charmap().map(cp) > 0, 107 "mono must cover arabic codepoint U+{cp:04X}", 108 ); 109 }); 110 } 111 112 #[test] 113 fn parley_weight_round_trips_each_step() { 114 assert_eq!(parley_weight(FontWeight::Regular), ParleyFontWeight::NORMAL); 115 assert_eq!(parley_weight(FontWeight::Medium), ParleyFontWeight::MEDIUM); 116 assert_eq!( 117 parley_weight(FontWeight::Semibold), 118 ParleyFontWeight::SEMI_BOLD 119 ); 120 assert_eq!(parley_weight(FontWeight::Bold), ParleyFontWeight::BOLD); 121 } 122}