1use super::*;
2use crate::{unicode, Tag};
3
4pub const HEBREW_SHAPER: ComplexShaper = ComplexShaper {
5 collect_features: None,
6 override_features: None,
7 create_data: None,
8 preprocess_text: None,
9 postprocess_glyphs: None,
10 normalization_mode: Some(ShapeNormalizationMode::Auto),
11 decompose: None,
12 compose: Some(compose),
13 setup_masks: None,
14 gpos_tag: Some(Tag::from_bytes(b"hebr")),
15 reorder_marks: None,
16 zero_width_marks: Some(ZeroWidthMarksMode::ByGdefLate),
17 fallback_position: true,
18};
19
20const S_DAGESH_FORMS: &[char] = &[
21 '\u{FB30}', // ALEF
22 '\u{FB31}', // BET
23 '\u{FB32}', // GIMEL
24 '\u{FB33}', // DALET
25 '\u{FB34}', // HE
26 '\u{FB35}', // VAV
27 '\u{FB36}', // ZAYIN
28 '\u{0000}', // HET
29 '\u{FB38}', // TET
30 '\u{FB39}', // YOD
31 '\u{FB3A}', // FINAL KAF
32 '\u{FB3B}', // KAF
33 '\u{FB3C}', // LAMED
34 '\u{0000}', // FINAL MEM
35 '\u{FB3E}', // MEM
36 '\u{0000}', // FINAL NUN
37 '\u{FB40}', // NUN
38 '\u{FB41}', // SAMEKH
39 '\u{0000}', // AYIN
40 '\u{FB43}', // FINAL PE
41 '\u{FB44}', // PE
42 '\u{0000}', // FINAL TSADI
43 '\u{FB46}', // TSADI
44 '\u{FB47}', // QOF
45 '\u{FB48}', // RESH
46 '\u{FB49}', // SHIN
47 '\u{FB4A}', // TAV
48];
49
50fn compose(ctx: &ShapeNormalizeContext, a: char, b: char) -> Option<char> {
51 // Hebrew presentation-form shaping.
52 // https://bugzilla.mozilla.org/show_bug.cgi?id=728866
53 // Hebrew presentation forms with dagesh, for characters U+05D0..05EA;
54 // Note that some letters do not have a dagesh presForm encoded.
55 match unicode::compose(a, b) {
56 Some(c) => Some(c),
57 None if !ctx.plan.has_gpos_mark => {
58 // Special-case Hebrew presentation forms that are excluded from
59 // standard normalization, but wanted for old fonts.
60 let a = a as u32;
61 let b = b as u32;
62 match b {
63 0x05B4 => {
64 // HIRIQ
65 match a {
66 0x05D9 => Some('\u{FB1D}'), // YOD
67 _ => None,
68 }
69 }
70 0x05B7 => {
71 // patah
72 match a {
73 0x05D9 => Some('\u{FB1F}'), // YIDDISH YOD YOD
74 0x05D0 => Some('\u{FB2E}'), // ALEF
75 _ => None,
76 }
77 }
78 0x05B8 => {
79 // QAMATS
80 match a {
81 0x05D0 => Some('\u{FB2F}'), // ALEF
82 _ => None,
83 }
84 }
85 0x05B9 => {
86 // HOLAM
87 match a {
88 0x05D5 => Some('\u{FB4B}'), // VAV
89 _ => None,
90 }
91 }
92 0x05BC => {
93 // DAGESH
94 match a {
95 0x05D0..=0x05EA => {
96 let c = S_DAGESH_FORMS[a as usize - 0x05D0];
97 if c != '\0' {
98 Some(c)
99 } else {
100 None
101 }
102 }
103 0xFB2A => Some('\u{FB2C}'), // SHIN WITH SHIN DOT
104 0xFB2B => Some('\u{FB2D}'), // SHIN WITH SIN DOT
105 _ => None,
106 }
107 }
108 0x05BF => {
109 // RAFE
110 match a {
111 0x05D1 => Some('\u{FB4C}'), // BET
112 0x05DB => Some('\u{FB4D}'), // KAF
113 0x05E4 => Some('\u{FB4E}'), // PE
114 _ => None,
115 }
116 }
117 0x05C1 => {
118 // SHIN DOT
119 match a {
120 0x05E9 => Some('\u{FB2A}'), // SHIN
121 0xFB49 => Some('\u{FB2C}'), // SHIN WITH DAGESH
122 _ => None,
123 }
124 }
125 0x05C2 => {
126 // SIN DOT
127 match a {
128 0x05E9 => Some('\u{FB2B}'), // SHIN
129 0xFB49 => Some('\u{FB2D}'), // SHIN WITH DAGESH
130 _ => None,
131 }
132 }
133 _ => None,
134 }
135 }
136 None => None,
137 }
138}
139