mirx 0.43.0

MIRX binary image format — flat & chunk-based container for ahead-of-time UI assets
Documentation
use super::*;
use crate::{
    Fixed,
    coding::Rle,
    font::{FontGlyphs, FontRepresentation, FontView},
};

fn asset(check: impl FnOnce(FontAsset<'_>)) {
    let map = GlyphMap::glyph_major(2, 2, 2).unwrap();
    let raw = RawGlyphs::builder(map, SampleLayout::A8)
        .build(&[7; 8])
        .unwrap();
    let image = EncodedImageAsset::new(
        SurfaceDescriptor::new(2, 4, SampleLayout::A8, ColorDescription::NONE).unwrap(),
        Rle::new().record(),
        &[0x87, 42],
    )
    .with_input_alignment(crate::ByteAlignment::new(64).unwrap())
    .with_integrity(DataIntegrity::Indexed(&[1, 2]));
    let surfaces = [
        GlyphSurfaceAsset::raw(raw),
        GlyphSurfaceAsset::Encoded { map, image },
    ];
    let metrics = [GlyphMetrics::default(); 2];
    let line = LineMetrics::new(Fixed::ONE, Fixed::ZERO, Fixed::ONE).unwrap();
    let representations = [
        RepresentationAsset::new(
            FontRepresentation::coverage(8, 12, 8).unwrap(),
            0,
            line,
            &metrics,
        ),
        RepresentationAsset::new(
            FontRepresentation::signed_distance(8, 3, 24, 17, 48, 8).unwrap(),
            1,
            line,
            &metrics,
        ),
    ];
    check(FontAsset::new(&['A', 'B'], &representations, &surfaces));
}

#[test]
fn owned_metadata_edits_preserve_encoded_data_and_shared_ordinals() {
    let mut result = None;
    asset(|asset| {
        let owned = Font::from_asset(asset, &PayloadLimits::EMBEDDED).unwrap();
        assert_eq!(owned.encode().unwrap(), asset.encode().unwrap());
        result = Some(owned);
    });
    let mut font = result.unwrap();
    let source = font.encode().unwrap();
    assert!(font.matches_payload(&source).unwrap());
    let stored = font.surface(1).unwrap().data().to_vec();
    assert_eq!(stored, [0x87, 42]);
    let metric = GlyphMetrics::new(
        Fixed::from_ratio(-17, 256),
        Fixed::from_ratio(-65, 256),
        Fixed::from_ratio(513, 256),
    );
    font.glyph_metrics_mut(1).unwrap()[0] = metric;
    let line =
        LineMetrics::new(Fixed::from_int(4), Fixed::from_int(-1), Fixed::from_int(5)).unwrap();
    font.set_line_metrics(1, line).unwrap();
    font.set_codepoint(1, '中').unwrap();
    assert!(font.set_codepoint(0, '中').is_err());
    assert!(font.set_codepoint(usize::MAX, 'x').is_err());
    assert!(font.set_line_metrics(usize::MAX, line).is_err());
    assert!(font.glyph_metrics_mut(usize::MAX).is_none());
    assert_eq!(font.codepoints(), ['A', '中']);
    assert_eq!(font.surface(1).unwrap().data(), stored);
    font.preflight(&PayloadLimits::EMBEDDED).unwrap();
    let bytes = font.encode().unwrap();
    let view = FontView::open_at(&bytes, 0, &PayloadLimits::EMBEDDED).unwrap();
    view.preflight(&PayloadLimits::EMBEDDED).unwrap();
    assert_eq!(view.tables().get(1).unwrap().metrics().get(0), Some(metric));
    assert_eq!(view.tables().get(1).unwrap().metrics().line_metrics(), line);
    assert!(matches!(view.glyphs(1), Some(FontGlyphs::Encoded(_))));
    let mut output = alloc::vec![0xcc; font.encoded_len().unwrap() + 8];
    let len = font.encode_into(&mut output).unwrap();
    assert_eq!(&output[..len], bytes);
    assert_eq!(&output[len..], &[0xcc; 8]);
}

#[test]
fn owning_limits_cover_metadata_and_encoded_storage_before_allocation() {
    asset(|asset| {
        assert!(matches!(
            Font::from_asset(asset, &PayloadLimits::EMBEDDED.with_max_decoded_bytes(8)),
            Err(FontError::OwnedBytesLimitExceeded { .. })
        ));
        let needed = (8..4096)
            .find(|&limit| {
                Font::from_asset(
                    asset,
                    &PayloadLimits::EMBEDDED.with_max_decoded_bytes(limit),
                )
                .is_ok()
            })
            .unwrap();
        assert!(
            Font::from_asset(
                asset,
                &PayloadLimits::EMBEDDED.with_max_decoded_bytes(needed - 1)
            )
            .is_err()
        );
        let font = Font::from_asset(
            asset,
            &PayloadLimits::EMBEDDED.with_max_decoded_bytes(needed),
        )
        .unwrap();
        assert_eq!(font.representation_count(), 2);
        assert_eq!(font.surface_count(), 2);
        assert!(font.surface(usize::MAX).is_none());
        assert!(font.representation(usize::MAX).is_none());
    });
}

#[test]
fn wire_owned_round_trip_preserves_raw_and_encoded_integrity_partitions() {
    asset(|asset| {
        let original = asset.encode().unwrap();
        let font = Font::decode_with_limits(&original, &PayloadLimits::EMBEDDED).unwrap();
        assert_eq!(font.encode().unwrap(), original);
        assert!(font.matches_payload(&original).unwrap());
        assert_eq!(
            font.surface(0).unwrap().integrity(),
            DataIntegrity::Indexed(&[8])
        );
        assert_eq!(
            font.surface(1).unwrap().integrity(),
            DataIntegrity::Indexed(&[1, 2])
        );
        for limits in [
            PayloadLimits::EMBEDDED.with_max_decoded_bytes(8),
            PayloadLimits::EMBEDDED.with_max_raster_work(0),
            PayloadLimits::EMBEDDED.with_max_font_glyphs(1),
        ] {
            assert!(Font::decode_with_limits(&original, &limits).is_err());
        }
    });
    let chars = ['A', 'B'];
    let map = GlyphMap::glyph_major(2, 2, 2).unwrap();
    let raw = RawGlyphs::builder(map, SampleLayout::A8)
        .build(&[7; 8])
        .unwrap();
    let metrics = [GlyphMetrics::default(); 2];
    let line = LineMetrics::new(Fixed::ONE, Fixed::ZERO, Fixed::ONE).unwrap();
    let representations = [RepresentationAsset::new(
        FontRepresentation::coverage(8, 12, 8).unwrap(),
        0,
        line,
        &metrics,
    )];
    let surfaces = [GlyphSurfaceAsset::raw(raw).with_integrity(DataIntegrity::Indexed(&[4, 8]))];
    let asset = FontAsset::new(&chars, &representations, &surfaces);
    let original = asset.encode().unwrap();
    let font = Font::decode_with_limits(&original, &PayloadLimits::EMBEDDED).unwrap();
    assert_eq!(font.encode().unwrap(), original);
    assert_eq!(
        font.surface(0).unwrap().integrity(),
        DataIntegrity::Indexed(&[4, 8])
    );
    let bad_surfaces = [GlyphSurfaceAsset::raw(raw).with_integrity(DataIntegrity::Indexed(&[3]))];
    let bad = FontAsset::new(&chars, &representations, &bad_surfaces);
    let mut output = [0xcc; 512];
    assert!(matches!(
        bad.encode_into(&mut output),
        Err(FontError::Integrity(_))
    ));
    assert_eq!(output, [0xcc; 512]);
}