mkwebfont_fontops 0.4.0

Internal crate for mkwebfont.
Documentation
use hb_subset::{
    sys::{
        hb_face_t, hb_ot_name_get_utf8, hb_ot_name_id_t,
        hb_ot_var_axis_flags_t_HB_OT_VAR_AXIS_FLAG_HIDDEN, hb_ot_var_axis_info_t,
        hb_ot_var_get_axis_count, hb_ot_var_get_axis_infos, hb_subset_input_pin_axis_location,
        hb_tag_t, HB_LANGUAGE_INVALID,
    },
    FontFace, SubsetInput,
};
use std::{ffi::c_uint, ops::RangeInclusive};

#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
pub enum AxisName {
    Weight,
}
impl AxisName {
    fn of(name: &str) -> Option<AxisName> {
        match name {
            x if x.eq_ignore_ascii_case("Weight") => Some(Self::Weight),
            _ => None,
        }
    }

    pub fn standard_name(&self) -> &'static str {
        match self {
            AxisName::Weight => "Weight",
        }
    }
}

#[derive(Clone, Debug)]
pub struct VariationAxis {
    pub name: String,
    pub axis: Option<AxisName>,
    pub tag: hb_tag_t,
    pub range: RangeInclusive<f32>,
    pub default: f32,
    pub is_hidden: bool,
}
impl VariationAxis {
    pub(crate) fn pin(&self, face: &mut FontFace, input: &mut SubsetInput) {
        unsafe {
            hb_subset_input_pin_axis_location(
                input.as_raw(),
                face.as_raw(),
                self.tag,
                self.default,
            );
        }
    }
}

unsafe fn load_string(face: *mut hb_face_t, name: hb_ot_name_id_t) -> String {
    let mut buf = vec![0u8; 128];
    loop {
        let mut size = buf.len() as c_uint;
        hb_ot_name_get_utf8(face, name, HB_LANGUAGE_INVALID, &mut size, buf.as_mut_ptr() as *mut _);
        if size as usize != buf.len() {
            let name = &buf[..size as usize];
            return String::from_utf8_lossy(name).to_string();
        } else {
            buf = vec![0; buf.len() * 2];
        }
    }
}
unsafe fn load_axis_info(face: *mut hb_face_t, axis: hb_ot_var_axis_info_t) -> VariationAxis {
    let mut name = load_string(face, axis.name_id);
    let axis_name = AxisName::of(&name);
    if let Some(axis) = axis_name {
        name = axis.standard_name().to_string();
    }
    VariationAxis {
        name,
        axis: axis_name,
        tag: axis.tag,
        range: axis.min_value..=axis.max_value,
        default: axis.max_value,
        is_hidden: (axis.flags & hb_ot_var_axis_flags_t_HB_OT_VAR_AXIS_FLAG_HIDDEN) != 0,
    }
}

pub fn get_variation_axises(face: &FontFace) -> Vec<VariationAxis> {
    unsafe {
        let face = face.as_raw();

        let count = hb_ot_var_get_axis_count(face) as usize;
        if count == 0 {
            Vec::new()
        } else {
            let mut data = vec![
                hb_ot_var_axis_info_t {
                    axis_index: 0,
                    tag: 0,
                    name_id: hb_ot_name_id_t(0),
                    flags: 0,
                    min_value: 0.0,
                    default_value: 0.0,
                    max_value: 0.0,
                    reserved: 0,
                };
                count
            ];

            let mut ct_var = count as c_uint;
            hb_ot_var_get_axis_infos(face, 0, &mut ct_var, data.as_mut_ptr());

            let mut vec = Vec::new();
            for axis in data {
                vec.push(load_axis_info(face, axis));
            }
            vec
        }
    }
}