1use super::{Gdef, Layout, Lookup, LookupFilter, LookupFlag, LookupKind, LookupRecord, Stage};
2use crate::parse_prelude::*;
3
4impl<'a> Layout<'a> {
5 pub fn new(stage: Stage, data: &'a [u8], gdef: Option<Gdef<'a>>) -> Self {
9 Self {
10 stage,
11 data: Buffer::new(data),
12 gdef,
13 }
14 }
15
16 pub fn stage(&self) -> Stage {
18 self.stage
19 }
20
21 pub fn data(&self) -> &'a [u8] {
23 self.data.data()
24 }
25
26 pub fn gdef(&self) -> Option<&Gdef<'a>> {
28 self.gdef.as_ref()
29 }
30
31 pub fn num_scripts(&self) -> u16 {
33 if let Some(base) = self.data.read_u16(4) {
34 self.data.read_u16(base as usize).unwrap_or(0)
35 } else {
36 0
37 }
38 }
39
40 pub fn script(&'a self, index: u16) -> Option<Script<'a>> {
42 let b = &self.data;
43 let list_base = b.read_u16(4)? as usize;
44 let len = b.read_u16(list_base)?;
45 if index >= len {
46 return None;
47 }
48 let record_base = list_base + 2 + index as usize * 6;
49 let tag = b.read_tag(record_base)?;
50 let mut offset = b.read_u16(record_base + 4)? as u32;
51 if offset == 0 {
52 return None;
53 }
54 offset += list_base as u32;
55 let num_languages = b.read_u16(offset as usize + 2)?;
56 let record = ScriptRecord {
57 tag,
58 offset,
59 num_languages,
60 };
61 Some(record.materialize(self))
62 }
63
64 pub fn scripts(&'a self) -> impl Iterator<Item = Script<'a>> + 'a + Clone {
66 (0..self.num_scripts()).filter_map(move |index| self.script(index))
67 }
68
69 pub fn num_features(&self) -> u16 {
71 if let Some(base) = self.data.read_u16(6) {
72 self.data.read_u16(base as usize).unwrap_or(0)
73 } else {
74 0
75 }
76 }
77
78 pub fn feature(&'a self, index: u16) -> Option<Feature<'a>> {
80 let b = &self.data;
81 let list_base = b.read_u16(6)? as usize;
82 let len = b.read_u16(list_base)?;
83 if index >= len {
84 return None;
85 }
86 let record_base = list_base + 2 + index as usize * 6;
87 let tag = b.read_tag(record_base)?;
88 let offset = b.read_u16(record_base + 4)? as u32;
89 if offset == 0 {
90 return None;
91 }
92 Some(
93 FeatureRecord {
94 index,
95 tag,
96 offset: list_base as u32 + offset,
97 }
98 .materialize(self),
99 )
100 }
101
102 pub fn features(&'a self) -> impl Iterator<Item = Feature<'a>> + 'a + Clone {
104 (0..self.num_features()).filter_map(move |index| self.feature(index))
105 }
106
107 pub fn feature_variations(&'a self) -> Option<FeatureVariations<'a>> {
109 if self.data.read_u16(2) >= Some(1) {
111 let offset = self.data.read_offset32(10, 0)? as usize;
112 let len = self.data.read_u32(offset + 4)?;
113 Some(FeatureVariations {
114 layout: self,
115 base: offset,
116 len,
117 })
118 } else {
119 None
120 }
121 }
122
123 pub fn num_lookups(&self) -> u16 {
125 if let Some(base) = self.data.read_u16(8) {
126 self.data.read_u16(base as usize).unwrap_or(0)
127 } else {
128 0
129 }
130 }
131
132 pub fn lookup(&'a self, index: u16) -> Option<Lookup<'a>> {
134 let b = &self.data;
135 let list_base = b.read_u16(8)? as usize;
136 let len = b.read_u16(list_base)?;
137 if index >= len {
138 return None;
139 }
140 let base = list_base + b.read_u16(list_base + 2 + index as usize * 2)? as usize;
141 let mut kind = b.read_u16(base)? as u8;
142 let flag = b.read_u16(base + 2)?;
143 let f = flag as u8;
144 let num_subtables = b.read_u16(base + 4)?;
145 let mark_class = (flag >> 8) as u8;
146 let ignore_marks = f & (1 << 3) != 0;
147 let mut mark_check = false;
148 let mut mark_set = 0;
149 if !ignore_marks {
150 if let Some(gdef) = &self.gdef {
151 mark_check = mark_class != 0 && gdef.has_mark_classes();
152 mark_set = if flag & 0x10 != 0 {
153 let idx = b.read_u16(base + 6 + num_subtables as usize * 2)?;
154 mark_check = true;
155 gdef.mark_set_offset(idx).unwrap_or(0)
156 } else {
157 0
158 };
159 }
160 }
161 let is_sub = self.stage == Stage::Substitution;
162 let subtables = base + 6;
163 let is_extension = (is_sub && kind == 7) || (!is_sub && kind == 9);
164 if is_extension && num_subtables > 0 {
165 let s = base + b.read_u16(subtables)? as usize;
166 kind = b.read_u16(s + 2)? as u8;
167 }
168 use LookupKind::*;
169 let kind = if is_sub {
170 match kind {
171 1 => SingleSubst,
172 2 => MultipleSubst,
173 3 => AlternateSubst,
174 4 => LigatureSubst,
175 5 => SeqContext,
176 6 => ChainContext,
177 8 => RevChainContext,
178 _ => return None,
179 }
180 } else {
181 match kind {
182 1 => SinglePos,
183 2 => PairPos,
184 3 => CursivePos,
185 4 => MarkPos,
186 5 => MarkLigaturePos,
187 6 => MarkMarkPos,
188 7 => SeqContext,
189 8 => ChainContext,
190 _ => return None,
191 }
192 };
193 let ignored_classes = ((f as u8) & 0b1110) | 1 << 5;
194 let filter = LookupFilter {
195 ignored_classes,
196 mask: 0,
197 mark_check,
198 mark_class,
199 mark_set,
200 };
201 Some(
202 LookupRecord {
203 index,
204 stage: self.stage,
205 kind,
206 flag: LookupFlag(flag),
207 filter,
208 is_extension,
209 offset: base as u32,
210 num_subtables,
211 }
212 .materialize(self),
213 )
214 }
215
216 pub fn lookups(&'a self) -> impl Iterator<Item = Lookup<'a>> + 'a + Clone {
218 (0..self.num_lookups()).filter_map(move |index| self.lookup(index))
219 }
220}
221
222#[derive(Copy, Clone)]
224pub struct ScriptRecord {
225 pub tag: Tag,
227 pub offset: u32,
230 pub num_languages: u16,
232}
233
234impl ScriptRecord {
235 pub fn materialize<'a>(&self, layout: &'a Layout<'a>) -> Script<'a> {
238 Script {
239 layout,
240 record: *self,
241 }
242 }
243}
244
245#[derive(Copy, Clone)]
249pub struct Script<'a> {
250 pub layout: &'a Layout<'a>,
252 pub record: ScriptRecord,
254}
255
256impl<'a> Script<'a> {
257 pub fn default_language(&self) -> Option<Language<'a>> {
259 let data = &self.layout.data;
260 let base = self.record.offset;
261 let offset = data.read_u16(base as usize)? as u32;
262 if offset != 0 {
263 let tag = Tag::new(b"DFLT");
264 let record = LanguageRecord {
265 script: self.record,
266 is_default: true,
267 tag,
268 offset: base + offset,
269 };
270 Some(Language {
271 script: *self,
272 record,
273 })
274 } else {
275 None
276 }
277 }
278
279 pub fn num_languages(&self) -> u16 {
281 self.record.num_languages
282 }
283
284 pub fn language(&self, index: u16) -> Option<Language<'a>> {
286 if index >= self.record.num_languages {
287 return None;
288 }
289 let data = &self.layout.data;
290 let base = self.record.offset;
291 let record_base = base as usize + 4 + index as usize * 6;
292 let tag = data.read_tag(record_base)?;
293 let mut offset = data.read_u16(record_base + 4)? as u32;
294 if offset == 0 {
295 return None;
296 }
297 offset += base;
298 let record = LanguageRecord {
299 script: self.record,
300 is_default: false,
301 tag,
302 offset,
303 };
304 Some(Language {
305 script: *self,
306 record,
307 })
308 }
309
310 pub fn languages(self) -> impl Iterator<Item = Language<'a>> + 'a + Clone {
312 (0..self.record.num_languages).filter_map(move |index| self.language(index))
313 }
314}
315
316#[derive(Copy, Clone)]
318pub struct LanguageRecord {
319 pub script: ScriptRecord,
321 pub is_default: bool,
323 pub tag: Tag,
325 pub offset: u32,
328}
329
330impl LanguageRecord {
331 pub fn code(&self) -> Option<&'static str> {
333 None
335 }
336
337 pub fn materialize<'a>(&self, table: &'a Layout<'a>) -> Language<'a> {
340 let script = self.script.materialize(table);
341 Language {
342 script,
343 record: *self,
344 }
345 }
346}
347
348#[derive(Copy, Clone)]
352pub struct Language<'a> {
353 pub script: Script<'a>,
355 pub record: LanguageRecord,
357}
358
359impl<'a> Language<'a> {
360 pub fn layout(&self) -> &Layout<'a> {
362 self.script.layout
363 }
364
365 pub fn tag(&self) -> Tag {
367 self.record.tag
368 }
369
370 pub fn code(&self) -> Option<&'static str> {
372 self.record.code()
373 }
374
375 pub fn feature_indices(&self) -> Slice<'a, u16> {
377 let data = &self.layout().data;
378 data.read_slice16(self.record.offset as usize + 4)
379 .unwrap_or_default()
380 }
381
382 pub fn features(&'a self) -> impl Iterator<Item = Feature<'a>> + 'a + Clone {
384 self.feature_indices()
385 .iter()
386 .filter_map(move |index| self.layout().feature(index))
387 }
388}
389
390#[derive(Copy, Clone, Debug)]
392pub struct FeatureRecord {
393 pub index: u16,
395 pub tag: Tag,
397 pub offset: u32,
400}
401
402impl FeatureRecord {
403 pub fn materialize<'a>(&self, layout: &'a Layout<'a>) -> Feature<'a> {
404 Feature {
405 layout,
406 record: *self,
407 }
408 }
409}
410
411#[derive(Copy, Clone)]
415pub struct Feature<'a> {
416 pub layout: &'a Layout<'a>,
418 pub record: FeatureRecord,
420}
421
422impl<'a> Feature<'a> {
423 pub fn lookup_indices(&self) -> Slice<'a, u16> {
425 self.layout
426 .data
427 .read_slice16(self.record.offset as usize + 2)
428 .unwrap_or_default()
429 }
430
431 pub fn lookups(&'a self) -> impl Iterator<Item = Lookup<'a>> + 'a + Clone {
433 self.lookup_indices()
434 .iter()
435 .filter_map(move |index| self.layout.lookup(index))
436 }
437}
438
439#[derive(Copy, Clone)]
443pub struct FeatureVariations<'a> {
444 layout: &'a Layout<'a>,
445 base: usize,
446 len: u32,
447}
448
449impl<'a> FeatureVariations<'a> {
450 pub fn len(&self) -> u32 {
452 self.len
453 }
454
455 pub fn is_empty(&self) -> bool {
457 self.len == 0
458 }
459
460 pub fn get(&self, index: u32) -> Option<ConditionSet<'a>> {
462 if index >= self.len {
463 return None;
464 }
465 let data = &self.layout.data;
466 let record_base = self.base + 8 + index as usize * 8;
467 let condition_set = data.read_offset32(record_base, self.base as u32)? as usize;
468 let feature_subst = data.read_offset32(record_base + 4, self.base as u32)?;
469 let len = data.read_u16(condition_set)?;
470 Some(ConditionSet {
471 layout: self.layout,
472 base: condition_set,
473 feature_subst,
474 len,
475 })
476 }
477
478 pub fn iter(&'a self) -> impl Iterator<Item = ConditionSet<'a>> + 'a + Clone {
480 (0..self.len).filter_map(move |index| self.get(index))
481 }
482
483 pub fn find(&'a self, coords: &[NormalizedCoord]) -> Option<ConditionSet<'a>> {
486 for set in self.iter() {
487 let mut satisfied = true;
488 for condition in set.iter() {
489 let coord = coords
490 .get(condition.axis_index as usize)
491 .copied()
492 .unwrap_or(0);
493 if coord < condition.min_value || coord > condition.max_value {
494 satisfied = false;
495 break;
496 }
497 }
498 if satisfied {
499 return Some(set);
500 }
501 }
502 None
503 }
504}
505
506#[derive(Copy, Clone)]
510pub struct ConditionSet<'a> {
511 layout: &'a Layout<'a>,
512 base: usize,
513 feature_subst: u32,
514 len: u16,
515}
516
517impl<'a> ConditionSet<'a> {
518 pub fn len(&self) -> u16 {
520 self.len
521 }
522
523 pub fn is_empty(&self) -> bool {
525 self.len == 0
526 }
527
528 pub fn get(&self, index: u16) -> Option<Condition> {
530 if index >= self.len {
531 return None;
532 }
533 let data = &self.layout.data;
534 let offset =
535 data.read_offset32(self.base + 2 + index as usize * 4, self.base as u32)? as usize;
536 let format = data.read_u16(offset)?;
537 if format != 1 {
538 return None;
539 }
540 let axis_index = data.read_u16(offset + 2)?;
541 let min_value = data.read_i16(offset + 4)?;
542 let max_value = data.read_i16(offset + 6)?;
543 Some(Condition {
544 axis_index,
545 min_value,
546 max_value,
547 })
548 }
549
550 pub fn iter(&'a self) -> impl Iterator<Item = Condition> + 'a + Clone {
552 (0..self.len).filter_map(move |index| self.get(index))
553 }
554
555 pub fn features(&self) -> FeatureSubst<'a> {
557 let data = &self.layout.data;
558 let len = data.read_u16(self.feature_subst as usize + 4).unwrap_or(0);
559 FeatureSubst {
560 layout: self.layout,
561 base: self.feature_subst as usize,
562 len,
563 }
564 }
565}
566
567#[derive(Copy, Clone, Debug)]
571pub struct Condition {
572 pub axis_index: u16,
574 pub min_value: NormalizedCoord,
576 pub max_value: NormalizedCoord,
578}
579
580#[derive(Copy, Clone)]
584pub struct FeatureSubst<'a> {
585 layout: &'a Layout<'a>,
586 base: usize,
587 len: u16,
588}
589
590impl<'a> FeatureSubst<'a> {
591 pub fn len(&self) -> u16 {
593 self.len
594 }
595
596 pub fn is_empty(&self) -> bool {
598 self.len == 0
599 }
600
601 pub fn get(&self, index: u16) -> Option<Feature<'a>> {
603 if index >= self.len() {
604 return None;
605 }
606 let data = &self.layout.data;
607 let subst_base = self.base + 6 + index as usize * 6;
608 let feature_index = data.read_u16(subst_base)?;
609 let offset = data.read_offset32(subst_base + 2, self.base as u32)?;
610 Some(
611 FeatureRecord {
612 tag: Tag(0),
613 index: feature_index,
614 offset,
615 }
616 .materialize(self.layout),
617 )
618 }
619
620 pub fn iter(&'a self) -> impl Iterator<Item = Feature<'a>> + 'a + Clone {
622 (0..self.len).filter_map(move |index| self.get(index))
623 }
624
625 pub fn find(&self, feature_index: u16) -> Option<Feature<'a>> {
627 for i in 0..self.len() {
628 if let Some(feature) = self.get(i) {
629 if feature.record.index == feature_index {
630 return Some(feature);
631 }
632 if feature.record.index > feature_index {
633 return None;
634 }
635 }
636 }
637 None
638 }
639}