rustybuzz/hb/
ot_layout_common.rs

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