rustybuzz/hb/
ot_layout_common.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use alloc::vec::Vec;

use ttf_parser::gpos::PositioningSubtable;
use ttf_parser::gsub::SubstitutionSubtable;
use ttf_parser::opentype_layout::{Coverage, Lookup};

use super::glyph_set::{GlyphSet, GlyphSetBuilder};

#[allow(dead_code)]
pub mod lookup_flags {
    pub const RIGHT_TO_LEFT: u16 = 0x0001;
    pub const IGNORE_BASE_GLYPHS: u16 = 0x0002;
    pub const IGNORE_LIGATURES: u16 = 0x0004;
    pub const IGNORE_MARKS: u16 = 0x0008;
    pub const IGNORE_FLAGS: u16 = 0x000E;
    pub const USE_MARK_FILTERING_SET: u16 = 0x0010;
    pub const MARK_ATTACHMENT_TYPE_MASK: u16 = 0xFF00;
}

#[derive(Clone)]
pub struct PositioningTable<'a> {
    pub inner: ttf_parser::opentype_layout::LayoutTable<'a>,
    pub lookups: Vec<PositioningLookup<'a>>,
}

impl<'a> PositioningTable<'a> {
    pub fn new(inner: ttf_parser::opentype_layout::LayoutTable<'a>) -> Self {
        let lookups = inner
            .lookups
            .into_iter()
            .map(PositioningLookup::parse)
            .collect();

        Self { inner, lookups }
    }
}

pub trait CoverageExt {
    fn collect(&self, set: &mut GlyphSetBuilder);
}

impl CoverageExt for Coverage<'_> {
    /// Collect this coverage table into a glyph set.
    fn collect(&self, set: &mut GlyphSetBuilder) {
        match *self {
            Self::Format1 { glyphs } => {
                for glyph in glyphs {
                    set.insert(glyph);
                }
            }
            Self::Format2 { records } => {
                for record in records {
                    set.insert_range(record.start..=record.end);
                }
            }
        }
    }
}

#[derive(Clone)]
pub struct PositioningLookup<'a> {
    pub subtables: Vec<PositioningSubtable<'a>>,
    pub coverage: GlyphSet,
    pub props: u32,
}

impl<'a> PositioningLookup<'a> {
    pub fn parse(lookup: Lookup<'a>) -> Self {
        let subtables: Vec<_> = lookup
            .subtables
            .into_iter::<PositioningSubtable>()
            .collect();

        let mut coverage = GlyphSet::builder();
        for subtable in &subtables {
            subtable.coverage().collect(&mut coverage);
        }

        Self {
            subtables,
            coverage: coverage.finish(),
            props: lookup_props(lookup),
        }
    }
}

#[derive(Clone)]
pub struct SubstitutionTable<'a> {
    pub inner: ttf_parser::opentype_layout::LayoutTable<'a>,
    pub lookups: Vec<SubstLookup<'a>>,
}

impl<'a> SubstitutionTable<'a> {
    pub fn new(inner: ttf_parser::opentype_layout::LayoutTable<'a>) -> Self {
        let lookups = inner.lookups.into_iter().map(SubstLookup::parse).collect();

        Self { inner, lookups }
    }
}

#[derive(Clone)]
pub struct SubstLookup<'a> {
    pub subtables: Vec<SubstitutionSubtable<'a>>,
    pub coverage: GlyphSet,
    pub reverse: bool,
    pub props: u32,
}

impl<'a> SubstLookup<'a> {
    pub fn parse(lookup: Lookup<'a>) -> Self {
        let subtables: Vec<_> = lookup
            .subtables
            .into_iter::<SubstitutionSubtable>()
            .collect();

        let mut coverage = GlyphSet::builder();
        let mut reverse = !subtables.is_empty();

        for subtable in &subtables {
            subtable.coverage().collect(&mut coverage);
            reverse &= subtable.is_reverse();
        }

        Self {
            subtables,
            coverage: coverage.finish(),
            reverse,
            props: lookup_props(lookup),
        }
    }
}

// lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
// higher 16-bit is mark-filtering-set if the lookup uses one.
// Not to be confused with glyph_props which is very similar. */
fn lookup_props(lookup: Lookup) -> u32 {
    let mut props = u32::from(lookup.flags.0);
    if let Some(set) = lookup.mark_filtering_set {
        props |= u32::from(set) << 16;
    }
    props
}