mirui 0.42.0

A lightweight, no_std ECS-driven UI framework for embedded, desktop, and WebAssembly
Documentation
//! End-to-end test against the prebuilt MiSans grayscale atlas.
//!
//! Fixture generated by
//!   `icu bake-font /Users/.../MiSans-Regular.ttf \
//!     --charset "ABC...xyz0..9 .,:;..." --size 16 --bit-depth 4 \
//!     --format gray -O tests/fixtures/`
//!
//! and committed verbatim, so the test pins the host coverage packer +
//! FontChunkHeader prefix + mirx writer against the runtime grayscale
//! reader.

use mirui::render::font::gray::GrayFontProvider;
use mirui::render::font::{FontProvider, GlyphKind};
use mirx::{chunk_type, parse_chunk};

const GRAY_ATLAS_BYTES: &[u8] = include_bytes!("fixtures/misans_gray_16_4bit.mirx");

fn open() -> GrayFontProvider {
    let parsed = parse_chunk(GRAY_ATLAS_BYTES).expect("parse mirx chunk file");
    let payload = parsed
        .chunk_payload(GRAY_ATLAS_BYTES, chunk_type::FONT)
        .expect("FONT chunk payload");
    GrayFontProvider::from_mirx_chunk(payload).expect("parse grayscale header")
}

#[test]
fn header_matches_generation_args() {
    let p = open();
    let h = p.header();
    assert_eq!(h.source_size, 16);
    assert_eq!(h.bit_depth, 4);
    // Grayscale tables carry no distance band.
    assert_eq!(h.spread, 0);
    // 16 × 16 × 4-bit ÷ 8 = 128 bytes per glyph.
    assert_eq!(h.bytes_per_glyph, 128);
    assert_eq!(h.glyph_count, 69);
}

#[test]
fn resolves_ascii_as_grayscale() {
    let p = open();
    for ch in ['A', 'Z', 'a', 'z', '0', '9', '!', '?'] {
        let g = p
            .glyph(ch, 16)
            .unwrap_or_else(|| panic!("missing glyph {ch:?}"));
        match g.kind {
            GlyphKind::Grayscale {
                bpp,
                w,
                h,
                coverage,
                ..
            } => {
                assert_eq!(bpp, 4);
                assert_eq!((w, h), (16, 16));
                assert_eq!(coverage.len(), 128);
            }
            other => panic!("expected Grayscale for {ch:?}, got {other:?}"),
        }
    }
}

#[test]
fn misses_codepoint_outside_charset() {
    let p = open();
    assert!(p.glyph('', 16).is_none());
}

#[test]
fn capital_a_has_coverage_gradient() {
    // A real glyph has anti-aliased edges, so its packed coverage must
    // span more than the two extremes (fully on / fully off).
    let p = open();
    let g = p.glyph('A', 16).expect("A");
    let GlyphKind::Grayscale { coverage, .. } = g.kind else {
        panic!("expected Grayscale");
    };
    let mut buckets = [0u32; 16];
    for &b in coverage {
        buckets[(b & 0x0F) as usize] += 1;
        buckets[(b >> 4) as usize] += 1;
    }
    let nonzero = buckets.iter().filter(|c| **c > 0).count();
    assert!(nonzero >= 3, "expected AA gradient, buckets {buckets:?}");
}