merman-render 0.4.2

Headless layout + SVG renderer for Mermaid (parity-focused; upstream SVG goldens).
Documentation
// This file is generated by `xtask gen-gantt-text-overrides`.
//
// Mermaid baseline: 11.12.2
// Source: fixtures/upstream-svgs/gantt/*.svg

const GANTT_DEFAULT_TASK_FONT_KEY: &str = "trebuchetms,verdana,arial,sans-serif";

#[allow(dead_code)]
fn font_size_key(font_size: f64) -> u16 {
    if !(font_size.is_finite() && font_size > 0.0) {
        return 0;
    }
    let k = (font_size * 100.0).round();
    if !(k.is_finite() && k >= 0.0 && k <= (u16::MAX as f64)) {
        return 0;
    }
    k as u16
}

static TASK_TEXT_BBOX_WIDTH_OVERRIDES_PX: &[(u16, &str, f64)] = &[
    (1100, "#Design jison grammar", 113.41650390625),
    (1100, ";Design jison grammar", 110.68701171875),
    (1100, "A", 9.0),
    (1100, "Active task", 55.7265625),
    (1100, "B", 7.0),
    (1100, "Build", 24.75),
    (1100, "C", 7.0),
    (1100, "Calling a callback", 86.99072265625),
    (1100, "Completed task", 77.3818359375),
    (1100, "Ctor task", 45.0263671875),
    (1100, "Design", 31.875),
    (1100, "Future task", 56.337890625),
    (1100, "London Trip 2", 66.671875),
    (1100, "Midnight", 43.748046875),
    (1100, "Noon", 24.84375),
    (1100, "One PM", 37.86962890625),
    (1100, "Proto task", 49.9677734375),
    (1100, "Task", 22.24853515625),
    (1100, "Task1", 27.578125),
    (1100, "Task2", 27.796875),
    (1100, "Visit mermaidjs", 78.27880859375),
    (1100, "days", 22.33251953125),
    (1100, "hours", 27.19873046875),
    (1100, "minutes", 39.64892578125),
    (1100, "ms", 14.130859375),
    (1100, "seconds", 38.93994140625),
    (1100, "t1", 10.140625),
    (1100, "task A", 30.8486328125),
    (1100, "task B", 30.45556640625),
    (1100, "task C", 30.45556640625),
    (1100, "task D", 30.45556640625),
    (1100, "task1", 25.921875),
    (1100, "task2", 26.1416015625),
    (1100, "task3", 26.1416015625),
    (1100, "task4", 26.1416015625),
    (1100, "test1", 24.953125),
    (1100, "test2", 25.1748046875),
    (1100, "test3", 25.1748046875),
    (1100, "test4", 25.1748046875),
    (1100, "test5", 25.1748046875),
    (1100, "test6", 25.1748046875),
    (1100, "test7", 25.1748046875),
    (1100, "y68", 18.193359375),
    (1100, "y69", 18.193359375),
];

pub fn lookup_task_text_bbox_width_px(font_size: f64, text: &str) -> Option<f64> {
    let fs = font_size_key(font_size);
    if fs == 0 || text.is_empty() {
        return None;
    }
    let mut lo = 0usize;
    let mut hi = TASK_TEXT_BBOX_WIDTH_OVERRIDES_PX.len();
    while lo < hi {
        let mid = (lo + hi) / 2;
        let (k_fs, k_text, w) = TASK_TEXT_BBOX_WIDTH_OVERRIDES_PX[mid];
        match k_fs.cmp(&fs) {
            std::cmp::Ordering::Equal => match k_text.cmp(text) {
                std::cmp::Ordering::Equal => return Some(w),
                std::cmp::Ordering::Less => lo = mid + 1,
                std::cmp::Ordering::Greater => hi = mid,
            },
            std::cmp::Ordering::Less => lo = mid + 1,
            std::cmp::Ordering::Greater => hi = mid,
        }
    }
    None
}

fn normalize_font_key(s: &str) -> String {
    s.chars()
        .filter_map(|ch| {
            if ch.is_whitespace() || ch == '"' || ch == '\'' || ch == ';' {
                None
            } else {
                Some(ch.to_ascii_lowercase())
            }
        })
        .collect()
}

pub fn lookup_task_text_bbox_width_override_px(
    font_family: &str,
    font_size: f64,
    text: &str,
) -> Option<f64> {
    if normalize_font_key(font_family) != GANTT_DEFAULT_TASK_FONT_KEY {
        return None;
    }
    lookup_task_text_bbox_width_px(font_size, text)
}