swash/feature/
at.rs

1use super::super::Tag;
2use super::internal::{at::*, *};
3use super::util::*;
4
5#[derive(Copy, Clone)]
6pub struct Script<'a> {
7    data: Bytes<'a>,
8    gsub: u32,
9    gpos: u32,
10    gsub_offset: u32,
11    gpos_offset: u32,
12    tag: Tag,
13}
14
15impl<'a> Script<'a> {
16    pub fn languages(&self) -> Languages<'a> {
17        Languages::new(
18            self.data,
19            self.gsub,
20            self.gpos,
21            self.gsub_offset,
22            self.gpos_offset,
23        )
24    }
25}
26
27#[derive(Copy, Clone)]
28pub struct Scripts<'a> {
29    data: Bytes<'a>,
30    gsub: u32,
31    gpos: u32,
32    in_gsub: bool,
33    len: u16,
34    cur: u16,
35    done: bool,
36}
37
38impl<'a> Scripts<'a> {
39    pub fn new(data: Bytes<'a>, gsub: u32, gpos: u32) -> Self {
40        Self {
41            data,
42            gsub,
43            gpos,
44            in_gsub: true,
45            len: script_count(&data, gsub),
46            cur: 0,
47            done: false,
48        }
49    }
50
51    fn get_next(&mut self) -> Option<Script<'a>> {
52        if self.in_gsub {
53            if self.cur < self.len {
54                let index = self.cur;
55                self.cur += 1;
56                let (tag, offset) = script_at(&self.data, self.gsub, index)?;
57                let gpos_offset = script_by_tag(&self.data, self.gpos, tag).unwrap_or(0);
58                return Some(Script {
59                    data: self.data,
60                    gsub: self.gsub,
61                    gpos: self.gpos,
62                    gsub_offset: offset,
63                    gpos_offset,
64                    tag,
65                });
66            } else {
67                self.in_gsub = false;
68                self.cur = 0;
69                self.len = script_count(&self.data, self.gpos);
70            }
71        } else if self.cur < self.len {
72            let index = self.cur;
73            self.cur += 1;
74            let (tag, offset) = script_at(&self.data, self.gpos, index)?;
75            if script_by_tag(&self.data, self.gsub, tag).is_some() {
76                return None;
77            }
78            return Some(Script {
79                data: self.data,
80                gsub: self.gsub,
81                gpos: self.gpos,
82                gsub_offset: 0,
83                gpos_offset: offset,
84                tag,
85            });
86        } else {
87            self.done = true;
88        }
89        None
90    }
91}
92
93impl<'a> Iterator for Scripts<'a> {
94    type Item = Script<'a>;
95
96    fn next(&mut self) -> Option<Self::Item> {
97        while !self.done {
98            let item = self.get_next();
99            if item.is_some() {
100                return item;
101            }
102        }
103        None
104    }
105}
106
107/// Specifies language system specific features used for shaping glyphs in
108/// a particular script.
109#[derive(Copy, Clone)]
110pub struct Language<'a> {
111    data: Bytes<'a>,
112    gsub: u32,
113    gpos: u32,
114    gsub_offset: u32,
115    gpos_offset: u32,
116    tag: Tag,
117}
118
119/// An iterator over languages supported by a script.
120#[derive(Copy, Clone)]
121pub struct Languages<'a> {
122    data: Bytes<'a>,
123    gsub: u32,
124    gpos: u32,
125    gsub_script: u32,
126    gpos_script: u32,
127    in_gsub: bool,
128    len: u16,
129    cur: u16,
130    done: bool,
131}
132
133impl<'a> Languages<'a> {
134    fn new(data: Bytes<'a>, gsub: u32, gpos: u32, gsub_script: u32, gpos_script: u32) -> Self {
135        Self {
136            data,
137            gsub,
138            gpos,
139            gsub_script,
140            gpos_script,
141            in_gsub: true,
142            len: script_language_count(&data, gsub_script),
143            cur: 0,
144            done: false,
145        }
146    }
147
148    fn get_next(&mut self) -> Option<Language<'a>> {
149        if self.in_gsub {
150            if self.cur < self.len {
151                let index = self.cur;
152                self.cur += 1;
153                let (tag, offset) = script_language_at(&self.data, self.gsub_script, index)?;
154                let gsub_default = tag == DFLT;
155                let (gpos_offset, _) = if gsub_default {
156                    (
157                        script_default_language(&self.data, self.gpos_script).unwrap_or(0),
158                        true,
159                    )
160                } else {
161                    script_language_by_tag(&self.data, self.gpos_script, Some(tag))
162                        .unwrap_or((0, false))
163                };
164                return Some(Language {
165                    data: self.data,
166                    gsub: self.gsub,
167                    gpos: self.gpos,
168                    gsub_offset: offset,
169                    gpos_offset,
170                    tag,
171                });
172            } else {
173                self.in_gsub = false;
174                self.cur = 0;
175                self.len = script_language_count(&self.data, self.gpos_script);
176            }
177        } else if self.cur < self.len {
178            let index = self.cur;
179            self.cur += 1;
180            let (tag, offset) = script_language_at(&self.data, self.gpos_script, index)?;
181            if script_language_by_tag(&self.data, self.gsub_script, Some(tag)).is_some() {
182                return None;
183            }
184            return Some(Language {
185                data: self.data,
186                gsub: self.gsub,
187                gpos: self.gpos,
188                gsub_offset: 0,
189                gpos_offset: offset,
190                tag,
191            });
192        } else {
193            self.done = true;
194        }
195        None
196    }
197}
198
199impl<'a> Iterator for Languages<'a> {
200    type Item = Language<'a>;
201
202    fn next(&mut self) -> Option<Self::Item> {
203        while !self.done {
204            let item = self.get_next();
205            if item.is_some() {
206                return item;
207            }
208        }
209        None
210    }
211}
212
213#[derive(Copy, Clone)]
214pub struct WritingSystem<'a> {
215    lang: Language<'a>,
216    script_tag: Tag,
217}
218
219impl<'a> WritingSystem<'a> {
220    pub fn script_tag(&self) -> Tag {
221        self.script_tag
222    }
223
224    pub fn language_tag(&self) -> Tag {
225        self.lang.tag
226    }
227
228    pub fn features(&self) -> Features<'a> {
229        Features::new(&self.lang)
230    }
231}
232
233#[derive(Copy, Clone)]
234pub struct WritingSystems<'a> {
235    scripts: Scripts<'a>,
236    langs: Option<Languages<'a>>,
237    script_tag: Tag,
238}
239
240impl<'a> WritingSystems<'a> {
241    pub fn new(scripts: Scripts<'a>) -> Self {
242        Self {
243            scripts,
244            langs: None,
245            script_tag: 0,
246        }
247    }
248}
249
250impl<'a> Iterator for WritingSystems<'a> {
251    type Item = WritingSystem<'a>;
252
253    fn next(&mut self) -> Option<Self::Item> {
254        loop {
255            if self.langs.is_none() {
256                let script = self.scripts.next()?;
257                self.script_tag = script.tag;
258                self.langs = Some(script.languages());
259            }
260            if let Some(lang) = self.langs.as_mut().unwrap().next() {
261                return Some(WritingSystem {
262                    lang,
263                    script_tag: self.script_tag,
264                });
265            } else {
266                self.langs = None;
267            }
268        }
269    }
270}
271
272/// Represents a single typographic feature-- a substitution or positioning
273/// action that is a component of text shaping.
274#[derive(Copy, Clone)]
275pub struct Feature {
276    pub stage: u8,
277    pub tag: Tag,
278}
279
280#[derive(Copy, Clone)]
281pub struct Features<'a> {
282    data: Bytes<'a>,
283    gsub: u32,
284    gpos: u32,
285    gsub_language: u32,
286    gpos_language: u32,
287    stage: u8,
288    len: u16,
289    cur: u16,
290    done: bool,
291}
292
293impl<'a> Features<'a> {
294    fn new(language: &Language<'a>) -> Self {
295        Self {
296            data: language.data,
297            gsub: language.gsub,
298            gpos: language.gpos,
299            gsub_language: language.gsub_offset,
300            gpos_language: language.gpos_offset,
301            stage: 0,
302            len: language_feature_count(&language.data, language.gsub_offset),
303            cur: 0,
304            done: false,
305        }
306    }
307
308    fn get_next(&mut self) -> Option<Feature> {
309        let (gsubgpos, language) = match self.stage {
310            0 => (self.gsub, self.gsub_language),
311            _ => (self.gpos, self.gpos_language),
312        };
313        if self.cur < self.len {
314            let index = self.cur;
315            self.cur += 1;
316            let feature = language_feature_at(&self.data, language, index)?;
317            let (tag, _offset) = feature_at(&self.data, gsubgpos, feature)?;
318            return Some(Feature {
319                stage: self.stage,
320                tag,
321            });
322        } else if self.stage == 0 {
323            self.stage = 1;
324            self.len = language_feature_count(&self.data, self.gpos_language);
325            self.cur = 0;
326        } else {
327            self.done = true;
328        }
329        None
330    }
331}
332
333impl<'a> Iterator for Features<'a> {
334    type Item = Feature;
335
336    fn next(&mut self) -> Option<Self::Item> {
337        while !self.done {
338            let item = self.get_next();
339            if item.is_some() {
340                return item;
341            }
342        }
343        None
344    }
345}
346
347#[derive(Copy, Clone)]
348pub struct AllFeatures<'a> {
349    data: Bytes<'a>,
350    seen: SeenFeatures,
351    table: u32,
352    next_table: u32,
353    stage: u8,
354    len: u16,
355    cur: u16,
356}
357
358impl<'a> AllFeatures<'a> {
359    pub fn new(data: Bytes<'a>, gsub: u32, gpos: u32) -> Self {
360        let len = feature_count(&data, gsub);
361        Self {
362            data,
363            seen: SeenFeatures::new(),
364            table: gsub,
365            next_table: gpos,
366            stage: 0,
367            len,
368            cur: 0,
369        }
370    }
371}
372
373impl<'a> Iterator for AllFeatures<'a> {
374    type Item = (u8, Tag);
375
376    fn next(&mut self) -> Option<Self::Item> {
377        loop {
378            if self.cur >= self.len {
379                if self.next_table == 0 {
380                    return None;
381                }
382                self.table = self.next_table;
383                self.next_table = 0;
384                self.stage = 1;
385                self.cur = 0;
386                self.len = feature_count(&self.data, self.table);
387                if self.len == 0 {
388                    return None;
389                }
390            }
391            let index = self.cur;
392            self.cur += 1;
393            if let Some((tag, _)) = feature_at(&self.data, self.table, index) {
394                match FEATURES.binary_search_by(|pair| pair.0.cmp(&tag)) {
395                    Ok(index) => {
396                        if self.seen.mark(index) {
397                            return Some((self.stage, tag));
398                        }
399                    }
400                    _ => continue,
401                }
402            }
403        }
404    }
405}