use write_fonts::types::Tag;
#[derive(Clone, Debug, Default, PartialEq)]
pub struct UnicodeRange([u32; 4]);
#[derive(Clone, Debug, Default, PartialEq)]
pub struct CodePageRange([u32; 2]);
#[allow(missing_docs)]
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Os2Builder {
pub us_weight_class: Option<u16>,
pub us_width_class: Option<u16>,
pub fs_type: Option<u16>,
pub s_family_class: Option<i16>,
pub panose_10: Option<[u8; 10]>,
pub unicode_range: Option<UnicodeRange>,
pub ach_vend_id: Option<Tag>,
pub us_win_ascent: Option<u16>,
pub us_win_descent: Option<u16>,
pub code_page_range: Option<CodePageRange>,
pub sx_height: Option<i16>,
pub s_cap_height: Option<i16>,
pub s_typo_ascender: Option<i16>,
pub s_typo_descender: Option<i16>,
pub s_typo_line_gap: Option<i16>,
pub us_lower_optical_point_size: Option<u16>,
pub us_upper_optical_point_size: Option<u16>,
}
impl UnicodeRange {
pub(crate) fn set_bit(&mut self, bit: u8) {
set_bit_impl(&mut self.0, bit)
}
}
impl CodePageRange {
pub(crate) fn bit_for_code_page(val: u16) -> Option<u8> {
CODEPAGE_TO_BIT
.iter()
.find_map(|(page, bit)| if *page == val { Some(*bit) } else { None })
}
pub(crate) fn add_code_page(&mut self, page: u16) {
let bit = Self::bit_for_code_page(page).unwrap();
set_bit_impl(&mut self.0, bit)
}
}
fn set_bit_impl<const N: usize>(array: &mut [u32; N], bit: u8) {
assert!(bit < (32 * N) as u8);
let idx = (bit / 32) as usize;
let bit = bit % 32;
array[idx] |= 1 << bit;
}
impl Os2Builder {
pub fn build(&self) -> write_fonts::tables::os2::Os2 {
let code_page_range = self.code_page_range.as_ref().map_or([0; 2], |r| r.0);
let unicode_range = self.unicode_range.as_ref().map_or([0; 4], |r| r.0);
write_fonts::tables::os2::Os2 {
us_weight_class: self.us_weight_class.unwrap_or_default(),
us_width_class: self.us_width_class.unwrap_or_default(),
fs_type: self.fs_type.unwrap_or_default(),
s_family_class: self.s_family_class.unwrap_or_default(),
ul_unicode_range_1: unicode_range[0],
ul_unicode_range_2: unicode_range[1],
ul_unicode_range_3: unicode_range[2],
ul_unicode_range_4: unicode_range[3],
panose_10: self.panose_10.unwrap_or_default(),
ach_vend_id: self.ach_vend_id.unwrap_or_default(),
s_typo_ascender: self.s_typo_ascender.unwrap_or_default(),
s_typo_descender: self.s_typo_descender.unwrap_or_default(),
s_typo_line_gap: self.s_typo_line_gap.unwrap_or_default(),
us_win_ascent: self.us_win_ascent.unwrap_or_default(),
us_win_descent: self.us_win_descent.unwrap_or_default(),
ul_code_page_range_1: Some(code_page_range[0]),
ul_code_page_range_2: Some(code_page_range[1]),
sx_height: Some(self.sx_height.unwrap_or_default()),
s_cap_height: Some(self.s_cap_height.unwrap_or_default()),
us_default_char: Some(0),
us_max_context: Some(0),
us_break_char: Some(0),
us_lower_optical_point_size: self.us_lower_optical_point_size,
us_upper_optical_point_size: self.us_upper_optical_point_size,
..Default::default()
}
}
}
static CODEPAGE_TO_BIT: &[(u16, u8)] = &[
(437, 63),
(708, 61),
(737, 60),
(775, 59),
(850, 62),
(852, 58),
(855, 57),
(857, 56),
(860, 55),
(861, 54),
(862, 53),
(863, 52),
(864, 51),
(865, 50),
(866, 49),
(869, 48),
(874, 16),
(932, 17),
(936, 18),
(949, 19),
(950, 20),
(1250, 1),
(1251, 2),
(1252, 0),
(1253, 3),
(1254, 4),
(1255, 5),
(1256, 6),
(1257, 7),
(1258, 8),
(1361, 21),
];