1use alloc::vec::Vec;
2use core::cmp::Ordering;
3use core::ops::Range;
4
5use super::buffer::{hb_buffer_t, GlyphFlags};
6use super::common::TagExt;
7use super::font_funcs::FontFuncsDispatch;
8use super::ot_layout::TableIndex;
9use super::ot_shape_plan::hb_ot_shape_plan_t;
10use super::{hb_font_t, hb_mask_t, hb_tag_t, tag, Language, Script};
11
12use core::mem::{size_of, size_of_val};
14
15pub struct hb_ot_map_t {
16 found_script: [bool; 2],
17 chosen_script: [Option<hb_tag_t>; 2],
18 global_mask: hb_mask_t,
19 features: Vec<feature_map_t>,
20 lookups: [Vec<lookup_map_t>; 2],
21 stages: [Vec<StageMap>; 2],
22 feature_variations: [Option<u32>; 2],
23}
24
25#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26pub struct feature_map_t {
27 tag: hb_tag_t,
28 index: [Option<u16>; 2],
30 stage: [usize; 2],
31 shift: u32,
32 mask: hb_mask_t,
33 one_mask: hb_mask_t,
35 auto_zwnj: bool,
36 auto_zwj: bool,
37 random: bool,
38 per_syllable: bool,
39}
40
41impl Ord for feature_map_t {
42 fn cmp(&self, other: &Self) -> Ordering {
43 self.tag.cmp(&other.tag)
44 }
45}
46
47impl PartialOrd for feature_map_t {
48 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
49 self.tag.partial_cmp(&other.tag)
50 }
51}
52
53#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
54pub struct lookup_map_t {
55 pub index: u16,
56 pub auto_zwnj: bool,
58 pub auto_zwj: bool,
59 pub random: bool,
60 pub mask: hb_mask_t,
61 pub per_syllable: bool,
62}
63
64#[derive(Clone, Copy)]
65pub struct StageMap {
66 pub last_lookup: usize,
68 pub pause_func: Option<pause_func_t>,
69}
70
71pub type pause_func_t = fn(&hb_ot_shape_plan_t, &mut FontFuncsDispatch, &mut hb_buffer_t) -> bool;
74
75impl hb_ot_map_t {
76 pub const MAX_BITS: u32 = 8;
77 pub const MAX_VALUE: u32 = (1 << Self::MAX_BITS) - 1;
78
79 #[inline]
80 pub fn found_script(&self, table_index: TableIndex) -> bool {
81 self.found_script[table_index]
82 }
83
84 #[inline]
85 pub fn chosen_script(&self, table_index: TableIndex) -> Option<hb_tag_t> {
86 self.chosen_script[table_index]
87 }
88
89 #[inline]
90 pub fn get_global_mask(&self) -> hb_mask_t {
91 self.global_mask
92 }
93
94 #[inline]
95 pub fn get_mask(&self, feature_tag: hb_tag_t) -> (hb_mask_t, u32) {
96 self.features
97 .binary_search_by_key(&feature_tag, |f| f.tag)
98 .map_or((0, 0), |idx| {
99 (self.features[idx].mask, self.features[idx].shift)
100 })
101 }
102
103 #[inline]
104 pub fn get_1_mask(&self, feature_tag: hb_tag_t) -> hb_mask_t {
105 self.features
106 .binary_search_by_key(&feature_tag, |f| f.tag)
107 .map_or(0, |idx| self.features[idx].one_mask)
108 }
109
110 #[inline]
111 pub fn get_feature_index(&self, table_index: TableIndex, feature_tag: hb_tag_t) -> Option<u16> {
112 self.features
113 .binary_search_by_key(&feature_tag, |f| f.tag)
114 .ok()
115 .and_then(|idx| self.features[idx].index[table_index])
116 }
117
118 #[inline]
119 pub fn get_feature_stage(
120 &self,
121 table_index: TableIndex,
122 feature_tag: hb_tag_t,
123 ) -> Option<usize> {
124 self.features
125 .binary_search_by_key(&feature_tag, |f| f.tag)
126 .map(|idx| self.features[idx].stage[table_index])
127 .ok()
128 }
129
130 #[inline]
131 pub fn stages(&self, table_index: TableIndex) -> &[StageMap] {
132 &self.stages[table_index]
133 }
134
135 #[inline]
136 pub fn lookup(&self, table_index: TableIndex, index: usize) -> &lookup_map_t {
137 &self.lookups[table_index][index]
138 }
139
140 #[inline]
141 pub fn stage_lookups(&self, table_index: TableIndex, stage: usize) -> &[lookup_map_t] {
142 &self.lookups[table_index][self.stage_lookup_range(table_index, stage)]
143 }
144
145 #[inline]
146 pub fn stage_lookup_range(&self, table_index: TableIndex, stage: usize) -> Range<usize> {
147 let stages = &self.stages[table_index];
148 let lookups = &self.lookups[table_index];
149 let start = stage
150 .checked_sub(1)
151 .map_or(0, |prev| stages[prev].last_lookup);
152 let end = stages
153 .get(stage)
154 .map_or(lookups.len(), |curr| curr.last_lookup);
155 start..end
156 }
157
158 pub fn feature_variations(&self) -> &[Option<u32>; 2] {
159 &self.feature_variations
160 }
161}
162
163pub type hb_ot_map_feature_flags_t = u32;
164pub const F_NONE: u32 = 0x0000;
165pub const F_GLOBAL: u32 = 0x0001; pub const F_HAS_FALLBACK: u32 = 0x0002; pub const F_MANUAL_ZWNJ: u32 = 0x0004; pub const F_MANUAL_ZWJ: u32 = 0x0008; pub const F_MANUAL_JOINERS: u32 = F_MANUAL_ZWNJ | F_MANUAL_ZWJ;
170pub const F_GLOBAL_MANUAL_JOINERS: u32 = F_GLOBAL | F_MANUAL_JOINERS;
171pub const F_GLOBAL_HAS_FALLBACK: u32 = F_GLOBAL | F_HAS_FALLBACK;
172pub const F_GLOBAL_SEARCH: u32 = 0x0010; pub const F_RANDOM: u32 = 0x0020; pub const F_PER_SYLLABLE: u32 = 0x0040; pub struct hb_ot_map_builder_t<'a> {
177 face: &'a hb_font_t<'a>,
178 found_script: [bool; 2],
179 script_index: [Option<u16>; 2],
180 chosen_script: [Option<hb_tag_t>; 2],
181 lang_index: [Option<u16>; 2],
182 current_stage: [usize; 2],
183 feature_infos: Vec<feature_info_t>,
184 stages: [Vec<stage_info_t>; 2],
185 pub(crate) is_simple: bool,
186}
187
188#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
189struct feature_info_t {
190 tag: hb_tag_t,
191 seq: usize,
193 max_value: u32,
194 flags: hb_ot_map_feature_flags_t,
195 default_value: u32,
197 stage: [usize; 2],
199}
200
201#[derive(Clone, Copy)]
202struct stage_info_t {
203 index: usize,
204 pause_func: Option<pause_func_t>,
205}
206
207const GLOBAL_BIT_SHIFT: u32 = 8 * size_of::<u32>() as u32 - 1;
208const GLOBAL_BIT_MASK: hb_mask_t = 1 << GLOBAL_BIT_SHIFT;
209
210impl<'a> hb_ot_map_builder_t<'a> {
211 pub fn new(
212 face: &'a hb_font_t<'a>,
213 script: Option<Script>,
214 language: Option<&Language>,
215 ) -> Self {
216 let (script_tags, lang_tags) = tag::tags_from_script_and_language(script, language);
219
220 let mut found_script = [false; 2];
221 let mut script_index = [None; 2];
222 let mut chosen_script = [None; 2];
223 let mut lang_index = [None; 2];
224
225 for (table_index, table) in face.layout_tables() {
226 if let Some((found, idx, tag)) = table.select_script(&script_tags) {
227 chosen_script[table_index] = Some(tag);
228 found_script[table_index] = found;
229 script_index[table_index] = Some(idx);
230
231 if let Some(idx) = table.select_script_language(idx, &lang_tags) {
232 lang_index[table_index] = Some(idx);
233 }
234 }
235 }
236
237 Self {
238 face,
239 found_script,
240 script_index,
241 chosen_script,
242 lang_index,
243 current_stage: [0, 0],
244 feature_infos: Vec::new(),
245 stages: [Vec::new(), Vec::new()],
246 is_simple: false,
247 }
248 }
249
250 #[inline]
251 pub fn chosen_script(&self, table_index: TableIndex) -> Option<hb_tag_t> {
252 self.chosen_script[table_index]
253 }
254
255 #[inline]
256 pub fn has_feature(&self, tag: hb_tag_t) -> bool {
257 for (table_index, table) in self.face.layout_tables() {
258 if let Some(script_index) = self.script_index[table_index] {
259 if table
260 .find_language_feature(script_index, self.lang_index[table_index], tag)
261 .is_some()
262 {
263 return true;
264 }
265 }
266 }
267
268 false
269 }
270
271 #[inline]
272 pub fn add_feature(&mut self, tag: hb_tag_t, flags: hb_ot_map_feature_flags_t, value: u32) {
273 if !tag.is_null() {
274 let seq = self.feature_infos.len();
275 self.feature_infos.push(feature_info_t {
276 tag,
277 seq,
278 max_value: value,
279 flags,
280 default_value: if flags & F_GLOBAL != 0 { value } else { 0 },
281 stage: self.current_stage,
282 });
283 }
284 }
285
286 #[inline]
287 pub fn enable_feature(&mut self, tag: hb_tag_t, flags: hb_ot_map_feature_flags_t, value: u32) {
288 self.add_feature(tag, flags | F_GLOBAL, value);
289 }
290
291 #[inline]
292 pub fn disable_feature(&mut self, tag: hb_tag_t) {
293 self.add_feature(tag, F_GLOBAL, 0);
294 }
295
296 #[inline]
297 pub fn add_gsub_pause(&mut self, pause: Option<pause_func_t>) {
298 self.add_pause(TableIndex::GSUB, pause);
299 }
300
301 #[inline]
302 pub fn add_gpos_pause(&mut self, pause: Option<pause_func_t>) {
303 self.add_pause(TableIndex::GPOS, pause);
304 }
305
306 fn add_pause(&mut self, table_index: TableIndex, pause: Option<pause_func_t>) {
307 self.stages[table_index].push(stage_info_t {
308 index: self.current_stage[table_index],
309 pause_func: pause,
310 });
311
312 self.current_stage[table_index] += 1;
313 }
314
315 pub fn compile(&mut self) -> hb_ot_map_t {
316 let mut required_index = [None; 2];
320 let mut required_tag = [None; 2];
321
322 for (table_index, table) in self.face.layout_tables() {
323 if let Some(script) = self.script_index[table_index] {
324 let lang = self.lang_index[table_index];
325 if let Some((idx, tag)) = table.get_required_language_feature(script, lang) {
326 required_index[table_index] = Some(idx);
327 required_tag[table_index] = Some(tag);
328 }
329 }
330 }
331
332 let (features, required_stage, global_mask) = self.collect_feature_maps(required_tag);
333
334 self.add_gsub_pause(None);
335 self.add_gpos_pause(None);
336
337 let (lookups, stages) =
338 self.collect_lookup_stages(&features, required_index, required_stage);
339
340 hb_ot_map_t {
341 found_script: self.found_script,
342 chosen_script: self.chosen_script,
343 global_mask,
344 features,
345 lookups,
346 stages,
347 feature_variations: self.face.ot_tables.feature_variations,
348 }
349 }
350
351 fn collect_feature_maps(
352 &mut self,
353 required_tag: [Option<hb_tag_t>; 2],
354 ) -> (Vec<feature_map_t>, [usize; 2], hb_mask_t) {
355 let mut map_features = Vec::new();
356 let mut required_stage = [0; 2];
357 let mut global_mask = GLOBAL_BIT_MASK;
358 let mut next_bit = GlyphFlags::DEFINED_BITS.count_ones() + 1;
359
360 self.dedup_feature_infos();
362
363 for info in &self.feature_infos {
364 let bits_needed = if info.flags & F_GLOBAL != 0 && info.max_value == 1 {
365 0
367 } else {
368 let v = info.max_value;
370 let num_bits = 8 * size_of_val(&v) as u32 - v.leading_zeros();
371 hb_ot_map_t::MAX_BITS.min(num_bits)
372 };
373
374 if info.max_value == 0 || next_bit + bits_needed >= GLOBAL_BIT_SHIFT {
375 continue;
377 }
378
379 let mut found = false;
380 let mut feature_index = [None; 2];
381
382 for (table_index, table) in self.face.layout_tables() {
383 if required_tag[table_index] == Some(info.tag) {
384 required_stage[table_index] = info.stage[table_index];
385 }
386
387 if let Some(script) = self.script_index[table_index] {
388 let lang = self.lang_index[table_index];
389 if let Some(idx) = table.find_language_feature(script, lang, info.tag) {
390 feature_index[table_index] = Some(idx);
391 found = true;
392 }
393 }
394 }
395
396 if !found && info.flags & F_GLOBAL_SEARCH != 0 {
397 for (table_index, table) in self.face.layout_tables() {
399 if let Some(idx) = table.feature_index(info.tag) {
400 feature_index[table_index] = Some(idx);
401 found = true;
402 }
403 }
404 }
405
406 if !found && !info.flags & F_HAS_FALLBACK != 0 {
407 continue;
408 }
409
410 let (shift, mask) = if info.flags & F_GLOBAL != 0 && info.max_value == 1 {
411 (GLOBAL_BIT_SHIFT, GLOBAL_BIT_MASK)
413 } else {
414 let shift = next_bit;
415 let mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
416 next_bit += bits_needed;
417 global_mask |= (info.default_value << shift) & mask;
418 (shift, mask)
419 };
420
421 map_features.push(feature_map_t {
422 tag: info.tag,
423 index: feature_index,
424 stage: info.stage,
425 shift,
426 mask,
427 one_mask: (1 << shift) & mask,
428 auto_zwnj: info.flags & F_MANUAL_ZWNJ == 0,
429 auto_zwj: info.flags & F_MANUAL_ZWJ == 0,
430 random: info.flags & F_RANDOM != 0,
431 per_syllable: info.flags & F_PER_SYLLABLE != 0,
432 });
433 }
434
435 if self.is_simple {
436 map_features.sort();
437 }
438
439 (map_features, required_stage, global_mask)
440 }
441
442 fn dedup_feature_infos(&mut self) {
443 let feature_infos = &mut self.feature_infos;
444 if feature_infos.is_empty() {
445 return;
446 }
447
448 if !self.is_simple {
449 feature_infos.sort();
450 }
451
452 let mut j = 0;
453 for i in 1..feature_infos.len() {
454 if feature_infos[i].tag != feature_infos[j].tag {
455 j += 1;
456 feature_infos[j] = feature_infos[i];
457 } else {
458 if feature_infos[i].flags & F_GLOBAL != 0 {
459 feature_infos[j].flags |= F_GLOBAL;
460 feature_infos[j].max_value = feature_infos[i].max_value;
461 feature_infos[j].default_value = feature_infos[i].default_value;
462 } else {
463 if feature_infos[j].flags & F_GLOBAL != 0 {
464 feature_infos[j].flags ^= F_GLOBAL;
465 }
466 feature_infos[j].max_value =
467 feature_infos[j].max_value.max(feature_infos[i].max_value);
468 }
470 let flags = feature_infos[i].flags & F_HAS_FALLBACK;
471 feature_infos[j].flags |= flags;
472 feature_infos[j].stage[0] =
473 feature_infos[j].stage[0].min(feature_infos[i].stage[0]);
474 feature_infos[j].stage[1] =
475 feature_infos[j].stage[1].min(feature_infos[i].stage[1]);
476 }
477 }
478
479 feature_infos.truncate(j + 1);
480 }
481
482 fn collect_lookup_stages(
483 &self,
484 map_features: &[feature_map_t],
485 required_feature_index: [Option<u16>; 2],
486 required_feature_stage: [usize; 2],
487 ) -> ([Vec<lookup_map_t>; 2], [Vec<StageMap>; 2]) {
488 let mut map_lookups = [Vec::new(), Vec::new()];
489 let mut map_stages = [Vec::new(), Vec::new()];
490
491 for table_index in TableIndex::iter() {
492 let mut stage_index = 0;
494 let mut last_lookup = 0;
495
496 let variation_index = self.face.ot_tables.feature_variations[table_index as usize];
497
498 for stage in 0..self.current_stage[table_index] {
499 if let Some(feature_index) = required_feature_index[table_index] {
500 if required_feature_stage[table_index] == stage {
501 self.add_lookups(
502 &mut map_lookups[table_index],
503 table_index,
504 feature_index,
505 variation_index,
506 GLOBAL_BIT_MASK,
507 true,
508 true,
509 false,
510 false,
511 );
512 }
513 }
514
515 for feature in map_features {
516 if let Some(feature_index) = feature.index[table_index] {
517 if feature.stage[table_index] == stage {
518 self.add_lookups(
519 &mut map_lookups[table_index],
520 table_index,
521 feature_index,
522 variation_index,
523 feature.mask,
524 feature.auto_zwnj,
525 feature.auto_zwj,
526 feature.random,
527 feature.per_syllable,
528 );
529 }
530 }
531 }
532
533 let lookups = &mut map_lookups[table_index];
535 let len = lookups.len();
536
537 if last_lookup + 1 < len {
538 lookups[last_lookup..].sort();
539
540 let mut j = last_lookup;
541 for i in j + 1..len {
542 if lookups[i].index != lookups[j].index {
543 j += 1;
544 lookups[j] = lookups[i];
545 } else {
546 lookups[j].mask |= lookups[i].mask;
547 lookups[j].auto_zwnj &= lookups[i].auto_zwnj;
548 lookups[j].auto_zwj &= lookups[i].auto_zwj;
549 }
550 }
551
552 lookups.truncate(j + 1);
553 }
554
555 last_lookup = lookups.len();
556
557 if let Some(info) = self.stages[table_index].get(stage_index) {
558 if info.index == stage {
559 map_stages[table_index].push(StageMap {
560 last_lookup,
561 pause_func: info.pause_func,
562 });
563
564 stage_index += 1;
565 }
566 }
567 }
568 }
569
570 (map_lookups, map_stages)
571 }
572
573 fn add_lookups(
574 &self,
575 lookups: &mut Vec<lookup_map_t>,
576 table_index: TableIndex,
577 feature_index: u16,
578 variation_index: Option<u32>,
579 mask: hb_mask_t,
580 auto_zwnj: bool,
581 auto_zwj: bool,
582 random: bool,
583 per_syllable: bool,
584 ) -> Option<()> {
585 let table = self.face.layout_table(table_index)?;
586
587 let lookup_count = table.lookup_count();
588 let feature = match variation_index {
589 Some(idx) => table
590 .feature_substitution(idx, feature_index)
591 .or_else(|| table.feature(feature_index))?,
592 None => table.feature(feature_index)?,
593 };
594
595 for index in feature.lookup_list_indices() {
596 let index = index.get();
597 if index < lookup_count {
598 lookups.push(lookup_map_t {
599 index,
600 auto_zwnj,
601 auto_zwj,
602 random,
603 mask,
604 per_syllable,
605 });
606 }
607 }
608
609 Some(())
610 }
611}