swash/feature/
mod.rs

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    /// GSUB, GPOS offsets
15    At(u32, u32),
16    /// Morx offset, kerning available
17    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/// Iterator over a collection of writing systems.
45#[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/// Script, language and associated typographic features available in a font.
103#[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    /// Returns the OpenType script tag for the writing system.
113    pub fn script_tag(&self) -> Tag {
114        self.script_tag
115    }
116
117    /// Returns the OpenType language tag for the writing system.
118    pub fn language_tag(&self) -> Tag {
119        self.lang_tag
120    }
121
122    /// Returns the script for the writing system.
123    pub fn script(&self) -> Option<Script> {
124        Script::from_opentype(self.script_tag)
125    }
126
127    /// Returns the language for the writing system.
128    pub fn language(&self) -> Option<Language> {
129        self.lang
130    }
131
132    /// Returns an iterator over the features provided by the writing
133    /// system.
134    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/// Typographic rule that produces modifications to a sequence of glyphs.
155#[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    /// Returns the feature tag.
172    pub fn tag(&self) -> Tag {
173        self.tag
174    }
175
176    /// Returns the name of the feature, if available.
177    pub fn name(&self) -> Option<&'static str> {
178        self.name
179    }
180
181    /// Returns the action of the feature.
182    pub fn action(&self) -> Action {
183        self.action
184    }
185}
186
187/// Modification performed by a feature.
188#[derive(Copy, Clone, PartialEq, Eq, Debug)]
189pub enum Action {
190    /// Replaces one or more glyphs such as in ligation.
191    Substitution,
192    /// Attaches one glyph to another such as in accent mark placement.
193    Attachment,
194    /// Adjusts the position of one or more glyphs such as in kerning.
195    Adjustment,
196}
197
198/// Iterator over a collection of typographic features.
199#[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}