1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! The character-ID-keyed fonts.

use std::io::Cursor;

use crate::compact1::index::{CharacterStrings, Dictionaries, Subroutines};
use crate::compact1::{GlyphID, Number, Operations, Operator, StringID};
use crate::Result;

/// A character-ID-keyed record in a font set.
#[derive(Clone, Debug)]
pub struct Record {
    pub registry: StringID,
    pub ordering: StringID,
    pub supplement: Number,
    pub encoding: Encoding,
    pub operations: Vec<Operations>,
    pub records: Vec<RecordInner>,
}

/// A record in a character-ID-keyed record in a font set.
#[derive(Clone, Debug)]
pub struct RecordInner {
    pub operations: Operations,
    pub subroutines: Subroutines,
}

/// An encoding of a glyph-to-dictionary mapping.
#[derive(Clone, Debug)]
pub enum Encoding {
    /// Format 0.
    Format0(Encoding0),
    /// Format 3.
    Format3(Encoding3),
}

/// A glyph-to-dictionary encoding in format 0.
#[derive(Clone, Debug)]
pub struct Encoding0 {
    pub format: u8,              // format
    pub dictionary_ids: Vec<u8>, // fds
}

table! {
    #[doc = "A glyph-to-dictionary encoding in format 3."]
    pub Encoding3 {
        format      (u8 ) = { 3 }, // format
        range_count (u16), // nRanges

        ranges (Vec<Range3>) |this, tape| { // Range3
            tape.take_given(this.range_count as usize)
        },

        glyph_count (u16), // sentinel
    }
}

table! {
    #[doc = "A range of a glyph-to-dictionary encoding in format 3."]
    #[derive(Copy)]
    pub Range3 {
        first_glyph_id (GlyphID), // first
        dictionary_id  (u8     ), // fd
    }
}

impl<'l> crate::walue::Read<'l> for Record {
    type Parameter = (u64, &'l Operations, &'l CharacterStrings);

    fn read<T: crate::tape::Read>(
        tape: &mut T,
        (position, top_operations, character_strings): Self::Parameter,
    ) -> Result<Self> {
        let operands = match top_operations.get(Operator::ROS) {
            Some(operands) if operands.len() == 3 => operands,
            _ => raise!("found a malformed character-ID-keyed record"),
        };
        let offset = get!(@single top_operations, FDSelect);
        let encoding = jump_take_given!(@unwrap tape, position, offset, character_strings);
        let offset = get!(@single top_operations, FDArray);
        let operations: Dictionaries = jump_take!(@unwrap tape, position, offset);
        let operations: Vec<_> = (&operations).try_into()?;
        let mut records = vec![];
        for top_operations in operations.iter() {
            records.push(tape.take_given((position, top_operations))?);
        }
        Ok(Self {
            registry: operands[0].try_into()?,
            ordering: operands[1].try_into()?,
            supplement: operands[2],
            encoding,
            operations,
            records,
        })
    }
}

impl<'l> crate::walue::Read<'l> for RecordInner {
    type Parameter = (u64, &'l Operations);

    fn read<T: crate::tape::Read>(
        tape: &mut T,
        (position, top_operations): Self::Parameter,
    ) -> Result<Self> {
        use crate::tape::Read;

        let (size, offset) = get!(@double top_operations, Private);
        let chunk: Vec<u8> = jump_take_given!(@unwrap tape, position, offset, size as usize);
        let operations = Cursor::new(chunk).take::<Operations>()?;
        let subroutines = match get!(@try @single operations, Subrs) {
            Some(another_offset) => jump_take!(@unwrap tape, position, offset + another_offset),
            _ => Default::default(),
        };
        Ok(Self {
            operations,
            subroutines,
        })
    }
}

impl<'l> crate::walue::Read<'l> for Encoding {
    type Parameter = &'l CharacterStrings;

    fn read<T: crate::tape::Read>(
        tape: &mut T,
        character_strings: Self::Parameter,
    ) -> Result<Self> {
        Ok(match tape.peek::<u8>()? {
            0 => Encoding::Format0(tape.take_given(character_strings)?),
            3 => Encoding::Format3(tape.take()?),
            format => {
                raise!("found an unknown format of the glyph-to-dictionary encoding ({format})")
            }
        })
    }
}

impl<'l> crate::walue::Read<'l> for Encoding0 {
    type Parameter = &'l CharacterStrings;

    fn read<T: crate::tape::Read>(
        tape: &mut T,
        character_strings: Self::Parameter,
    ) -> Result<Self> {
        let format = tape.take()?;
        debug_assert_eq!(format, 0);
        Ok(Self {
            format,
            dictionary_ids: tape.take_given(character_strings.count as usize)?,
        })
    }
}