rustybuzz/hb/
ot_layout_common.rs

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