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
//! 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, Tape, Walue};

/// 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> Walue<'l> for Record {
    type Parameter = (u64, &'l Operations, &'l CharacterStrings);

    fn read<T: Tape>(
        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);
        tape.jump(position + offset as u64)?;
        let encoding = tape.take_given(character_strings)?;
        let offset = get!(@single top_operations, FDArray);
        tape.jump(position + offset as u64)?;
        let operations: Vec<_> = (&tape.take::<Dictionaries>()?).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> Walue<'l> for RecordInner {
    type Parameter = (u64, &'l Operations);

    fn read<T: Tape>(tape: &mut T, (position, top_operations): Self::Parameter) -> Result<Self> {
        let (size, offset) = get!(@double top_operations, Private);
        tape.jump(position + offset as u64)?;
        let chunk = tape.take_given::<Vec<u8>>(size as usize)?;
        let operations = Cursor::new(chunk).take::<Operations>()?;
        let subroutines = match get!(@try @single operations, Subrs) {
            Some(another_offset) => {
                tape.jump(position + offset as u64 + another_offset as u64)?;
                tape.take()?
            }
            _ => Default::default(),
        };
        Ok(Self {
            operations,
            subroutines,
        })
    }
}

impl<'l> Walue<'l> for Encoding {
    type Parameter = &'l CharacterStrings;

    fn read<T: Tape>(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 unsupported format of the glyph-to-dictionary encoding ({})",
                format,
            ),
        })
    }
}

impl<'l> Walue<'l> for Encoding0 {
    type Parameter = &'l CharacterStrings;

    fn read<T: Tape>(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)?,
        })
    }
}