1 //! OpenType Layout common table formats
2 
3 #[path = "./lookupflag.rs"]
4 mod lookupflag;
5 
6 use core::cmp::Ordering;
7 
8 pub use lookupflag::LookupFlag;
9 
10 #[cfg(test)]
11 #[path = "../tests/layout.rs"]
12 mod spec_tests;
13 
14 include!("../../generated/generated_layout.rs");
15 
16 impl<'a, T: FontRead<'a>> Lookup<'a, T> {
get_subtable(&self, offset: Offset16) -> Result<T, ReadError>17     pub fn get_subtable(&self, offset: Offset16) -> Result<T, ReadError> {
18         self.resolve_offset(offset)
19     }
20 
21     #[cfg(feature = "traversal")]
traverse_lookup_flag(&self) -> traversal::FieldType<'a>22     fn traverse_lookup_flag(&self) -> traversal::FieldType<'a> {
23         self.lookup_flag().to_bits().into()
24     }
25 }
26 
27 /// A trait that abstracts the behaviour of an extension subtable
28 ///
29 /// This is necessary because GPOS and GSUB have different concrete types
30 /// for their extension lookups.
31 pub trait ExtensionLookup<'a, T: FontRead<'a>>: FontRead<'a> {
extension(&self) -> Result<T, ReadError>32     fn extension(&self) -> Result<T, ReadError>;
33 }
34 
35 /// an array of subtables, maybe behind extension lookups
36 ///
37 /// This is used to implement more ergonomic access to lookup subtables for
38 /// GPOS & GSUB lookup tables.
39 pub enum Subtables<'a, T: FontRead<'a>, Ext: ExtensionLookup<'a, T>> {
40     Subtable(ArrayOfOffsets<'a, T>),
41     Extension(ArrayOfOffsets<'a, Ext>),
42 }
43 
44 impl<'a, T: FontRead<'a> + 'a, Ext: ExtensionLookup<'a, T> + 'a> Subtables<'a, T, Ext> {
45     /// create a new subtables array given offests to non-extension subtables
new(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self46     pub(crate) fn new(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
47         Subtables::Subtable(ArrayOfOffsets::new(offsets, data, ()))
48     }
49 
50     /// create a new subtables array given offsets to extension subtables
new_ext(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self51     pub(crate) fn new_ext(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
52         Subtables::Extension(ArrayOfOffsets::new(offsets, data, ()))
53     }
54 
55     /// The number of subtables in this collection
len(&self) -> usize56     pub fn len(&self) -> usize {
57         match self {
58             Subtables::Subtable(inner) => inner.len(),
59             Subtables::Extension(inner) => inner.len(),
60         }
61     }
62 
is_empty(&self) -> bool63     pub fn is_empty(&self) -> bool {
64         self.len() == 0
65     }
66 
67     /// Return the subtable at the given index
get(&self, idx: usize) -> Result<T, ReadError>68     pub fn get(&self, idx: usize) -> Result<T, ReadError> {
69         match self {
70             Subtables::Subtable(inner) => inner.get(idx),
71             Subtables::Extension(inner) => inner.get(idx).and_then(|ext| ext.extension()),
72         }
73     }
74 
75     /// Return an iterator over all the subtables in the collection
iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a76     pub fn iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a {
77         let (left, right) = match self {
78             Subtables::Subtable(inner) => (Some(inner.iter()), None),
79             Subtables::Extension(inner) => (
80                 None,
81                 Some(inner.iter().map(|ext| ext.and_then(|ext| ext.extension()))),
82             ),
83         };
84         left.into_iter()
85             .flatten()
86             .chain(right.into_iter().flatten())
87     }
88 }
89 
90 /// An enum for different possible tables referenced by [Feature::feature_params_offset]
91 pub enum FeatureParams<'a> {
92     StylisticSet(StylisticSetParams<'a>),
93     Size(SizeParams<'a>),
94     CharacterVariant(CharacterVariantParams<'a>),
95 }
96 
97 impl ReadArgs for FeatureParams<'_> {
98     type Args = Tag;
99 }
100 
101 impl<'a> FontReadWithArgs<'a> for FeatureParams<'a> {
read_with_args(bytes: FontData<'a>, args: &Tag) -> Result<FeatureParams<'a>, ReadError>102     fn read_with_args(bytes: FontData<'a>, args: &Tag) -> Result<FeatureParams<'a>, ReadError> {
103         match *args {
104             t if t == Tag::new(b"size") => SizeParams::read(bytes).map(Self::Size),
105             // to whoever is debugging this dumb bug I wrote: I'm sorry.
106             t if &t.to_raw()[..2] == b"ss" => {
107                 StylisticSetParams::read(bytes).map(Self::StylisticSet)
108             }
109             t if &t.to_raw()[..2] == b"cv" => {
110                 CharacterVariantParams::read(bytes).map(Self::CharacterVariant)
111             }
112             // NOTE: what even is our error condition here? an offset exists but
113             // we don't know the tag?
114             _ => Err(ReadError::InvalidFormat(0xdead)),
115         }
116     }
117 }
118 
119 #[cfg(feature = "traversal")]
120 impl<'a> SomeTable<'a> for FeatureParams<'a> {
type_name(&self) -> &str121     fn type_name(&self) -> &str {
122         match self {
123             FeatureParams::StylisticSet(table) => table.type_name(),
124             FeatureParams::Size(table) => table.type_name(),
125             FeatureParams::CharacterVariant(table) => table.type_name(),
126         }
127     }
128 
get_field(&self, idx: usize) -> Option<Field<'a>>129     fn get_field(&self, idx: usize) -> Option<Field<'a>> {
130         match self {
131             FeatureParams::StylisticSet(table) => table.get_field(idx),
132             FeatureParams::Size(table) => table.get_field(idx),
133             FeatureParams::CharacterVariant(table) => table.get_field(idx),
134         }
135     }
136 }
137 
138 impl FeatureTableSubstitutionRecord {
alternate_feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError>139     pub fn alternate_feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
140         self.alternate_feature_offset()
141             .resolve_with_args(data, &Tag::new(b"NULL"))
142     }
143 }
144 
145 impl<'a> CoverageTable<'a> {
iter(&self) -> impl Iterator<Item = GlyphId> + 'a146     pub fn iter(&self) -> impl Iterator<Item = GlyphId> + 'a {
147         // all one expression so that we have a single return type
148         let (iter1, iter2) = match self {
149             CoverageTable::Format1(t) => (Some(t.glyph_array().iter().map(|g| g.get())), None),
150             CoverageTable::Format2(t) => {
151                 let iter = t.range_records().iter().flat_map(RangeRecord::iter);
152                 (None, Some(iter))
153             }
154         };
155 
156         iter1
157             .into_iter()
158             .flatten()
159             .chain(iter2.into_iter().flatten())
160     }
161 
162     /// If this glyph is in the coverage table, returns its index
get(&self, gid: GlyphId) -> Option<u16>163     pub fn get(&self, gid: GlyphId) -> Option<u16> {
164         match self {
165             CoverageTable::Format1(sub) => sub.get(gid),
166             CoverageTable::Format2(sub) => sub.get(gid),
167         }
168     }
169 }
170 
171 impl CoverageFormat1<'_> {
172     /// If this glyph is in the coverage table, returns its index
get(&self, gid: GlyphId) -> Option<u16>173     pub fn get(&self, gid: GlyphId) -> Option<u16> {
174         let be_glyph: BigEndian<GlyphId> = gid.into();
175         self.glyph_array()
176             .binary_search(&be_glyph)
177             .ok()
178             .map(|idx| idx as _)
179     }
180 }
181 
182 impl CoverageFormat2<'_> {
183     /// If this glyph is in the coverage table, returns its index
get(&self, gid: GlyphId) -> Option<u16>184     pub fn get(&self, gid: GlyphId) -> Option<u16> {
185         self.range_records()
186             .binary_search_by(|rec| {
187                 if rec.end_glyph_id() < gid {
188                     Ordering::Less
189                 } else if rec.start_glyph_id() > gid {
190                     Ordering::Greater
191                 } else {
192                     Ordering::Equal
193                 }
194             })
195             .ok()
196             .map(|idx| {
197                 let rec = &self.range_records()[idx];
198                 rec.start_coverage_index() + gid.to_u16() - rec.start_glyph_id().to_u16()
199             })
200     }
201 }
202 
203 impl RangeRecord {
iter(&self) -> impl Iterator<Item = GlyphId> + '_204     fn iter(&self) -> impl Iterator<Item = GlyphId> + '_ {
205         (self.start_glyph_id().to_u16()..=self.end_glyph_id().to_u16()).map(GlyphId::new)
206     }
207 }
208 
209 impl DeltaFormat {
value_count(self, start_size: u16, end_size: u16) -> usize210     pub(crate) fn value_count(self, start_size: u16, end_size: u16) -> usize {
211         let range_len = end_size.saturating_add(1).saturating_sub(start_size) as usize;
212         let val_per_word = match self {
213             DeltaFormat::Local2BitDeltas => 8,
214             DeltaFormat::Local4BitDeltas => 4,
215             DeltaFormat::Local8BitDeltas => 2,
216             _ => return 0,
217         };
218 
219         let count = range_len / val_per_word;
220         let extra = (range_len % val_per_word).min(1);
221         count + extra
222     }
223 }
224 
225 // we as a 'format' in codegen, and the generic error type for an invalid format
226 // stores the value as an i64, so we need this conversion.
227 impl From<DeltaFormat> for i64 {
from(value: DeltaFormat) -> Self228     fn from(value: DeltaFormat) -> Self {
229         value as u16 as _
230     }
231 }
232 
233 impl<'a> ClassDefFormat1<'a> {
234     /// Get the class for this glyph id
get(&self, gid: GlyphId) -> u16235     pub fn get(&self, gid: GlyphId) -> u16 {
236         if gid < self.start_glyph_id() {
237             return 0;
238         }
239         let idx = gid.to_u16() - self.start_glyph_id().to_u16();
240         self.class_value_array()
241             .get(idx as usize)
242             .map(|x| x.get())
243             .unwrap_or(0)
244     }
245 
246     /// Iterate over each glyph and its class.
iter(&self) -> impl Iterator<Item = (GlyphId, u16)> + 'a247     pub fn iter(&self) -> impl Iterator<Item = (GlyphId, u16)> + 'a {
248         let start = self.start_glyph_id();
249         self.class_value_array()
250             .iter()
251             .enumerate()
252             .map(move |(i, val)| {
253                 let gid = start.to_u16().saturating_add(i as u16);
254                 (GlyphId::new(gid), val.get())
255             })
256     }
257 }
258 
259 impl<'a> ClassDefFormat2<'a> {
260     /// Get the class for this glyph id
get(&self, gid: GlyphId) -> u16261     pub fn get(&self, gid: GlyphId) -> u16 {
262         let records = self.class_range_records();
263         let ix = match records.binary_search_by(|rec| rec.start_glyph_id().cmp(&gid)) {
264             Ok(ix) => ix,
265             Err(ix) => ix.saturating_sub(1),
266         };
267         if let Some(record) = records.get(ix) {
268             if (record.start_glyph_id()..=record.end_glyph_id()).contains(&gid) {
269                 return record.class();
270             }
271         }
272         0
273     }
274 
275     /// Iterate over each glyph and its class.
iter(&self) -> impl Iterator<Item = (GlyphId, u16)> + 'a276     pub fn iter(&self) -> impl Iterator<Item = (GlyphId, u16)> + 'a {
277         self.class_range_records().iter().flat_map(|range| {
278             let start = range.start_glyph_id().to_u16();
279             let end = range.end_glyph_id().to_u16();
280             (start..=end).map(|gid| (GlyphId::new(gid), range.class()))
281         })
282     }
283 }
284 
285 impl ClassDef<'_> {
286     /// Get the class for this glyph id
get(&self, gid: GlyphId) -> u16287     pub fn get(&self, gid: GlyphId) -> u16 {
288         match self {
289             ClassDef::Format1(table) => table.get(gid),
290             ClassDef::Format2(table) => table.get(gid),
291         }
292     }
293 
294     /// Iterate over each glyph and its class.
295     ///
296     /// This will not include class 0 unless it has been explicitly assigned.
iter(&self) -> impl Iterator<Item = (GlyphId, u16)> + '_297     pub fn iter(&self) -> impl Iterator<Item = (GlyphId, u16)> + '_ {
298         let (one, two) = match self {
299             ClassDef::Format1(inner) => (Some(inner.iter()), None),
300             ClassDef::Format2(inner) => (None, Some(inner.iter())),
301         };
302         one.into_iter().flatten().chain(two.into_iter().flatten())
303     }
304 }
305 
306 impl<'a> Device<'a> {
307     /// Iterate over the decoded values for this device
iter(&self) -> impl Iterator<Item = i8> + 'a308     pub fn iter(&self) -> impl Iterator<Item = i8> + 'a {
309         let format = self.delta_format();
310         let mut n = (self.end_size() - self.start_size()) as usize + 1;
311         let deltas_per_word = match format {
312             DeltaFormat::Local2BitDeltas => 8,
313             DeltaFormat::Local4BitDeltas => 4,
314             DeltaFormat::Local8BitDeltas => 2,
315             _ => 0,
316         };
317 
318         self.delta_value().iter().flat_map(move |val| {
319             let iter = iter_packed_values(val.get(), format, n);
320             n = n.saturating_sub(deltas_per_word);
321             iter
322         })
323     }
324 }
325 
iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8>326 fn iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8> {
327     let mut decoded = [None; 8];
328     let (mask, sign_mask, bits) = match format {
329         DeltaFormat::Local2BitDeltas => (0b11, 0b10, 2usize),
330         DeltaFormat::Local4BitDeltas => (0b1111, 0b1000, 4),
331         DeltaFormat::Local8BitDeltas => (0b1111_1111, 0b1000_0000, 8),
332         _ => (0, 0, 0),
333     };
334 
335     let max_per_word = 16 / bits;
336     #[allow(clippy::needless_range_loop)] // enumerate() feels weird here
337     for i in 0..n.min(max_per_word) {
338         let mask = mask << ((16 - bits) - i * bits);
339         let val = (raw & mask) >> ((16 - bits) - i * bits);
340         let sign = val & sign_mask != 0;
341 
342         let val = if sign {
343             // it is 2023 and I am googling to remember how twos compliment works
344             -((((!val) & mask) + 1) as i8)
345         } else {
346             val as i8
347         };
348         decoded[i] = Some(val)
349     }
350     decoded.into_iter().flatten()
351 }
352 
353 #[cfg(test)]
354 mod tests {
355     use super::*;
356 
357     #[test]
coverage_get_format1()358     fn coverage_get_format1() {
359         // manually generated, corresponding to the glyphs (1, 7, 13, 27, 44);
360         const COV1_DATA: FontData = FontData::new(&[0, 1, 0, 5, 0, 1, 0, 7, 0, 13, 0, 27, 0, 44]);
361 
362         let coverage = CoverageFormat1::read(COV1_DATA).unwrap();
363         assert_eq!(coverage.get(GlyphId::new(1)), Some(0));
364         assert_eq!(coverage.get(GlyphId::new(2)), None);
365         assert_eq!(coverage.get(GlyphId::new(7)), Some(1));
366         assert_eq!(coverage.get(GlyphId::new(27)), Some(3));
367         assert_eq!(coverage.get(GlyphId::new(45)), None);
368     }
369 
370     #[test]
coverage_get_format2()371     fn coverage_get_format2() {
372         // manually generated, corresponding to glyphs (5..10) and (30..40).
373         const COV2_DATA: FontData =
374             FontData::new(&[0, 2, 0, 2, 0, 5, 0, 9, 0, 0, 0, 30, 0, 39, 0, 5]);
375         let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
376         assert_eq!(coverage.get(GlyphId::new(2)), None);
377         assert_eq!(coverage.get(GlyphId::new(7)), Some(2));
378         assert_eq!(coverage.get(GlyphId::new(9)), Some(4));
379         assert_eq!(coverage.get(GlyphId::new(10)), None);
380         assert_eq!(coverage.get(GlyphId::new(32)), Some(7));
381         assert_eq!(coverage.get(GlyphId::new(39)), Some(14));
382         assert_eq!(coverage.get(GlyphId::new(40)), None);
383     }
384 
385     #[test]
classdef_get_format2()386     fn classdef_get_format2() {
387         let classdef = ClassDef::read(FontData::new(
388             font_test_data::gdef::MARKATTACHCLASSDEF_TABLE,
389         ))
390         .unwrap();
391         assert!(matches!(classdef, ClassDef::Format2(..)));
392         let gid_class_pairs = [
393             (616, 1),
394             (617, 1),
395             (618, 1),
396             (624, 1),
397             (625, 1),
398             (626, 1),
399             (652, 2),
400             (653, 2),
401             (654, 2),
402             (655, 2),
403             (661, 2),
404         ];
405         for (gid, class) in gid_class_pairs {
406             assert_eq!(classdef.get(GlyphId::new(gid)), class);
407         }
408         for (gid, class) in classdef.iter() {
409             assert_eq!(classdef.get(gid), class);
410         }
411     }
412 
413     #[test]
delta_decode()414     fn delta_decode() {
415         // these examples come from the spec
416         assert_eq!(
417             iter_packed_values(0x123f, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
418             &[1, 2, 3, -1]
419         );
420 
421         assert_eq!(
422             iter_packed_values(0x5540, DeltaFormat::Local2BitDeltas, 5).collect::<Vec<_>>(),
423             &[1, 1, 1, 1, 1]
424         );
425     }
426 
427     #[test]
delta_decode_all()428     fn delta_decode_all() {
429         // manually generated with write-fonts
430         let bytes: &[u8] = &[0, 7, 0, 13, 0, 3, 1, 244, 30, 245, 101, 8, 42, 0];
431         let device = Device::read(bytes.into()).unwrap();
432         assert_eq!(
433             device.iter().collect::<Vec<_>>(),
434             &[1i8, -12, 30, -11, 101, 8, 42]
435         );
436     }
437 }
438