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 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
133fn 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}