postscript/compact1/font_set/
character_id_keyed.rs

1//! The character-ID-keyed fonts.
2
3use std::io::Cursor;
4
5use crate::compact1::index::{CharacterStrings, Dictionaries, Subroutines};
6use crate::compact1::{GlyphID, Number, Operations, Operator, StringID};
7use crate::Result;
8
9/// A character-ID-keyed record in a font set.
10#[derive(Clone, Debug)]
11pub struct Record {
12    pub registry: StringID,
13    pub ordering: StringID,
14    pub supplement: Number,
15    pub encoding: Encoding,
16    pub operations: Vec<Operations>,
17    pub records: Vec<RecordInner>,
18}
19
20/// A record in a character-ID-keyed record in a font set.
21#[derive(Clone, Debug)]
22pub struct RecordInner {
23    pub operations: Operations,
24    pub subroutines: Subroutines,
25}
26
27/// An encoding of a glyph-to-dictionary mapping.
28#[derive(Clone, Debug)]
29pub enum Encoding {
30    /// Format 0.
31    Format0(Encoding0),
32    /// Format 3.
33    Format3(Encoding3),
34}
35
36/// A glyph-to-dictionary encoding in format 0.
37#[derive(Clone, Debug)]
38pub struct Encoding0 {
39    pub format: u8,              // format
40    pub dictionary_ids: Vec<u8>, // fds
41}
42
43table! {
44    /// A glyph-to-dictionary encoding in format 3.
45    pub Encoding3 {
46        format      (u8 ) = { 3 }, // format
47        range_count (u16), // nRanges
48
49        ranges (Vec<Range3>) |this, tape| { // Range3
50            tape.take_given(this.range_count as usize)
51        },
52
53        glyph_count (u16), // sentinel
54    }
55}
56
57table! {
58    /// A range of a glyph-to-dictionary encoding in format 3.
59    #[derive(Copy)]
60    pub Range3 {
61        first_glyph_id (GlyphID), // first
62        dictionary_id  (u8     ), // fd
63    }
64}
65
66impl<'l> crate::walue::Read<'l> for Record {
67    type Parameter = (u64, &'l Operations, &'l CharacterStrings);
68
69    fn read<T: crate::tape::Read>(
70        tape: &mut T,
71        (position, top_operations, character_strings): Self::Parameter,
72    ) -> Result<Self> {
73        let operands = match top_operations.get(Operator::ROS) {
74            Some(operands) if operands.len() == 3 => operands,
75            _ => raise!("found a malformed character-ID-keyed record"),
76        };
77        let offset = get!(@single top_operations, FDSelect);
78        let encoding = jump_take_given!(@unwrap tape, position, offset, character_strings);
79        let offset = get!(@single top_operations, FDArray);
80        let operations: Dictionaries = jump_take!(@unwrap tape, position, offset);
81        let operations: Vec<_> = (&operations).try_into()?;
82        let mut records = vec![];
83        for top_operations in operations.iter() {
84            records.push(tape.take_given((position, top_operations))?);
85        }
86        Ok(Self {
87            registry: operands[0].try_into()?,
88            ordering: operands[1].try_into()?,
89            supplement: operands[2],
90            encoding,
91            operations,
92            records,
93        })
94    }
95}
96
97impl<'l> crate::walue::Read<'l> for RecordInner {
98    type Parameter = (u64, &'l Operations);
99
100    fn read<T: crate::tape::Read>(
101        tape: &mut T,
102        (position, top_operations): Self::Parameter,
103    ) -> Result<Self> {
104        use crate::tape::Read;
105
106        let (size, offset) = get!(@double top_operations, Private);
107        let chunk: Vec<u8> = jump_take_given!(@unwrap tape, position, offset, size as usize);
108        let operations = Cursor::new(chunk).take::<Operations>()?;
109        let subroutines = match get!(@try @single operations, Subrs) {
110            Some(another_offset) => jump_take!(@unwrap tape, position, offset + another_offset),
111            _ => Default::default(),
112        };
113        Ok(Self {
114            operations,
115            subroutines,
116        })
117    }
118}
119
120impl<'l> crate::walue::Read<'l> for Encoding {
121    type Parameter = &'l CharacterStrings;
122
123    fn read<T: crate::tape::Read>(
124        tape: &mut T,
125        character_strings: Self::Parameter,
126    ) -> Result<Self> {
127        Ok(match tape.peek::<u8>()? {
128            0 => Encoding::Format0(tape.take_given(character_strings)?),
129            3 => Encoding::Format3(tape.take()?),
130            format => {
131                raise!("found an unknown format of the glyph-to-dictionary encoding ({format})")
132            }
133        })
134    }
135}
136
137impl<'l> crate::walue::Read<'l> for Encoding0 {
138    type Parameter = &'l CharacterStrings;
139
140    fn read<T: crate::tape::Read>(
141        tape: &mut T,
142        character_strings: Self::Parameter,
143    ) -> Result<Self> {
144        let format = tape.take()?;
145        debug_assert_eq!(format, 0);
146        Ok(Self {
147            format,
148            dictionary_ids: tape.take_given(character_strings.count as usize)?,
149        })
150    }
151}