read-fonts 0.46.0

Reading OpenType font files.
Documentation
use super::*;
use crate::FontData;
use font_test_data::bebuffer::BeBuffer;
use font_types::{GlyphId24, Uint24};

fn coverage(gid: u32) -> Vec<u8> {
    BeBuffer::new()
        .push(3u16)
        .push(Uint24::new(1))
        .push(GlyphId24::new(gid))
        .to_vec()
}

fn font(kind: u16, subtable: &[u8]) -> Vec<u8> {
    BeBuffer::new()
        .push(1u16)
        .push(0u16)
        .extend([0u16; 2])
        .push(10u16)
        .push(1u16)
        .push(4u16)
        .push(kind)
        .push(0u16)
        .push(1u16)
        .push(8u16)
        .extend(subtable.iter().copied())
        .to_vec()
}

fn close(kind: u16, subtable: &[u8], inputs: &[u32]) -> Result<Vec<u16>, ReadError> {
    let bytes = font(kind, subtable);
    let gpos = Gpos::read(FontData::new(&bytes)).unwrap();
    let mut lookups = [0].into_iter().collect();
    gpos.closure_lookups(
        &inputs.iter().copied().map(GlyphId::new).collect(),
        &mut lookups,
    )?;
    Ok(lookups.iter().collect())
}

fn fixtures() -> Vec<(u16, Vec<u8>, bool)> {
    vec![
        (
            1,
            BeBuffer::new()
                .push(3u16)
                .push(10u32)
                .push(4u16)
                .push(20i16)
                .extend(coverage(65536))
                .to_vec(),
            false,
        ),
        (
            1,
            BeBuffer::new()
                .push(4u16)
                .push(13u32)
                .push(4u16)
                .push(Uint24::new(1))
                .push(20i16)
                .extend(coverage(65536))
                .to_vec(),
            false,
        ),
        (
            2,
            BeBuffer::new()
                .push(3u16)
                .push(16u32)
                .extend([0u16; 2])
                .push(Uint24::new(1))
                .push(Uint24::new(24))
                .extend(coverage(65536))
                .push(Uint24::new(1))
                .push(GlyphId24::new(70000))
                .to_vec(),
            true,
        ),
        (
            2,
            BeBuffer::new()
                .push(4u16)
                .push(22u32)
                .extend([0u16; 2])
                .push(30u32)
                .push(41u32)
                .extend([2u16; 2])
                .extend(coverage(65536))
                .push(3u16)
                .push(GlyphId24::new(65536))
                .push(Uint24::new(1))
                .push(Uint24::new(1))
                .push(3u16)
                .push(GlyphId24::new(70000))
                .push(Uint24::new(1))
                .push(Uint24::new(1))
                .to_vec(),
            true,
        ),
        (
            3,
            BeBuffer::new()
                .push(2u16)
                .push(15u32)
                .push(Uint24::new(1))
                .extend([Uint24::new(0); 2])
                .extend(coverage(65536))
                .to_vec(),
            false,
        ),
        (
            4,
            BeBuffer::new()
                .push(2u16)
                .push(20u32)
                .push(28u32)
                .push(1u16)
                .extend([0u32; 2])
                .extend(coverage(65536))
                .extend(coverage(70000))
                .to_vec(),
            true,
        ),
        (
            5,
            BeBuffer::new()
                .push(2u16)
                .push(20u32)
                .push(28u32)
                .push(1u16)
                .extend([0u32; 2])
                .extend(coverage(65536))
                .extend(coverage(70000))
                .to_vec(),
            true,
        ),
        (
            6,
            BeBuffer::new()
                .push(2u16)
                .push(20u32)
                .push(28u32)
                .push(1u16)
                .extend([0u32; 2])
                .extend(coverage(65536))
                .extend(coverage(70000))
                .to_vec(),
            true,
        ),
    ]
}

#[test]
fn extended_positioning_lookup_closure_and_extensions() {
    for (kind, bytes, both) in fixtures() {
        assert_eq!(close(kind, &bytes, &[65536, 70000]).unwrap(), [0]);
        assert!(close(kind, &bytes, &[0, 4464]).unwrap().is_empty());
        assert_eq!(
            close(kind, &bytes, &[65536]).unwrap(),
            if both { vec![] } else { vec![0] }
        );
        let extension = BeBuffer::new()
            .push(1u16)
            .push(kind)
            .push(8u32)
            .extend(bytes.iter().copied());
        assert_eq!(close(9, &extension, &[65536, 70000]).unwrap(), [0]);
        let mut null = bytes.clone();
        null[2..6].fill(0);
        assert!(close(kind, &null, &[65536, 70000]).unwrap().is_empty());
        null[2..6].fill(0xff);
        assert!(close(kind, &null, &[65536, 70000]).is_err());
    }
}

#[test]
fn extended_pair_closure_preserves_large_set_indices_and_offsets() {
    let count = 65537u32;
    let coverage_offset = 13 + count * 3;
    let set_offset = coverage_offset + 14;
    let bytes = BeBuffer::new()
        .push(3u16)
        .push(coverage_offset)
        .extend([0u16; 2])
        .push(Uint24::new(count))
        .extend((0..count).map(|i| Uint24::new(if i == count - 1 { set_offset } else { 0 })))
        .push(4u16)
        .push(Uint24::new(1))
        .extend([0, 65536, 0].map(Uint24::new))
        .push(Uint24::new(1))
        .push(GlyphId24::new(0xffffff))
        .to_vec();
    assert_eq!(close(2, &bytes, &[65536, 0xffffff]).unwrap(), [0]);
    assert!(close(2, &bytes, &[0, 0xffffff]).unwrap().is_empty());
    let mut null = bytes.clone();
    let index = 13 + 65536 * 3;
    null[index..index + 3].fill(0);
    assert!(close(2, &null, &[65536, 0xffffff]).unwrap().is_empty());
    null[index..index + 3].fill(0xff);
    assert!(close(2, &null, &[65536, 0xffffff]).is_err());
}

#[test]
fn extended_pair_closure_preserves_large_pair_counts() {
    let count = 65537u32;
    let bytes = BeBuffer::new()
        .push(3u16)
        .push(16u32)
        .extend([0u16; 2])
        .push(Uint24::new(1))
        .push(Uint24::new(24))
        .extend(coverage(70000))
        .push(Uint24::new(count))
        .extend((0..count).map(GlyphId24::new))
        .to_vec();
    assert_eq!(close(2, &bytes, &[65536, 70000]).unwrap(), [0]);
    assert!(close(2, &bytes, &[70000]).unwrap().is_empty());
}