1use crate::figfont::FIGfont;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum LayoutMode {
12 FullWidth,
14 Kerning,
16 UniversalSmush,
18 RuleSmush(u8),
20 OverlapOnly,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum Justify {
28 Center,
30 Left,
32 Right,
34 FontDefault,
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub enum LayoutFlag {
42 Kerning,
44 FullWidth,
46 ForceSmush,
48 FontDefaultSmush,
50 OverlapOnly,
52 Explicit(i32),
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub enum JustifyFlag {
59 Center,
61 Left,
63 Right,
65 FontDefault,
67}
68
69#[derive(Debug, Clone, Default)]
71pub struct LayoutFlags {
72 pub flags: Vec<LayoutFlag>,
74}
75
76#[derive(Debug, Clone, Default)]
78pub struct JustifyFlags {
79 pub flags: Vec<JustifyFlag>,
81}
82
83pub struct LayoutResolver;
86
87impl LayoutResolver {
88 pub fn resolve(font: &FIGfont, flags: &LayoutFlags) -> LayoutMode {
93 if let Some(last) = flags.flags.last() {
94 return match *last {
95 LayoutFlag::Kerning => LayoutMode::Kerning,
96 LayoutFlag::FullWidth => LayoutMode::FullWidth,
97 LayoutFlag::ForceSmush => {
98 let bits = (font.full_layout & 0b0011_1111) as u8;
99 if bits == 0 {
100 LayoutMode::UniversalSmush
101 } else {
102 LayoutMode::RuleSmush(bits)
103 }
104 }
105 LayoutFlag::FontDefaultSmush => font_default_mode(font),
106 LayoutFlag::OverlapOnly => LayoutMode::OverlapOnly,
107 LayoutFlag::Explicit(n) => explicit_mode(n),
108 };
109 }
110 font_default_mode(font)
111 }
112}
113
114fn font_default_mode(font: &FIGfont) -> LayoutMode {
115 let smushing = font.full_layout & (crate::smush::RULE_HORIZONTAL_SMUSHING as u32) != 0;
116 let kerning = font.full_layout & (crate::smush::RULE_HORIZONTAL_KERNING as u32) != 0;
117 let bits = (font.full_layout & 0b0011_1111) as u8;
118 if smushing {
119 if bits == 0 {
120 LayoutMode::UniversalSmush
121 } else {
122 LayoutMode::RuleSmush(bits)
123 }
124 } else if kerning {
125 LayoutMode::Kerning
126 } else {
127 LayoutMode::FullWidth
128 }
129}
130
131fn explicit_mode(n: i32) -> LayoutMode {
132 match n {
133 -1 => LayoutMode::FullWidth,
134 0 => LayoutMode::Kerning,
135 -2 => LayoutMode::Kerning,
138 bits if (1..=63).contains(&bits) => LayoutMode::RuleSmush(bits as u8),
139 _ => LayoutMode::FullWidth,
140 }
141}
142
143pub fn resolve_justify(flags: &JustifyFlags) -> Justify {
147 flags
148 .flags
149 .last()
150 .map(|f| match *f {
151 JustifyFlag::Center => Justify::Center,
152 JustifyFlag::Left => Justify::Left,
153 JustifyFlag::Right => Justify::Right,
154 JustifyFlag::FontDefault => Justify::FontDefault,
155 })
156 .unwrap_or(Justify::FontDefault)
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162 use crate::figfont::parse_bytes;
163
164 fn font() -> FIGfont {
165 parse_bytes(crate::figfont::BUNDLED_FONTS[0].1).expect("bundled font parses")
166 }
167
168 #[test]
169 fn empty_flags_yields_font_default() {
170 let mode = LayoutResolver::resolve(&font(), &LayoutFlags::default());
171 let _ = mode; }
173
174 #[test]
175 fn last_wins_layout_kerning() {
176 let f = LayoutFlags {
177 flags: vec![
178 LayoutFlag::FullWidth,
179 LayoutFlag::ForceSmush,
180 LayoutFlag::Kerning,
181 ],
182 };
183 assert_eq!(LayoutResolver::resolve(&font(), &f), LayoutMode::Kerning);
184 }
185
186 #[test]
187 fn explicit_layout_bitfield_24() {
188 let f = LayoutFlags {
189 flags: vec![LayoutFlag::Explicit(24)],
190 };
191 assert_eq!(
192 LayoutResolver::resolve(&font(), &f),
193 LayoutMode::RuleSmush(24)
194 );
195 }
196
197 #[test]
198 fn explicit_layout_zero_is_kerning() {
199 let f = LayoutFlags {
200 flags: vec![LayoutFlag::Explicit(0)],
201 };
202 assert_eq!(LayoutResolver::resolve(&font(), &f), LayoutMode::Kerning);
203 }
204
205 #[test]
206 fn justify_last_wins() {
207 let j = JustifyFlags {
208 flags: vec![JustifyFlag::Left, JustifyFlag::Center, JustifyFlag::Right],
209 };
210 assert_eq!(resolve_justify(&j), Justify::Right);
211 }
212
213 #[test]
214 fn justify_empty_yields_font_default() {
215 assert_eq!(
216 resolve_justify(&JustifyFlags::default()),
217 Justify::FontDefault
218 );
219 }
220}