mmdflux 2.5.0

Render Mermaid diagrams as Unicode text, ASCII, SVG, and MMDS JSON.
Documentation
use super::generated::mmdflux_sans_v1;

#[derive(Debug, Clone, PartialEq)]
pub(crate) struct RecordedMetricsProfile {
    units_per_em: u16,
    advance_scale: f64,
    advances: &'static [(char, u16)],
}

impl RecordedMetricsProfile {
    pub(crate) fn mmdflux_sans_v1() -> Self {
        Self {
            units_per_em: mmdflux_sans_v1::UNITS_PER_EM,
            advance_scale: mmdflux_sans_v1::ADVANCE_SCALE,
            advances: mmdflux_sans_v1::ADVANCES,
        }
    }

    pub(crate) fn measure_scalar_width(&self, font_size: f64, ch: char) -> f64 {
        if ch == '\t' {
            return self.space_width(font_size) * 4.0;
        }
        if ch.is_control() {
            return 0.0;
        }
        if is_combining_mark(ch) {
            return 0.0;
        }
        if let Some(width) = self.recorded_width(font_size, ch) {
            return width;
        }
        if is_space_separator(ch) {
            return self.space_width(font_size);
        }
        if is_known_wide_scalar(ch) {
            return font_size;
        }
        font_size * 0.56
    }

    fn space_width(&self, font_size: f64) -> f64 {
        self.recorded_width(font_size, ' ')
            .unwrap_or(font_size * 0.25)
    }

    fn recorded_width(&self, font_size: f64, ch: char) -> Option<f64> {
        let index = self
            .advances
            .binary_search_by_key(&ch, |(codepoint, _)| *codepoint)
            .ok()?;
        let advance_units = self.advances[index].1;
        Some(advance_units as f64 / self.units_per_em as f64 * font_size * self.advance_scale)
    }
}

fn is_combining_mark(ch: char) -> bool {
    matches!(
        ch as u32,
        0x0300..=0x036F | 0x1AB0..=0x1AFF | 0x1DC0..=0x1DFF | 0x20D0..=0x20FF | 0xFE20..=0xFE2F
    )
}

fn is_space_separator(ch: char) -> bool {
    matches!(
        ch as u32,
        0x00A0 | 0x1680 | 0x2000..=0x200A | 0x202F | 0x205F | 0x3000
    )
}

fn is_known_wide_scalar(ch: char) -> bool {
    matches!(
        ch as u32,
        0x1100..=0x115F
            | 0x2329..=0x232A
            | 0x2E80..=0xA4CF
            | 0xAC00..=0xD7A3
            | 0xF900..=0xFAFF
            | 0xFE10..=0xFE19
            | 0xFE30..=0xFE6F
            | 0xFF00..=0xFF60
            | 0xFFE0..=0xFFE6
            | 0x1F300..=0x1FAFF
    )
}