1use crate::parser::{FromData, FromSlice, LazyArray16, LazyOffsetArray16, Offset, Offset16, Offset32, Stream};
2
3pub type LookupList<'a> = LazyOffsetArray16<'a, Lookup<'a>>;
5
6#[derive(Clone, Copy, Debug)]
8pub struct Lookup<'a> {
9 pub flags: LookupFlags,
11 pub subtables: LookupSubtables<'a>,
13 pub mark_filtering_set: Option<u16>,
15}
16
17impl<'a> FromSlice<'a> for Lookup<'a> {
18 fn parse(data: &'a [u8]) -> Option<Self> {
19 let mut s = Stream::new(data);
20 let kind = s.read::<u16>()?;
21 let flags = s.read::<LookupFlags>()?;
22 let count = s.read::<u16>()?;
23 let offsets = s.read_array16(count)?;
24
25 let mut mark_filtering_set: Option<u16> = None;
26 if flags.use_mark_filtering_set() {
27 mark_filtering_set = Some(s.read::<u16>()?);
28 }
29
30 Some(Self {
31 flags,
32 subtables: LookupSubtables { kind, data, offsets },
33 mark_filtering_set,
34 })
35 }
36}
37
38pub trait LookupSubtable<'a>: Sized {
42 fn parse(data: &'a [u8], kind: u16) -> Option<Self>;
44}
45
46#[derive(Clone, Copy)]
48pub struct LookupSubtables<'a> {
49 kind: u16,
50 data: &'a [u8],
51 offsets: LazyArray16<'a, Offset16>,
52}
53
54impl core::fmt::Debug for LookupSubtables<'_> {
55 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
56 write!(f, "LookupSubtables {{ ... }}")
57 }
58}
59
60impl<'a> LookupSubtables<'a> {
61 #[inline]
63 pub fn len(&self) -> u16 {
64 self.offsets.len()
65 }
66
67 pub fn get<T: LookupSubtable<'a>>(&self, index: u16) -> Option<T> {
75 let offset = self.offsets.get(index)?.to_usize();
76 let data = self.data.get(offset..)?;
77 T::parse(data, self.kind)
78 }
79
80 pub fn into_iter<T: LookupSubtable<'a>>(self) -> LookupSubtablesIter<'a, T> {
84 LookupSubtablesIter {
85 data: self,
86 index: 0,
87 data_type: core::marker::PhantomData,
88 }
89 }
90}
91
92#[allow(missing_debug_implementations)]
94pub struct LookupSubtablesIter<'a, T: LookupSubtable<'a>> {
95 data: LookupSubtables<'a>,
96 index: u16,
97 data_type: core::marker::PhantomData<T>,
98}
99
100impl<'a, T: LookupSubtable<'a>> Iterator for LookupSubtablesIter<'a, T> {
101 type Item = T;
102
103 fn next(&mut self) -> Option<Self::Item> {
104 if self.index < self.data.len() {
105 self.index += 1;
106 self.data.get(self.index - 1)
107 } else {
108 None
109 }
110 }
111}
112
113#[allow(missing_docs)]
115#[derive(Clone, Copy, Debug)]
116pub struct LookupFlags(pub u16);
117
118#[allow(missing_docs)]
119impl LookupFlags {
120 #[inline] pub fn right_to_left(self) -> bool { self.0 & 0x0001 != 0 }
121 #[inline] pub fn ignore_base_glyphs(self) -> bool { self.0 & 0x0002 != 0 }
122 #[inline] pub fn ignore_ligatures(self) -> bool { self.0 & 0x0004 != 0 }
123 #[inline] pub fn ignore_marks(self) -> bool { self.0 & 0x0008 != 0 }
124 #[inline] pub fn ignore_flags(self) -> bool { self.0 & 0x000E != 0 }
125 #[inline] pub fn use_mark_filtering_set(self) -> bool { self.0 & 0x0010 != 0 }
126 #[inline] pub fn mark_attachment_type(self) -> u8 { (self.0 & 0xFF00) as u8 }
127}
128
129impl FromData for LookupFlags {
130 const SIZE: usize = 2;
131
132 #[inline]
133 fn parse(data: &[u8]) -> Option<Self> {
134 u16::parse(data).map(Self)
135 }
136}
137
138pub(crate) fn parse_extension_lookup<'a, T: 'a>(
139 data: &'a [u8],
140 parse: impl FnOnce(&'a [u8], u16) -> Option<T>,
141) -> Option<T> {
142 let mut s = Stream::new(data);
143 let format = s.read::<u16>()?;
144 match format {
145 1 => {
146 let kind = s.read::<u16>()?;
147 let offset = s.read::<Offset32>()?.to_usize();
148 parse(data.get(offset..)?, kind)
149 }
150 _ => None,
151 }
152}