1use super::buffer::*;
2use super::internal::aat::*;
3
4pub fn apply_morx(
5 data: &[u8],
6 morx: u32,
7 buffer: &mut Buffer,
8 selectors: &[(u16, u16)],
9) -> Option<()> {
10 use morx::*;
11 let max_ops = buffer.glyphs.len() * 16;
12 for chain in chains(data, morx) {
13 let mut ops = 0;
14 let mut flags = chain.default_flags();
15 if !selectors.is_empty() {
16 for feature in chain.features() {
17 let key = (feature.selector, feature.setting_selector);
18 if selectors.binary_search(&key).is_ok() {
19 flags = flags & feature.disable_flags | feature.enable_flags;
20 }
21 }
22 }
23 for (_i, subtable) in chain.subtables().enumerate() {
24 if subtable.flags() & flags == 0 {
25 continue;
29 } else {
30 }
34 let reverse = subtable.should_reverse(buffer.is_rtl);
35 buffer.ensure_order(reverse);
36 let kind = match subtable.kind() {
37 Some(kind) => kind,
38 _ => continue,
39 };
40 match kind {
41 SubtableKind::Rearrangement(t) => {
42 let mut i = 0;
44 let mut state = RearrangementState::new();
45 while i < buffer.glyphs.len() && ops < max_ops {
46 let g = buffer.glyphs[i].id;
47 match t.next(&mut state, i, g, false, |r| {
48 r.apply(&mut buffer.glyphs);
52 Some(())
53 }) {
54 Some(advance) => i += advance,
55 None => break,
56 }
57 ops += 1;
58 }
59 t.next(&mut state, i, 0, true, |r| {
61 r.apply(&mut buffer.glyphs);
62 Some(())
63 });
64 }
65 SubtableKind::Contextual(t) => {
66 let mut state = ContextualState::new();
68 for i in 0..buffer.glyphs.len() {
69 let g = buffer.glyphs[i].id;
70 t.next(&mut state, i, g, false, |i, g| {
71 buffer.substitute(i, g);
72 Some(())
73 });
74 }
75 if let Some(last_id) = buffer.glyphs.last().map(|g| g.id) {
77 t.next(
78 &mut state,
79 buffer.glyphs.len() - 1,
80 last_id,
81 true,
82 |i, g| {
83 buffer.substitute(i, g);
84 Some(())
85 },
86 );
87 }
88 }
89 SubtableKind::NonContextual(t) => {
90 for (_i, g) in buffer.glyphs.iter_mut().enumerate() {
92 if let Some(s) = t.substitute(g.id) {
93 g.id = s;
97 }
98 }
99 }
100 SubtableKind::Ligature(t) => {
101 let mut i = 0;
103 let mut state = LigatureState::new();
104 while i < buffer.glyphs.len() && ops < max_ops {
105 let g = buffer.glyphs[i].id;
106 let f = |i, g, comps: &[usize]| {
107 buffer.substitute_ligature(i, g, comps);
108 Some(())
109 };
110 if t.next(&mut state, i, g, false, f).is_none() {
111 break;
112 }
113 i += 1;
114 ops += 1;
115 }
116 t.next(
118 &mut state,
119 buffer.glyphs.len().saturating_sub(1),
120 0,
121 true,
122 |i, g, comps| {
123 buffer.substitute_ligature(i, g, comps);
124 Some(())
125 },
126 );
127 }
128 SubtableKind::Insertion(t) => {
129 let mut i = 0;
131 let mut state = InsertionState::new();
132 while i < buffer.glyphs.len() && ops < max_ops {
133 let g = buffer.glyphs[i].id;
134 match t.next(&mut state, i, g, false, |i, array| {
135 buffer.multiply(i, array.len());
140 let start = i;
141 let end = start + array.len();
142 for (g, s) in buffer.glyphs[start..end].iter_mut().zip(array.iter()) {
143 g.id = s;
144 g.flags = 0;
145 }
146 Some(())
147 }) {
148 Some(advance) => i += advance,
149 None => break,
150 }
151 ops += 1;
152 }
153 t.next(
155 &mut state,
156 buffer.glyphs.len().saturating_sub(1),
157 0,
158 true,
159 |i, array| {
160 buffer.multiply(i, array.len());
161 let start = i;
162 let end = start + array.len();
163 for (g, s) in buffer.glyphs[start..end].iter_mut().zip(array.iter()) {
164 g.id = s;
165 g.flags = 0;
166 }
167 Some(())
168 },
169 );
170 }
171 }
172 }
173 }
174 buffer.ensure_order(false);
175 Some(())
176}
177
178pub fn apply_kerx(
179 data: &[u8],
180 kerx: u32,
181 ankr: u32,
182 buffer: &mut Buffer,
183 disable_kern: bool,
184) -> Option<()> {
185 use kerx::*;
186 for (_i, subtable) in subtables(data, kerx, ankr).enumerate() {
187 let reverse = subtable.should_reverse(buffer.is_rtl);
191 buffer.ensure_order(reverse);
192 let kind = match subtable.kind() {
193 Some(kind) => kind,
194 _ => continue,
195 };
196 if subtable.is_vertical() || subtable.is_cross_stream() {
197 continue;
198 }
199 match kind {
200 SubtableKind::Format0(t) => {
201 if disable_kern {
202 continue;
203 }
204 let len = buffer.len();
205 let mut left_index = if let Some((index, _)) = buffer
206 .glyphs
207 .iter()
208 .enumerate()
209 .find(|(_, g)| g.joining_type != 6)
210 {
211 index
212 } else {
213 continue;
214 };
215 let mut left = buffer.glyphs[left_index].id;
216 for i in left_index + 1..len {
217 if buffer.glyphs[i].joining_type == 6 {
218 continue;
219 }
220 let right = buffer.glyphs[i].id;
221 if let Some(kerning) = t.get(left, right) {
222 if kerning != 0 {
223 buffer.positions[left_index].advance += kerning as f32;
227 }
228 }
229 left_index = i;
230 left = right;
231 }
232 }
233 SubtableKind::Format1(t) => {
234 if disable_kern {
235 continue;
236 }
237 let mut i = 0;
238 let len = buffer.glyphs.len();
239 let mut state = ContextualState::new();
240 while i < len {
241 match t.next(&mut state, i, buffer.glyphs[i].id, |i, kerning| {
242 buffer.positions[i].advance += kerning as f32;
243 Some(())
244 }) {
245 Some(advance) => i += advance,
246 None => break,
247 }
248 }
249 }
250 SubtableKind::Format2(t) => {
251 if disable_kern {
252 continue;
253 }
254 let len = buffer.len();
256 let mut left_index = if let Some((index, _)) = buffer
257 .glyphs
258 .iter()
259 .enumerate()
260 .find(|(_, g)| g.joining_type != 6)
261 {
262 index
263 } else {
264 continue;
265 };
266 let mut left = buffer.glyphs[left_index].id;
267 for i in left_index + 1..len {
268 if buffer.glyphs[i].joining_type == 6 {
269 continue;
270 }
271 let right = buffer.glyphs[i].id;
272 if let Some(kerning) = t.get(left, right) {
273 if kerning != 0 {
274 buffer.positions[left_index].advance += kerning as f32;
278 }
279 }
280 left_index = i;
281 left = right;
282 }
283 }
284 SubtableKind::Format4(t) => {
285 let mut i = 0;
286 let len = buffer.glyphs.len();
287 let mut state = Format4State::new();
288 while i < len {
289 match t.next(&mut state, i, buffer.glyphs[i].id, |i, base, x, y| {
290 buffer.position_mark(i, base, x, y);
291 Some(())
292 }) {
293 Some(advance) => i += advance,
294 None => break,
295 }
296 }
297 }
298 }
299 }
300 buffer.ensure_order(false);
301 Some(())
302}
303
304pub fn apply_kern(data: &[u8], kern: u32, buffer: &mut Buffer) -> Option<()> {
305 use kern::*;
306 for (_i, subtable) in subtables(data, kern).enumerate() {
307 let kind = match subtable.kind() {
308 Some(kind) => kind,
309 _ => continue,
310 };
311 if !subtable.is_horizontal() {
312 continue;
313 }
314 buffer.ensure_order(buffer.is_rtl);
315 let cross_stream = subtable.cross_stream();
316 match kind {
317 SubtableKind::Format0(t) => {
318 buffer.ensure_order(false);
319 let len = buffer.len();
320 let mut left_index = if let Some((index, _)) = buffer
321 .glyphs
322 .iter()
323 .enumerate()
324 .find(|(_, g)| g.joining_type != 6)
325 {
326 index
327 } else {
328 continue;
329 };
330 let mut left = buffer.glyphs[left_index].id;
331 for i in left_index + 1..len {
332 if buffer.glyphs[i].joining_type == 6 {
333 continue;
334 }
335 let right = buffer.glyphs[i].id;
336 if let Some(kerning) = t.get(left, right) {
337 if kerning != 0 {
338 buffer.positions[left_index].advance += kerning as f32;
342 }
343 }
344 left_index = i;
345 left = right;
346 }
347 }
348 SubtableKind::Format1(t) => {
349 let mut i = 0;
350 let len = buffer.glyphs.len();
351 let mut state = Format1State::new();
352 while i < len {
353 match t.next(&mut state, i, buffer.glyphs[i].id, |i, kerning| {
354 let g = &buffer.glyphs[i];
355 if g.joining_type == 6 {
356 if cross_stream {
357 let pos = &mut buffer.positions[i];
358 if pos.y == 0. {
359 pos.y = kerning as f32;
360 }
361 } else if let Some(base) = find_base(buffer, buffer.is_rtl, i) {
362 let diff = if base >= i { base - i } else { i - base };
363 if diff < 255 {
364 let pos = &mut buffer.positions[i];
365 if pos.base == 0 {
366 pos.flags |= MARK_ATTACH;
367 pos.base = diff as u8;
368 pos.x = kerning as f32;
369 buffer.has_marks = true;
370 }
371 }
372 }
373 }
374 Some(())
375 }) {
376 Some(advance) => i += advance,
377 None => break,
378 }
379 }
380 }
381 }
382 }
383 buffer.ensure_order(false);
384 Some(())
385}
386
387fn find_base(buffer: &Buffer, reverse: bool, index: usize) -> Option<usize> {
388 use crate::text::cluster::ShapeClass;
389 let cluster = buffer.glyphs[index].cluster;
390 if reverse {
391 for i in index + 1..buffer.len() {
392 let g = &buffer.glyphs[i];
393 if g.cluster != cluster {
394 return None;
395 }
396 if g.char_class == ShapeClass::Base {
397 return Some(i);
398 }
399 }
400 } else if index > 0 {
401 for i in (0..index).rev() {
402 let g = &buffer.glyphs[i];
403 if g.cluster != cluster {
404 return None;
405 }
406 if g.char_class == ShapeClass::Base {
407 return Some(i);
408 }
409 }
410 }
411 None
412}