swash/shape/
partition.rs
1use super::{Direction, ShapeContext, Shaper};
7use crate::text::cluster::{CharCluster, Parser, Token};
8use crate::text::{Codepoint as _, Language, Script};
9use crate::{FontRef, Setting, Synthesis};
10use core::iter::Copied;
11use core::slice;
12
13pub trait Selector {
15 type SelectedFont: SelectedFont;
17
18 fn select_font(&mut self, cluster: &mut CharCluster) -> Option<Self::SelectedFont>;
20}
21
22pub trait SelectedFont: PartialEq {
24 fn font(&self) -> FontRef;
26
27 fn id_override(&self) -> Option<[u64; 2]> {
28 None
29 }
30
31 fn synthesis(&self) -> Option<Synthesis> {
33 None
34 }
35}
36
37pub trait ShapeOptions {
39 type Features: Iterator<Item = Setting<u16>>;
41
42 type Variations: Iterator<Item = Setting<f32>>;
44
45 fn script(&self) -> Script {
47 Script::Latin
48 }
49
50 fn language(&self) -> Option<Language> {
52 None
53 }
54
55 fn direction(&self) -> Direction {
57 Direction::LeftToRight
58 }
59
60 fn size(&self) -> f32 {
62 0.
63 }
64
65 fn features(&self) -> Self::Features;
67
68 fn variations(&self) -> Self::Variations;
70
71 fn insert_dotted_circles(&self) -> bool {
74 false
75 }
76}
77
78#[derive(Copy, Clone)]
80pub struct SimpleShapeOptions<'a> {
81 pub script: Script,
83 pub language: Option<Language>,
85 pub direction: Direction,
87 pub size: f32,
89 pub features: &'a [Setting<u16>],
91 pub variations: &'a [Setting<f32>],
93 pub insert_dotted_circles: bool,
95}
96
97impl Default for SimpleShapeOptions<'_> {
98 fn default() -> Self {
99 Self {
100 script: Script::Latin,
101 language: None,
102 direction: Direction::LeftToRight,
103 size: 0.,
104 features: &[],
105 variations: &[],
106 insert_dotted_circles: false,
107 }
108 }
109}
110
111impl<'a> ShapeOptions for SimpleShapeOptions<'a> {
112 type Features = Copied<slice::Iter<'a, Setting<u16>>>;
113 type Variations = Copied<slice::Iter<'a, Setting<f32>>>;
114
115 fn script(&self) -> Script {
116 self.script
117 }
118
119 fn language(&self) -> Option<Language> {
120 self.language
121 }
122
123 fn direction(&self) -> Direction {
124 self.direction
125 }
126
127 fn size(&self) -> f32 {
128 self.size
129 }
130
131 fn features(&self) -> Self::Features {
132 self.features.iter().copied()
133 }
134
135 fn variations(&self) -> Self::Variations {
136 self.variations.iter().copied()
137 }
138
139 fn insert_dotted_circles(&self) -> bool {
140 self.insert_dotted_circles
141 }
142}
143
144pub fn shape<S, T>(
148 context: &mut ShapeContext,
149 selector: &mut S,
150 options: &impl ShapeOptions,
151 tokens: T,
152 mut f: impl FnMut(&S::SelectedFont, Shaper),
153) where
154 S: Selector,
155 T: IntoIterator<Item = Token>,
156 T::IntoIter: Clone,
157{
158 let mut cluster = CharCluster::new();
159 if options.direction() == Direction::RightToLeft {
160 let mut parser = Parser::new(
161 options.script(),
162 tokens.into_iter().map(|mut t| {
163 t.ch = t.ch.mirror().unwrap_or(t.ch);
164 t
165 }),
166 );
167 if !parser.next(&mut cluster) {
168 return;
169 }
170 let mut font = selector.select_font(&mut cluster);
171 while shape_clusters(
172 context,
173 selector,
174 options,
175 &mut parser,
176 &mut cluster,
177 &mut font,
178 &mut f,
179 ) {}
180 } else {
181 let mut parser = Parser::new(options.script(), tokens.into_iter());
182 if !parser.next(&mut cluster) {
183 return;
184 }
185 let mut font = selector.select_font(&mut cluster);
186 while shape_clusters(
187 context,
188 selector,
189 options,
190 &mut parser,
191 &mut cluster,
192 &mut font,
193 &mut f,
194 ) {}
195 }
196}
197
198fn shape_clusters<S, T>(
199 context: &mut ShapeContext,
200 selector: &mut S,
201 options: &impl ShapeOptions,
202 parser: &mut Parser<T>,
203 cluster: &mut CharCluster,
204 current_font: &mut Option<S::SelectedFont>,
205 f: &mut impl FnMut(&S::SelectedFont, Shaper),
206) -> bool
207where
208 S: Selector,
209 T: Iterator<Item = Token> + Clone,
210{
211 if current_font.is_none() {
212 return false;
213 }
214 let font = current_font.as_ref().unwrap();
215 let font_ref = font.font();
216 let id = font
217 .id_override()
218 .unwrap_or([font_ref.key.value(), u64::MAX]);
219 let mut shaper = context
220 .builder_with_id(font.font(), id)
221 .script(options.script())
222 .language(options.language())
223 .direction(options.direction())
224 .size(options.size())
225 .features(options.features())
226 .variations(
227 font.synthesis()
228 .as_ref()
229 .map(|s| s.variations())
230 .unwrap_or(&[])
231 .iter()
232 .copied(),
233 )
234 .variations(options.variations())
235 .insert_dotted_circles(options.insert_dotted_circles())
236 .build();
237 loop {
238 shaper.add_cluster(cluster);
239 if !parser.next(cluster) {
240 f(font, shaper);
241 return false;
242 }
243 if let Some(next_font) = selector.select_font(cluster) {
244 if next_font != *font {
245 f(font, shaper);
246 *current_font = Some(next_font);
247 return true;
248 }
249 } else {
250 return false;
251 }
252 }
253}