1mod apply;
2mod contextual;
3pub mod feature;
4mod kerning;
5mod layout;
6mod map;
7pub mod matching;
8mod position;
9mod substitute;
10
11pub use apply::*;
12pub use kerning::*;
13pub use layout::*;
14pub use map::*;
15pub use position::*;
16pub use substitute::*;
17
18use alloc::vec::Vec;
19
20use ttf_parser::gpos::PositioningSubtable;
21use ttf_parser::gsub::SubstitutionSubtable;
22use ttf_parser::opentype_layout::{Coverage, Lookup};
23
24use crate::glyph_set::{GlyphSet, GlyphSetBuilder};
25
26#[allow(dead_code)]
27pub mod lookup_flags {
28 pub const RIGHT_TO_LEFT: u16 = 0x0001;
29 pub const IGNORE_BASE_GLYPHS: u16 = 0x0002;
30 pub const IGNORE_LIGATURES: u16 = 0x0004;
31 pub const IGNORE_MARKS: u16 = 0x0008;
32 pub const IGNORE_FLAGS: u16 = 0x000E;
33 pub const USE_MARK_FILTERING_SET: u16 = 0x0010;
34 pub const MARK_ATTACHMENT_TYPE_MASK: u16 = 0xFF00;
35}
36
37#[derive(Clone)]
38pub struct PositioningTable<'a> {
39 pub inner: ttf_parser::opentype_layout::LayoutTable<'a>,
40 pub lookups: Vec<PositioningLookup<'a>>,
41}
42
43impl<'a> PositioningTable<'a> {
44 pub fn new(inner: ttf_parser::opentype_layout::LayoutTable<'a>) -> Self {
45 let lookups: Vec> = innerimpl Iterator>
46 .lookups
47 .into_iter()
48 .map(PositioningLookup::parse)
49 .collect();
50
51 Self { inner, lookups }
52 }
53}
54
55pub trait CoverageExt {
56 fn collect(&self, set: &mut GlyphSetBuilder);
57}
58
59impl CoverageExt for Coverage<'_> {
60 /// Collect this coverage table into a glyph set.
61 fn collect(&self, set: &mut GlyphSetBuilder) {
62 match *self {
63 Self::Format1 { glyphs: LazyArray16<'_, GlyphId> } => {
64 for glyph: GlyphId in glyphs {
65 set.insert(glyph);
66 }
67 }
68 Self::Format2 { records: LazyArray16<'_, RangeRecord> } => {
69 for record: RangeRecord in records {
70 set.insert_range(record.start..=record.end);
71 }
72 }
73 }
74 }
75}
76
77#[derive(Clone)]
78pub struct PositioningLookup<'a> {
79 pub subtables: Vec<PositioningSubtable<'a>>,
80 pub coverage: GlyphSet,
81 pub props: u32,
82}
83
84impl<'a> PositioningLookup<'a> {
85 pub fn parse(lookup: Lookup<'a>) -> Self {
86 let subtables: Vec<_> = lookupLookupSubtablesIter<'_, PositioningSubtable<'_>>
87 .subtables
88 .into_iter::<PositioningSubtable>()
89 .collect();
90
91 let mut coverage: GlyphSetBuilder = GlyphSet::builder();
92 for subtable: &PositioningSubtable<'_> in &subtables {
93 subtable.coverage().collect(&mut coverage);
94 }
95
96 Self {
97 subtables,
98 coverage: coverage.finish(),
99 props: lookup_props(lookup),
100 }
101 }
102}
103
104#[derive(Clone)]
105pub struct SubstitutionTable<'a> {
106 pub inner: ttf_parser::opentype_layout::LayoutTable<'a>,
107 pub lookups: Vec<SubstLookup<'a>>,
108}
109
110impl<'a> SubstitutionTable<'a> {
111 pub fn new(inner: ttf_parser::opentype_layout::LayoutTable<'a>) -> Self {
112 let lookups: Vec> = inner.lookups.into_iter().map(SubstLookup::parse).collect();
113
114 Self { inner, lookups }
115 }
116}
117
118#[derive(Clone)]
119pub struct SubstLookup<'a> {
120 pub subtables: Vec<SubstitutionSubtable<'a>>,
121 pub coverage: GlyphSet,
122 pub reverse: bool,
123 pub props: u32,
124}
125
126impl<'a> SubstLookup<'a> {
127 pub fn parse(lookup: Lookup<'a>) -> Self {
128 let subtables: Vec<_> = lookupLookupSubtablesIter<'_, SubstitutionSubtable<'_>>
129 .subtables
130 .into_iter::<SubstitutionSubtable>()
131 .collect();
132
133 let mut coverage: GlyphSetBuilder = GlyphSet::builder();
134 let mut reverse: bool = !subtables.is_empty();
135
136 for subtable: &SubstitutionSubtable<'_> in &subtables {
137 subtable.coverage().collect(&mut coverage);
138 reverse &= subtable.is_reverse();
139 }
140
141 Self {
142 subtables,
143 coverage: coverage.finish(),
144 reverse,
145 props: lookup_props(lookup),
146 }
147 }
148}
149
150// lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
151// higher 16-bit is mark-filtering-set if the lookup uses one.
152// Not to be confused with glyph_props which is very similar. */
153fn lookup_props(lookup: Lookup) -> u32 {
154 let mut props: u32 = u32::from(lookup.flags.0);
155 if let Some(set: u16) = lookup.mark_filtering_set {
156 props |= u32::from(set) << 16;
157 }
158 props
159}
160