opentype/layout/
feature.rs

1//! The feature list.
2
3use truetype::Tag;
4
5table! {
6    @position
7    /// A feature list.
8    pub Features { // FeatureList
9        count (u16), // featureCount
10
11        headers (Vec<Header>) |this, tape, _| { // featureRecords
12            tape.take_given(this.count as usize)
13        },
14
15        records (Vec<Record>) |this, tape, position| {
16            jump_take!(tape, position, this.count, i => this.headers[i].offset)
17        },
18    }
19}
20
21table! {
22    /// A feature header.
23    #[derive(Copy)]
24    pub Header { // FeatureRecord
25        tag    (Tag), // featureTag
26        offset (u16), // featureOffset
27    }
28}
29
30table! {
31    @position
32    /// A feature record.
33    pub Record { // Feature
34        parameter_offset   (u16), // featureParamsOffset
35        lookup_index_count (u16), // lookupIndexCount
36
37        lookup_indices (Vec<u16>) |this, tape, _| { // lookupListIndices
38            tape.take_given(this.lookup_index_count as usize)
39        },
40
41        parameters (Option<Vec<u8>>) |this, tape, position| {
42            if this.parameter_offset > 0 {
43                tape.jump(position + this.parameter_offset as u64)?;
44                Ok(Some(tape.take_bytes(0)?))
45            } else {
46                Ok(None)
47            }
48        },
49    }
50}
51
52table! {
53    /// Feature variations.
54    #[derive(Copy)]
55    pub Variations { // FeatureVariations
56        major_version (u16) = { 1 }, // MajorVersion
57        minor_version (u16) = { 0 }, // MinorVersion
58        count         (u32), // FeatureVariationRecordsCount
59    }
60}
61
62impl Features {
63    /// Return the record of a feature if present.
64    pub fn get<T: Into<Tag>>(&self, tag: T) -> Option<&Record> {
65        let tag = tag.into();
66        self.headers
67            .iter()
68            .enumerate()
69            .find(|(_, header)| header.tag == tag)
70            .map(|(i, _)| &self.records[i])
71    }
72}
73
74macro_rules! implement {
75    ($($tag:literal => $name:literal => $variant:ident,)*) => (
76        /// A feature.
77        #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
78        pub enum Feature {
79            $(#[doc = $name] $variant,)*
80            Other(Tag),
81        }
82
83        impl Feature {
84            /// Create an instance from a tag.
85            pub fn from_tag(tag: &Tag) -> Self {
86                match &**tag {
87                    $($tag => Self::$variant,)*
88                    _ => Self::Other(tag.clone()),
89                }
90            }
91
92            /// Return the name.
93            pub fn name(&self) -> Option<&'static str> {
94                match self {
95                    $(Self::$variant => Some($name),)*
96                    _ => None,
97                }
98            }
99        }
100
101        impl From<Feature> for Tag {
102            fn from(feature: Feature) -> Self {
103                match feature {
104                    $(Feature::$variant => Tag(*$tag),)*
105                    Feature::Other(tag) => tag,
106                }
107            }
108        }
109    );
110}
111
112implement! {
113    b"aalt" => "Access All Alternates" => AccessAllAlternates,
114    b"abvf" => "Above-base Forms" => AboveBaseForms,
115    b"abvm" => "Above-base Mark Positioning" => AboveBaseMarkPositioning,
116    b"abvs" => "Above-base Substitutions" => AboveBaseSubstitutions,
117    b"afrc" => "Alternative Fractions" => AlternativeFractions,
118    b"akhn" => "Akhand" => Akhand,
119    b"blwf" => "Below-base Forms" => BelowBaseForms,
120    b"blwm" => "Below-base Mark Positioning" => BelowBaseMarkPositioning,
121    b"blws" => "Below-base Substitutions" => BelowBaseSubstitutions,
122    b"calt" => "Contextual Alternates" => ContextualAlternates,
123    b"case" => "Case-sensitive Forms" => CaseSensitiveForms,
124    b"ccmp" => "Glyph Composition and Decomposition" => GlyphCompositionDecomposition,
125    b"cfar" => "Conjunct Form After Ro" => ConjunctFormAfterRo,
126    b"chws" => "Contextual Half-width Spacing" => ContextualHalfWidthSpacing,
127    b"cjct" => "Conjunct Forms" => ConjunctForms,
128    b"clig" => "Contextual Ligatures" => ContextualLigatures,
129    b"cpct" => "Centered CJK Punctuation" => CenteredCJKPunctuation,
130    b"cpsp" => "Capital Spacing" => CapitalSpacing,
131    b"cswh" => "Contextual Swash" => ContextualSwash,
132    b"curs" => "Cursive Positioning" => CursivePositioning,
133    b"cv01" => "Character Variants 1" => CharacterVariants1,
134    b"cv02" => "Character Variants 2" => CharacterVariants2,
135    b"cv03" => "Character Variants 3" => CharacterVariants3,
136    b"cv04" => "Character Variants 4" => CharacterVariants4,
137    b"cv05" => "Character Variants 5" => CharacterVariants5,
138    b"cv06" => "Character Variants 6" => CharacterVariants6,
139    b"cv07" => "Character Variants 7" => CharacterVariants7,
140    b"cv08" => "Character Variants 8" => CharacterVariants8,
141    b"cv09" => "Character Variants 9" => CharacterVariants9,
142    b"cv10" => "Character Variants 10" => CharacterVariants10,
143    b"cv11" => "Character Variants 11" => CharacterVariants11,
144    b"cv12" => "Character Variants 12" => CharacterVariants12,
145    b"cv13" => "Character Variants 13" => CharacterVariants13,
146    b"cv14" => "Character Variants 14" => CharacterVariants14,
147    b"cv15" => "Character Variants 15" => CharacterVariants15,
148    b"cv16" => "Character Variants 16" => CharacterVariants16,
149    b"cv17" => "Character Variants 17" => CharacterVariants17,
150    b"cv18" => "Character Variants 18" => CharacterVariants18,
151    b"cv19" => "Character Variants 19" => CharacterVariants19,
152    b"cv20" => "Character Variants 20" => CharacterVariants20,
153    b"cv21" => "Character Variants 21" => CharacterVariants21,
154    b"cv22" => "Character Variants 22" => CharacterVariants22,
155    b"cv23" => "Character Variants 23" => CharacterVariants23,
156    b"cv24" => "Character Variants 24" => CharacterVariants24,
157    b"cv25" => "Character Variants 25" => CharacterVariants25,
158    b"cv26" => "Character Variants 26" => CharacterVariants26,
159    b"cv27" => "Character Variants 27" => CharacterVariants27,
160    b"cv28" => "Character Variants 28" => CharacterVariants28,
161    b"cv29" => "Character Variants 29" => CharacterVariants29,
162    b"cv30" => "Character Variants 30" => CharacterVariants30,
163    b"cv31" => "Character Variants 31" => CharacterVariants31,
164    b"cv32" => "Character Variants 32" => CharacterVariants32,
165    b"cv33" => "Character Variants 33" => CharacterVariants33,
166    b"cv34" => "Character Variants 34" => CharacterVariants34,
167    b"cv35" => "Character Variants 35" => CharacterVariants35,
168    b"cv36" => "Character Variants 36" => CharacterVariants36,
169    b"cv37" => "Character Variants 37" => CharacterVariants37,
170    b"cv38" => "Character Variants 38" => CharacterVariants38,
171    b"cv39" => "Character Variants 39" => CharacterVariants39,
172    b"cv40" => "Character Variants 40" => CharacterVariants40,
173    b"cv41" => "Character Variants 41" => CharacterVariants41,
174    b"cv42" => "Character Variants 42" => CharacterVariants42,
175    b"cv43" => "Character Variants 43" => CharacterVariants43,
176    b"cv44" => "Character Variants 44" => CharacterVariants44,
177    b"cv45" => "Character Variants 45" => CharacterVariants45,
178    b"cv46" => "Character Variants 46" => CharacterVariants46,
179    b"cv47" => "Character Variants 47" => CharacterVariants47,
180    b"cv48" => "Character Variants 48" => CharacterVariants48,
181    b"cv49" => "Character Variants 49" => CharacterVariants49,
182    b"cv50" => "Character Variants 50" => CharacterVariants50,
183    b"cv51" => "Character Variants 51" => CharacterVariants51,
184    b"cv52" => "Character Variants 52" => CharacterVariants52,
185    b"cv53" => "Character Variants 53" => CharacterVariants53,
186    b"cv54" => "Character Variants 54" => CharacterVariants54,
187    b"cv55" => "Character Variants 55" => CharacterVariants55,
188    b"cv56" => "Character Variants 56" => CharacterVariants56,
189    b"cv57" => "Character Variants 57" => CharacterVariants57,
190    b"cv58" => "Character Variants 58" => CharacterVariants58,
191    b"cv59" => "Character Variants 59" => CharacterVariants59,
192    b"cv60" => "Character Variants 60" => CharacterVariants60,
193    b"cv61" => "Character Variants 61" => CharacterVariants61,
194    b"cv62" => "Character Variants 62" => CharacterVariants62,
195    b"cv63" => "Character Variants 63" => CharacterVariants63,
196    b"cv64" => "Character Variants 64" => CharacterVariants64,
197    b"cv65" => "Character Variants 65" => CharacterVariants65,
198    b"cv66" => "Character Variants 66" => CharacterVariants66,
199    b"cv67" => "Character Variants 67" => CharacterVariants67,
200    b"cv68" => "Character Variants 68" => CharacterVariants68,
201    b"cv69" => "Character Variants 69" => CharacterVariants69,
202    b"cv70" => "Character Variants 70" => CharacterVariants70,
203    b"cv71" => "Character Variants 71" => CharacterVariants71,
204    b"cv72" => "Character Variants 72" => CharacterVariants72,
205    b"cv73" => "Character Variants 73" => CharacterVariants73,
206    b"cv74" => "Character Variants 74" => CharacterVariants74,
207    b"cv75" => "Character Variants 75" => CharacterVariants75,
208    b"cv76" => "Character Variants 76" => CharacterVariants76,
209    b"cv77" => "Character Variants 77" => CharacterVariants77,
210    b"cv78" => "Character Variants 78" => CharacterVariants78,
211    b"cv79" => "Character Variants 79" => CharacterVariants79,
212    b"cv80" => "Character Variants 80" => CharacterVariants80,
213    b"cv81" => "Character Variants 81" => CharacterVariants81,
214    b"cv82" => "Character Variants 82" => CharacterVariants82,
215    b"cv83" => "Character Variants 83" => CharacterVariants83,
216    b"cv84" => "Character Variants 84" => CharacterVariants84,
217    b"cv85" => "Character Variants 85" => CharacterVariants85,
218    b"cv86" => "Character Variants 86" => CharacterVariants86,
219    b"cv87" => "Character Variants 87" => CharacterVariants87,
220    b"cv88" => "Character Variants 88" => CharacterVariants88,
221    b"cv89" => "Character Variants 89" => CharacterVariants89,
222    b"cv90" => "Character Variants 90" => CharacterVariants90,
223    b"cv91" => "Character Variants 91" => CharacterVariants91,
224    b"cv92" => "Character Variants 92" => CharacterVariants92,
225    b"cv93" => "Character Variants 93" => CharacterVariants93,
226    b"cv94" => "Character Variants 94" => CharacterVariants94,
227    b"cv95" => "Character Variants 95" => CharacterVariants95,
228    b"cv96" => "Character Variants 96" => CharacterVariants96,
229    b"cv97" => "Character Variants 97" => CharacterVariants97,
230    b"cv98" => "Character Variants 98" => CharacterVariants98,
231    b"cv99" => "Character Variants 99" => CharacterVariants99,
232    b"c2pc" => "Petite Capitals from Capitals" => PetiteCapitalsFromCapitals,
233    b"c2sc" => "Small Capitals from Capitals" => SmallCapitalsFromCapitals,
234    b"dist" => "Distances" => Distances,
235    b"dlig" => "Discretionary Ligatures" => DiscretionaryLigatures,
236    b"dnom" => "Denominators" => Denominators,
237    b"dtls" => "Dotless Forms" => DotlessForms,
238    b"expt" => "Expert Forms" => ExpertForms,
239    b"falt" => "Final Glyph on Line Alternates" => FinalGlyphonLineAlternates,
240    b"fin2" => "Terminal Forms 2" => TerminalForms2,
241    b"fin3" => "Terminal Forms 3" => TerminalForms3,
242    b"fina" => "Terminal Forms 1" => TerminalForms1,
243    b"flac" => "Flattened Accent Forms" => FlattenedAccentForms,
244    b"frac" => "Fractions" => Fractions,
245    b"fwid" => "Full Widths" => FullWidths,
246    b"half" => "Half Forms" => HalfForms,
247    b"haln" => "Halant Forms" => HalantForms,
248    b"halt" => "Alternate Half Widths" => AlternateHalfWidths,
249    b"hist" => "Historical Forms" => HistoricalForms,
250    b"hkna" => "Horizontal Kana Alternates" => HorizontalKanaAlternates,
251    b"hlig" => "Historical Ligatures" => HistoricalLigatures,
252    b"hngl" => "Hangul" => Hangul,
253    b"hojo" => "Hojo Kanji Forms" => HojoKanjiForms,
254    b"hwid" => "Half Widths" => HalfWidths,
255    b"init" => "Initial Forms" => InitialForms,
256    b"isol" => "Isolated Forms" => IsolatedForms,
257    b"ital" => "Italics" => Italics,
258    b"jalt" => "Justification Alternates" => JustificationAlternates,
259    b"jp78" => "JIS78 Forms" => JIS78Forms,
260    b"jp83" => "JIS83 Forms" => JIS83Forms,
261    b"jp90" => "JIS90 Forms" => JIS90Forms,
262    b"jp04" => "JIS2004 Forms" => JIS2004Forms,
263    b"kern" => "Kerning" => Kerning,
264    b"lfbd" => "Left Bounds" => LeftBounds,
265    b"liga" => "Standard Ligatures" => StandardLigatures,
266    b"ljmo" => "Leading Jamo Forms" => LeadingJamoForms,
267    b"lnum" => "Lining Figures" => LiningFigures,
268    b"locl" => "Localized Forms" => LocalizedForms,
269    b"ltra" => "Left-to-right Alternates" => LeftToRightAlternates,
270    b"ltrm" => "Left-to-right Mirrored Forms" => LeftToRightMirroredForms,
271    b"mark" => "Mark Positioning" => MarkPositioning,
272    b"med2" => "Medial Forms 2" => MedialForms2,
273    b"medi" => "Medial Forms 1" => MedialForms1,
274    b"mgrk" => "Mathematical Greek" => MathematicalGreek,
275    b"mkmk" => "Mark-to-mark Positioning" => MarkToMarkPositioning,
276    b"mset" => "Mark Positioning via Substitution" => MarkPositioningViaSubstitution,
277    b"nalt" => "Alternate Annotation Forms" => AlternateAnnotationForms,
278    b"nlck" => "NLC Kanji Forms" => NLCKanjiForms,
279    b"nukt" => "Nukta Forms" => NuktaForms,
280    b"numr" => "Numerators" => Numerators,
281    b"onum" => "Oldstyle Figures" => OldstyleFigures,
282    b"opbd" => "Optical Bounds" => OpticalBounds,
283    b"ordn" => "Ordinals" => Ordinals,
284    b"ornm" => "Ornaments" => Ornaments,
285    b"palt" => "Proportional Alternate Widths" => ProportionalAlternateWidths,
286    b"pcap" => "Petite Capitals" => PetiteCapitals,
287    b"pkna" => "Proportional Kana" => ProportionalKana,
288    b"pnum" => "Proportional Figures" => ProportionalFigures,
289    b"pref" => "Pre-base Forms" => PreBaseForms,
290    b"pres" => "Pre-base Substitutions" => PreBaseSubstitutions,
291    b"pstf" => "Post-base Forms" => PostBaseForms,
292    b"psts" => "Post-base Substitutions" => PostBaseSubstitutions,
293    b"pwid" => "Proportional Widths" => ProportionalWidths,
294    b"qwid" => "Quarter Widths" => QuarterWidths,
295    b"rand" => "Randomize" => Randomize,
296    b"rclt" => "Required Contextual Alternates" => RequiredContextualAlternates,
297    b"rkrf" => "Rakar Forms" => RakarForms,
298    b"rlig" => "Required Ligatures" => RequiredLigatures,
299    b"rphf" => "Reph Forms" => RephForms,
300    b"rtbd" => "Right Bounds" => RightBounds,
301    b"rtla" => "Right-to-left Alternates" => RightToLeftAlternates,
302    b"rtlm" => "Right-to-left Mirrored Forms" => RightToLeftMirroredForms,
303    b"ruby" => "Ruby Notation Forms" => RubyNotationForms,
304    b"rvrn" => "Required Variation Alternates" => RequiredVariationAlternates,
305    b"salt" => "Stylistic Alternates" => StylisticAlternates,
306    b"sinf" => "Scientific Inferiors" => ScientificInferiors,
307    b"size" => "Optical Size" => OpticalSize,
308    b"smcp" => "Small Capitals" => SmallCapitals,
309    b"smpl" => "Simplified Forms" => SimplifiedForms,
310    b"ss01" => "Stylistic Set 1" => StylisticSet1,
311    b"ss02" => "Stylistic Set 2" => StylisticSet2,
312    b"ss03" => "Stylistic Set 3" => StylisticSet3,
313    b"ss04" => "Stylistic Set 4" => StylisticSet4,
314    b"ss05" => "Stylistic Set 5" => StylisticSet5,
315    b"ss06" => "Stylistic Set 6" => StylisticSet6,
316    b"ss07" => "Stylistic Set 7" => StylisticSet7,
317    b"ss08" => "Stylistic Set 8" => StylisticSet8,
318    b"ss09" => "Stylistic Set 9" => StylisticSet9,
319    b"ss10" => "Stylistic Set 10" => StylisticSet10,
320    b"ss11" => "Stylistic Set 11" => StylisticSet11,
321    b"ss12" => "Stylistic Set 12" => StylisticSet12,
322    b"ss13" => "Stylistic Set 13" => StylisticSet13,
323    b"ss14" => "Stylistic Set 14" => StylisticSet14,
324    b"ss15" => "Stylistic Set 15" => StylisticSet15,
325    b"ss16" => "Stylistic Set 16" => StylisticSet16,
326    b"ss17" => "Stylistic Set 17" => StylisticSet17,
327    b"ss18" => "Stylistic Set 18" => StylisticSet18,
328    b"ss19" => "Stylistic Set 19" => StylisticSet19,
329    b"ss20" => "Stylistic Set 20" => StylisticSet20,
330    b"ssty" => "Math Script Style Alternates" => MathScriptStyleAlternates,
331    b"stch" => "Stretching Glyph Decomposition" => StretchingGlyphDecomposition,
332    b"subs" => "Subscript" => Subscript,
333    b"sups" => "Superscript" => Superscript,
334    b"swsh" => "Swash" => Swash,
335    b"titl" => "Titling" => Titling,
336    b"tjmo" => "Trailing Jamo Forms" => TrailingJamoForms,
337    b"tnam" => "Traditional Name Forms" => TraditionalNameForms,
338    b"tnum" => "Tabular Figures" => TabularFigures,
339    b"trad" => "Traditional Forms" => TraditionalForms,
340    b"twid" => "Third Widths" => ThirdWidths,
341    b"unic" => "Unicase" => Unicase,
342    b"valt" => "Alternate Vertical Metrics" => AlternateVerticalMetrics,
343    b"vatu" => "Vattu Variants" => VattuVariants,
344    b"vchw" => "Vertical Contextual Half-width Spacing" => VerticalContextualHalfWidthSpacing,
345    b"vert" => "Vertical Writing" => VerticalWriting,
346    b"vhal" => "Alternate Vertical Half Metrics" => AlternateVerticalHalfMetrics,
347    b"vjmo" => "Vowel Jamo Forms" => VowelJamoForms,
348    b"vkna" => "Vertical Kana Alternates" => VerticalKanaAlternates,
349    b"vkrn" => "Vertical Kerning" => VerticalKerning,
350    b"vpal" => "Proportional Alternate Vertical Metrics" => ProportionalAlternateVerticalMetrics,
351    b"vrt2" => "Vertical Alternates and Rotation" => VerticalAlternatesAndRotation,
352    b"vrtr" => "Vertical Alternates for Rotation" => VerticalAlternatesForRotation,
353    b"zero" => "Slashed Zero" => SlashedZero,
354}