1 | use super::*; |
2 | use crate::{unicode, Tag}; |
3 | |
4 | pub 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 | |
20 | const 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 | |
50 | fn 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 | |