1mod aat;
2mod at;
3mod util;
4
5use super::internal::{self, raw_tag, Bytes, RawFont};
6use super::{FontRef, Tag};
7use crate::text::{Language, Script};
8
9const DFLT: u32 = raw_tag(b"DFLT");
10
11#[derive(Copy, Clone)]
12enum Kind {
13 None,
14 At(u32, u32),
16 Aat(u32, bool),
18}
19
20impl Kind {
21 fn from_font(font: &FontRef) -> Self {
22 let gsub = font.table_offset(raw_tag(b"GSUB"));
23 let gpos = font.table_offset(raw_tag(b"GPOS"));
24 if gsub != 0 || gpos != 0 {
25 return Self::At(gsub, gpos);
26 }
27 let morx = font.table_offset(raw_tag(b"morx"));
28 if morx != 0 {
29 let kern = font.table_offset(raw_tag(b"kern")) != 0
30 || font.table_offset(raw_tag(b"kerx")) != 0;
31 return Self::Aat(morx, kern);
32 }
33 Self::None
34 }
35}
36
37#[derive(Copy, Clone)]
38enum WritingSystemsKind<'a> {
39 None,
40 At(at::WritingSystems<'a>),
41 Aat(aat::OnceItem<'a>),
42}
43
44#[derive(Copy, Clone)]
46pub struct WritingSystems<'a> {
47 kind: WritingSystemsKind<'a>,
48}
49
50impl<'a> WritingSystems<'a> {
51 pub(crate) fn from_font(font: &FontRef<'a>) -> Self {
52 let kind = Kind::from_font(font);
53 WritingSystems {
54 kind: match kind {
55 Kind::At(gsub, gpos) => WritingSystemsKind::At(at::WritingSystems::new(
56 at::Scripts::new(Bytes::new(font.data), gsub, gpos),
57 )),
58 Kind::Aat(morx, kern) => WritingSystemsKind::Aat(Some(aat::Item {
59 chains: aat::chains(font.data, morx),
60 kern,
61 })),
62 _ => WritingSystemsKind::None,
63 },
64 }
65 }
66}
67
68#[derive(Copy, Clone)]
69enum WritingSystemKind<'a> {
70 At(at::WritingSystem<'a>),
71 Aat(aat::Item<'a>),
72}
73
74impl<'a> Iterator for WritingSystems<'a> {
75 type Item = WritingSystem<'a>;
76
77 fn next(&mut self) -> Option<Self::Item> {
78 match &mut self.kind {
79 WritingSystemsKind::At(iter) => {
80 let item = iter.next()?;
81 Some(WritingSystem {
82 kind: WritingSystemKind::At(item),
83 script_tag: item.script_tag(),
84 lang_tag: item.language_tag(),
85 lang: Language::from_opentype(item.language_tag()),
86 })
87 }
88 WritingSystemsKind::Aat(iter) => {
89 let item = iter.take()?;
90 Some(WritingSystem {
91 kind: WritingSystemKind::Aat(item),
92 script_tag: DFLT,
93 lang_tag: DFLT,
94 lang: None,
95 })
96 }
97 _ => None,
98 }
99 }
100}
101
102#[derive(Copy, Clone)]
104pub struct WritingSystem<'a> {
105 kind: WritingSystemKind<'a>,
106 script_tag: Tag,
107 lang_tag: Tag,
108 lang: Option<Language>,
109}
110
111impl<'a> WritingSystem<'a> {
112 pub fn script_tag(&self) -> Tag {
114 self.script_tag
115 }
116
117 pub fn language_tag(&self) -> Tag {
119 self.lang_tag
120 }
121
122 pub fn script(&self) -> Option<Script> {
124 Script::from_opentype(self.script_tag)
125 }
126
127 pub fn language(&self) -> Option<Language> {
129 self.lang
130 }
131
132 pub fn features(&self) -> Features<'a> {
135 Features {
136 kind: match self.kind {
137 WritingSystemKind::At(item) => FeaturesKind::At(item.features()),
138 WritingSystemKind::Aat(item) => {
139 FeaturesKind::Aat(aat::Features::new(item.chains, item.kern))
140 }
141 },
142 }
143 }
144}
145
146#[derive(Copy, Clone)]
147enum FeaturesKind<'a> {
148 None,
149 At(at::Features<'a>),
150 AtAll(at::AllFeatures<'a>),
151 Aat(aat::Features<'a>),
152}
153
154#[derive(Copy, Clone)]
156pub struct Feature {
157 tag: Tag,
158 name: Option<&'static str>,
159 action: Action,
160}
161
162impl Feature {
163 fn from_tag(tag: Tag, action: Action) -> Self {
164 Self {
165 tag,
166 name: util::desc_from_at(tag).map(|x| x.1),
167 action,
168 }
169 }
170
171 pub fn tag(&self) -> Tag {
173 self.tag
174 }
175
176 pub fn name(&self) -> Option<&'static str> {
178 self.name
179 }
180
181 pub fn action(&self) -> Action {
183 self.action
184 }
185}
186
187#[derive(Copy, Clone, PartialEq, Eq, Debug)]
189pub enum Action {
190 Substitution,
192 Attachment,
194 Adjustment,
196}
197
198#[derive(Copy, Clone)]
200pub struct Features<'a> {
201 kind: FeaturesKind<'a>,
202}
203
204impl<'a> Features<'a> {
205 pub(crate) fn from_font(font: &FontRef<'a>) -> Self {
206 let kind = Kind::from_font(font);
207 Self {
208 kind: match kind {
209 Kind::At(gsub, gpos) => {
210 FeaturesKind::AtAll(at::AllFeatures::new(Bytes::new(font.data), gsub, gpos))
211 }
212 Kind::Aat(morx, kern) => {
213 FeaturesKind::Aat(aat::Features::new(aat::chains(font.data, morx), kern))
214 }
215 _ => FeaturesKind::None,
216 },
217 }
218 }
219}
220
221const MARK: u32 = raw_tag(b"mark");
222const MKMK: u32 = raw_tag(b"mkmk");
223
224impl<'a> Iterator for Features<'a> {
225 type Item = Feature;
226
227 fn next(&mut self) -> Option<Self::Item> {
228 match &mut self.kind {
229 FeaturesKind::At(iter) => {
230 let item = iter.next()?;
231 let action = if item.stage == 0 {
232 Action::Substitution
233 } else {
234 match item.tag {
235 MARK | MKMK => Action::Attachment,
236 _ => Action::Adjustment,
237 }
238 };
239 Some(Feature::from_tag(item.tag, action))
240 }
241 FeaturesKind::AtAll(iter) => {
242 let (stage, tag) = iter.next()?;
243 let action = if stage == 0 {
244 Action::Substitution
245 } else {
246 match tag {
247 MARK | MKMK => Action::Attachment,
248 _ => Action::Adjustment,
249 }
250 };
251 Some(Feature::from_tag(tag, action))
252 }
253 FeaturesKind::Aat(iter) => {
254 let (tag, name) = iter.next()?;
255 let action = if tag == raw_tag(b"kern") {
256 Action::Adjustment
257 } else {
258 Action::Substitution
259 };
260 Some(Feature {
261 tag,
262 name: Some(name),
263 action,
264 })
265 }
266 _ => None,
267 }
268 }
269}