1use core::ops::{Index, IndexMut};
4
5use super::buffer::*;
6use super::font_funcs::FontFuncsDispatch;
7use super::ot::lookup::LookupInfo;
8use super::ot_layout_gsubgpos::OT;
9use super::ot_shape_plan::hb_ot_shape_plan_t;
10use super::unicode::hb_unicode_funcs_t;
11use super::{hb_font_t, GlyphInfo};
12use crate::hb::ot_layout_gsubgpos::OT::check_glyph_property;
13use crate::hb::unicode::GeneralCategory;
14
15impl GlyphInfo {
16 declare_buffer_var!(u16, 1, 0, GLYPH_PROPS_VAR, glyph_props, set_glyph_props);
17 declare_buffer_var!(u8, 1, 2, LIG_PROPS_VAR, lig_props, set_lig_props);
18 declare_buffer_var!(u8, 1, 3, SYLLABLE_VAR, syllable, set_syllable);
19 declare_buffer_var!(
20 u16,
21 2,
22 0,
23 UNICODE_PROPS_VAR,
24 unicode_props,
25 set_unicode_props
26 );
27}
28
29impl hb_buffer_t {
30 pub(crate) fn allocate_unicode_vars(&mut self) {
31 self.allocate_var(GlyphInfo::UNICODE_PROPS_VAR);
32 }
33 pub(crate) fn deallocate_unicode_vars(&mut self) {
34 self.deallocate_var(GlyphInfo::UNICODE_PROPS_VAR);
35 }
36 pub(crate) fn assert_unicode_vars(&mut self) {
37 self.assert_var(GlyphInfo::UNICODE_PROPS_VAR);
38 }
39
40 pub(crate) fn allocate_gsubgpos_vars(&mut self) {
41 self.allocate_var(GlyphInfo::LIG_PROPS_VAR);
42 self.allocate_var(GlyphInfo::GLYPH_PROPS_VAR);
43 }
44 pub(crate) fn deallocate_gsubgpos_vars(&mut self) {
45 self.deallocate_var(GlyphInfo::LIG_PROPS_VAR);
46 self.deallocate_var(GlyphInfo::GLYPH_PROPS_VAR);
47 }
48 pub(crate) fn assert_gsubgpos_vars(&mut self) {
49 self.assert_var(GlyphInfo::LIG_PROPS_VAR);
50 self.assert_var(GlyphInfo::GLYPH_PROPS_VAR);
51 }
52}
53
54pub const MAX_NESTING_LEVEL: usize = 64;
55pub const MAX_CONTEXT_LENGTH: usize = 64;
56
57pub fn hb_ot_layout_has_kerning(face: &hb_font_t) -> bool {
58 face.aat_tables.kern.is_some()
59}
60
61pub fn hb_ot_layout_has_machine_kerning(face: &hb_font_t) -> bool {
62 match face.aat_tables.kern {
63 Some(ref kern) => kern
64 .0
65 .subtables()
66 .filter_map(Result::ok)
67 .any(|s| s.is_state_machine()),
68 None => false,
69 }
70}
71
72pub fn hb_ot_layout_has_cross_kerning(face: &hb_font_t) -> bool {
73 match face.aat_tables.kern {
74 Some(ref kern) => kern
75 .0
76 .subtables()
77 .filter_map(Result::ok)
78 .any(|s| s.is_cross_stream()),
79 None => false,
80 }
81}
82
83pub fn _hb_ot_layout_set_glyph_props(face: &hb_font_t, buffer: &mut hb_buffer_t) {
86 buffer.assert_gsubgpos_vars();
87
88 let len = buffer.len;
89 for info in &mut buffer.info[..len] {
90 info.set_glyph_props(face.ot_tables.glyph_props(info.as_glyph()));
91 info.set_lig_props(0);
92 }
93}
94
95pub fn hb_ot_layout_has_glyph_classes(face: &hb_font_t) -> bool {
96 face.ot_tables.has_glyph_classes()
97}
98
99#[derive(Clone, Copy, Debug, PartialEq, Eq)]
102pub enum TableIndex {
103 GSUB = 0,
104 GPOS = 1,
105}
106
107impl TableIndex {
108 pub fn iter() -> impl Iterator<Item = TableIndex> {
109 [Self::GSUB, Self::GPOS].iter().copied()
110 }
111}
112
113impl<T> Index<TableIndex> for [T] {
114 type Output = T;
115
116 fn index(&self, table_index: TableIndex) -> &Self::Output {
117 &self[table_index as usize]
118 }
119}
120
121impl<T> IndexMut<TableIndex> for [T] {
122 fn index_mut(&mut self, table_index: TableIndex) -> &mut Self::Output {
123 &mut self[table_index as usize]
124 }
125}
126
127pub trait LayoutTable {
129 const INDEX: TableIndex;
131
132 const IN_PLACE: bool;
134
135 fn get_lookup(&self, index: u16) -> Option<&LookupInfo>;
137}
138
139pub fn hb_ot_layout_substitute_start(face: &hb_font_t, buffer: &mut hb_buffer_t) {
142 _hb_ot_layout_set_glyph_props(face, buffer);
143}
144
145pub fn apply_layout_table<T: LayoutTable>(
147 plan: &hb_ot_shape_plan_t,
148 face: &hb_font_t,
149 font_funcs: &mut FontFuncsDispatch,
150 buffer: &mut hb_buffer_t,
151 table: Option<&T>,
152) {
153 let mut ctx = OT::hb_ot_apply_context_t::new(T::INDEX, face, *font_funcs.scale(), buffer);
154
155 for (stage_index, stage) in plan.ot_map.stages(T::INDEX).iter().enumerate() {
156 if let Some(table) = table {
157 for lookup_map in plan.ot_map.stage_lookups(T::INDEX, stage_index) {
158 let Some(lookup) = table.get_lookup(lookup_map.index) else {
159 continue;
160 };
161
162 if lookup.digest().may_intersect(&ctx.buffer.digest) {
163 ctx.lookup_index = lookup_map.index;
164 ctx.set_lookup_mask(lookup_map.mask);
165 ctx.auto_zwj = lookup_map.auto_zwj;
166 ctx.auto_zwnj = lookup_map.auto_zwnj;
167
168 ctx.random = lookup_map.random;
169 ctx.per_syllable = lookup_map.per_syllable;
170
171 apply_string::<T>(&mut ctx, lookup);
172 }
173 }
174 }
175
176 if let Some(func) = stage.pause_func {
177 if func(plan, font_funcs, ctx.buffer) {
178 ctx.buffer.update_digest();
179 }
180 }
181 }
182}
183
184fn apply_string<T: LayoutTable>(ctx: &mut OT::hb_ot_apply_context_t, lookup: &LookupInfo) {
185 if ctx.buffer.is_empty() || ctx.lookup_mask() == 0 {
186 return;
187 }
188
189 ctx.lookup_props = lookup.props();
190 ctx.update_matchers();
191
192 if !lookup.is_reverse() {
193 if !T::IN_PLACE {
195 ctx.buffer.clear_output();
196 }
197 ctx.buffer.idx = 0;
198 apply_forward(ctx, lookup);
199
200 if !T::IN_PLACE {
201 ctx.buffer.sync();
202 }
203 } else {
204 debug_assert!(!ctx.buffer.have_output);
206
207 ctx.buffer.idx = ctx.buffer.len - 1;
208 apply_backward(ctx, lookup);
209 }
210}
211
212fn apply_forward(ctx: &mut OT::hb_ot_apply_context_t, lookup: &LookupInfo) -> bool {
213 let mut ret = false;
214 let Some(table_data) = ctx.face.ot_tables.table_data(ctx.table_index) else {
215 return false;
216 };
217
218 let use_hot_subtable_cache = lookup.cache_enter(ctx);
219
220 while ctx.buffer.successful {
221 let mut j = ctx.buffer.idx;
222 while j < ctx.buffer.len && {
223 let info = &ctx.buffer.info[j];
224 !(lookup.digest.may_have(info.glyph_id)
225 && (info.mask & ctx.lookup_mask()) != 0
226 && check_glyph_property(ctx.face, info, ctx.lookup_props))
227 } {
228 j += 1;
229 }
230 if j > ctx.buffer.idx {
231 ctx.buffer.next_glyphs(j - ctx.buffer.idx);
232 }
233 if ctx.buffer.idx >= ctx.buffer.len {
234 break;
235 }
236
237 if lookup
238 .apply(ctx, table_data, use_hot_subtable_cache)
239 .is_some()
240 {
241 ret = true;
242 } else {
243 ctx.buffer.next_glyph();
244 }
245 }
246
247 if use_hot_subtable_cache {
248 lookup.cache_leave(ctx);
249 }
250
251 ret
252}
253
254fn apply_backward(ctx: &mut OT::hb_ot_apply_context_t, lookup: &LookupInfo) -> bool {
255 let mut ret = false;
256 let Some(table_data) = ctx.face.ot_tables.table_data(ctx.table_index) else {
257 return false;
258 };
259 loop {
260 let cur = ctx.buffer.cur(0);
261 ret |= lookup.digest.may_have(cur.glyph_id)
262 && (cur.mask & ctx.lookup_mask()) != 0
263 && check_glyph_property(ctx.face, cur, ctx.lookup_props)
264 && lookup.apply(ctx, table_data, false).is_some();
265
266 if ctx.buffer.idx == 0 {
267 break;
268 }
269
270 ctx.buffer.idx -= 1;
271 }
272 ret
273}
274
275impl GlyphInfo {
358 #[doc(alias = "_hb_glyph_info_set_general_category")]
362 #[inline]
363 pub(crate) fn set_general_category(&mut self, gen_cat: GeneralCategory) {
364 let gen_cat = gen_cat.0 as u32;
366 let n = (gen_cat as u16)
367 | (self.unicode_props() & (0xFF & !UnicodeProps::GENERAL_CATEGORY.bits()));
368 self.set_unicode_props(n);
369 }
370
371 #[doc(alias = "_hb_glyph_info_get_general_category")]
375 #[inline]
376 pub(crate) fn general_category(&self) -> GeneralCategory {
377 let n = self.unicode_props() & UnicodeProps::GENERAL_CATEGORY.bits();
378 GeneralCategory(n as u8)
379 }
380
381 #[doc(alias = "_hb_glyph_info_is_unicode_mark")]
385 #[inline]
386 pub(crate) fn is_unicode_mark(&self) -> bool {
387 self.general_category().is_mark()
388 }
389
390 #[doc(alias = "_hb_glyph_info_set_modified_combining_class")]
394 #[inline]
395 pub(crate) fn set_modified_combining_class(&mut self, modified_class: u8) {
396 if !self.is_unicode_mark() {
397 return;
398 }
399 let n = ((modified_class as u16) << 8) | (self.unicode_props() & 0xFF);
400 self.set_unicode_props(n);
401 }
402
403 #[doc(alias = "_hb_glyph_info_get_modified_combining_class")]
407 #[inline]
408 pub(crate) fn modified_combining_class(&self) -> u8 {
409 if self.is_unicode_mark() {
410 (self.unicode_props() >> 8) as u8
411 } else {
412 0
413 }
414 }
415
416 #[doc(alias = "_hb_glyph_info_is_unicode_space")]
426 #[inline]
427 pub(crate) fn is_unicode_space(&self) -> bool {
428 self.general_category() == GeneralCategory::SPACE_SEPARATOR
429 }
430
431 #[doc(alias = "_hb_glyph_info_set_unicode_space_fallback_type")]
435 #[inline]
436 pub(crate) fn set_unicode_space_fallback_type(&mut self, s: hb_unicode_funcs_t::space_t) {
437 if !self.is_unicode_space() {
438 return;
439 }
440 let n = ((s as u16) << 8) | (self.unicode_props() & 0xFF);
441 self.set_unicode_props(n);
442 }
443
444 #[doc(alias = "_hb_glyph_info_get_unicode_space_fallback_type")]
448 #[inline]
449 pub(crate) fn unicode_space_fallback_type(&self) -> hb_unicode_funcs_t::space_t {
450 if self.is_unicode_space() {
451 (self.unicode_props() >> 8) as u8
452 } else {
453 hb_unicode_funcs_t::NOT_SPACE
454 }
455 }
456
457 #[doc(alias = "_hb_glyph_info_is_variation_selector")]
461 #[inline]
462 pub(crate) fn is_variation_selector(&self) -> bool {
463 let a = self.general_category() == GeneralCategory::FORMAT;
464 let b = (self.unicode_props() & UnicodeProps::CF_VS.bits()) != 0;
465 a && b
466 }
467
468 #[doc(alias = "_hb_glyph_info_set_variation_selector")]
472 #[inline]
473 pub(crate) fn set_variation_selector(&mut self, customize: bool) {
474 if customize {
475 self.set_general_category(GeneralCategory::FORMAT);
476 self.set_unicode_props(self.unicode_props() | UnicodeProps::CF_VS.bits());
477 } else {
478 self.set_general_category(GeneralCategory::NON_SPACING_MARK);
480 }
481 }
482
483 #[doc(alias = "_hb_glyph_info_is_default_ignorable")]
487 #[inline]
488 pub(crate) fn is_default_ignorable(&self) -> bool {
489 let n = self.unicode_props() & UnicodeProps::IGNORABLE.bits();
490 n != 0 && !self.substituted()
491 }
492
493 #[doc(alias = "_hb_glyph_info_set_default_ignorable")]
497 #[inline]
498 pub(crate) fn _set_default_ignorable(&mut self) {
499 self.set_unicode_props(self.unicode_props() | UnicodeProps::IGNORABLE.bits());
500 }
501
502 #[doc(alias = "_hb_glyph_info_clear_default_ignorable")]
506 #[inline]
507 pub(crate) fn clear_default_ignorable(&mut self) {
508 let mut n = self.unicode_props();
509 n &= !UnicodeProps::IGNORABLE.bits();
510 self.set_unicode_props(n);
511 }
512
513 #[doc(alias = "_hb_glyph_info_is_hidden")]
517 #[inline]
518 pub(crate) fn is_hidden(&self) -> bool {
519 (self.unicode_props() & UnicodeProps::HIDDEN.bits()) != 0
520 }
521
522 #[doc(alias = "_hb_glyph_info_set_continuation")]
532 #[inline]
533 pub(crate) fn set_continuation(&mut self, scratch_flags: &mut hb_buffer_scratch_flags_t) {
534 *scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS;
535 let mut n = self.unicode_props();
536 n |= UnicodeProps::CONTINUATION.bits();
537 self.set_unicode_props(n);
538 }
539
540 #[doc(alias = "_hb_glyph_info_clear_continuation")]
544 #[inline]
545 pub(crate) fn clear_continuation(&mut self) {
546 let mut n = self.unicode_props();
547 n &= !UnicodeProps::CONTINUATION.bits();
548 self.set_unicode_props(n);
549 }
550
551 #[doc(alias = "_hb_glyph_info_is_continuation")]
555 #[inline]
556 pub(crate) fn is_continuation(&self) -> bool {
557 self.unicode_props() & UnicodeProps::CONTINUATION.bits() != 0
558 }
559}
560
561pub(crate) fn _hb_grapheme_group_func(_: &GlyphInfo, b: &GlyphInfo) -> bool {
562 b.is_continuation()
563}
564
565pub fn _hb_ot_layout_reverse_graphemes(buffer: &mut hb_buffer_t) {
566 buffer.reverse_groups(
569 _hb_grapheme_group_func,
570 buffer.cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS,
571 );
572}
573
574impl GlyphInfo {
575 #[doc(alias = "_hb_glyph_info_is_unicode_format")]
579 #[inline]
580 pub(crate) fn is_unicode_format(&self) -> bool {
581 self.general_category() == GeneralCategory::FORMAT
582 }
583
584 #[doc(alias = "_hb_glyph_info_is_zwnj")]
588 #[inline]
589 pub(crate) fn is_zwnj(&self) -> bool {
590 self.is_unicode_format() && (self.unicode_props() & UnicodeProps::CF_ZWNJ.bits() != 0)
591 }
592
593 #[doc(alias = "_hb_glyph_info_is_zwnj")]
597 #[inline]
598 pub(crate) fn is_zwj(&self) -> bool {
599 self.is_unicode_format() && (self.unicode_props() & UnicodeProps::CF_ZWJ.bits() != 0)
600 }
601
602 #[doc(alias = "_hb_glyph_info_is_aat_deleted")]
606 #[inline]
607 pub(crate) fn is_aat_deleted(&self) -> bool {
608 self.is_unicode_format()
609 && (self.unicode_props() & UnicodeProps::CF_AAT_DELETED.bits() != 0)
610 }
611
612 #[doc(alias = "_hb_glyph_info_set_aat_deleted")]
616 #[inline]
617 pub(crate) fn set_aat_deleted(&mut self) {
618 self.set_general_category(GeneralCategory::FORMAT);
619 self.set_unicode_props(
620 self.unicode_props()
621 | UnicodeProps::CF_AAT_DELETED.bits()
622 | UnicodeProps::HIDDEN.bits(),
623 );
624 }
625
626 const IS_LIG_BASE: u8 = 0x10;
657
658 #[doc(alias = "_hb_glyph_info_set_lig_props_for_ligature")]
662 #[inline]
663 pub(crate) fn set_lig_props_for_ligature(&mut self, lig_id: u8, lig_num_comps: u8) {
664 self.set_lig_props((lig_id << 5) | Self::IS_LIG_BASE | (lig_num_comps & 0x0F));
665 }
666
667 #[doc(alias = "_hb_glyph_info_set_lig_props_for_mark")]
671 #[inline]
672 pub(crate) fn set_lig_props_for_mark(&mut self, lig_id: u8, lig_comp: u8) {
673 self.set_lig_props((lig_id << 5) | (lig_comp & 0x0F));
674 }
675
676 #[doc(alias = "_hb_glyph_info_set_lig_props_for_component")]
680 #[inline]
681 pub(crate) fn set_lig_props_for_component(&mut self, comp: u8) {
682 self.set_lig_props_for_mark(0, comp);
683 }
684
685 #[doc(alias = "_hb_glyph_info_get_lig_id")]
689 #[inline]
690 pub(crate) fn lig_id(&self) -> u8 {
691 self.lig_props() >> 5
692 }
693
694 #[doc(alias = "_hb_glyph_info_ligated_internal")]
698 #[inline]
699 pub(crate) fn ligated_internal(&self) -> bool {
700 self.lig_props() & Self::IS_LIG_BASE != 0
701 }
702
703 #[doc(alias = "_hb_glyph_info_get_lig_comp")]
707 #[inline]
708 pub(crate) fn lig_comp(&self) -> u8 {
709 if self.ligated_internal() {
710 0
711 } else {
712 self.lig_props() & 0x0F
713 }
714 }
715
716 #[doc(alias = "_hb_glyph_info_get_lig_num_comps")]
720 #[inline]
721 pub(crate) fn lig_num_comps(&self) -> u8 {
722 if self.glyph_props() & GlyphPropsFlags::LIGATURE.bits() != 0 && self.ligated_internal() {
723 self.lig_props() & 0x0F
724 } else {
725 1
726 }
727 }
728
729 #[doc(alias = "_hb_glyph_info_is_base_glyph")]
746 #[inline]
747 pub(crate) fn is_base_glyph(&self) -> bool {
748 self.glyph_props() & GlyphPropsFlags::BASE_GLYPH.bits() != 0
749 }
750
751 #[doc(alias = "_hb_glyph_info_is_ligature")]
755 #[inline]
756 pub(crate) fn is_ligature(&self) -> bool {
757 self.glyph_props() & GlyphPropsFlags::LIGATURE.bits() != 0
758 }
759
760 #[doc(alias = "_hb_glyph_info_is_mark")]
764 #[inline]
765 pub(crate) fn is_mark(&self) -> bool {
766 self.glyph_props() & GlyphPropsFlags::MARK.bits() != 0
767 }
768
769 #[doc(alias = "_hb_glyph_info_substituted")]
773 #[inline]
774 pub(crate) fn substituted(&self) -> bool {
775 self.glyph_props() & GlyphPropsFlags::SUBSTITUTED.bits() != 0
776 }
777
778 #[doc(alias = "_hb_glyph_info_ligated")]
782 #[inline]
783 pub(crate) fn ligated(&self) -> bool {
784 self.glyph_props() & GlyphPropsFlags::LIGATED.bits() != 0
785 }
786
787 #[doc(alias = "_hb_glyph_info_multiplied")]
791 #[inline]
792 pub(crate) fn multiplied(&self) -> bool {
793 self.glyph_props() & GlyphPropsFlags::MULTIPLIED.bits() != 0
794 }
795
796 #[doc(alias = "_hb_glyph_info_ligated_and_didnt_multiply")]
800 #[inline]
801 pub(crate) fn ligated_and_didnt_multiply(&self) -> bool {
802 self.ligated() && !self.multiplied()
803 }
804
805 #[doc(alias = "_hb_glyph_info_clear_ligated_and_multiplied")]
809 #[inline]
810 pub(crate) fn clear_ligated_and_multiplied(&mut self) {
811 let mut n = self.glyph_props();
812 n &= !(GlyphPropsFlags::LIGATED | GlyphPropsFlags::MULTIPLIED).bits();
813 self.set_glyph_props(n);
814 }
815
816 #[doc(alias = "_hb_glyph_info_clear_substituted")]
820 #[inline]
821 pub(crate) fn clear_substituted(&mut self) {
822 let mut n = self.glyph_props();
823 n &= !GlyphPropsFlags::SUBSTITUTED.bits();
824 self.set_glyph_props(n);
825 }
826}
827
828pub fn _hb_clear_substitution_flags(
829 _: &hb_ot_shape_plan_t,
830 _: &mut FontFuncsDispatch,
831 buffer: &mut hb_buffer_t,
832) -> bool {
833 let len = buffer.len;
834 for info in &mut buffer.info[..len] {
835 info.clear_substituted();
836 }
837
838 false
839}