/work/workdir/UnpackedTarball/harfbuzz/src/hb-ot-shaper-hebrew.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright © 2010,2012 Google, Inc. |
3 | | * |
4 | | * This is part of HarfBuzz, a text shaping library. |
5 | | * |
6 | | * Permission is hereby granted, without written agreement and without |
7 | | * license or royalty fees, to use, copy, modify, and distribute this |
8 | | * software and its documentation for any purpose, provided that the |
9 | | * above copyright notice and the following two paragraphs appear in |
10 | | * all copies of this software. |
11 | | * |
12 | | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | | * DAMAGE. |
17 | | * |
18 | | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | | * |
24 | | * Google Author(s): Behdad Esfahbod |
25 | | */ |
26 | | |
27 | | #include "hb.hh" |
28 | | |
29 | | #ifndef HB_NO_OT_SHAPE |
30 | | |
31 | | #include "hb-ot-shaper.hh" |
32 | | |
33 | | |
34 | | static bool |
35 | | compose_hebrew (const hb_ot_shape_normalize_context_t *c, |
36 | | hb_codepoint_t a, |
37 | | hb_codepoint_t b, |
38 | | hb_codepoint_t *ab) |
39 | 64.6k | { |
40 | | /* Hebrew presentation-form shaping. |
41 | | * https://bugzilla.mozilla.org/show_bug.cgi?id=728866 |
42 | | * Hebrew presentation forms with dagesh, for characters U+05D0..05EA; |
43 | | * Note that some letters do not have a dagesh presForm encoded. |
44 | | */ |
45 | 64.6k | static const hb_codepoint_t sDageshForms[0x05EAu - 0x05D0u + 1] = { |
46 | 64.6k | 0xFB30u, /* ALEF */ |
47 | 64.6k | 0xFB31u, /* BET */ |
48 | 64.6k | 0xFB32u, /* GIMEL */ |
49 | 64.6k | 0xFB33u, /* DALET */ |
50 | 64.6k | 0xFB34u, /* HE */ |
51 | 64.6k | 0xFB35u, /* VAV */ |
52 | 64.6k | 0xFB36u, /* ZAYIN */ |
53 | 64.6k | 0x0000u, /* HET */ |
54 | 64.6k | 0xFB38u, /* TET */ |
55 | 64.6k | 0xFB39u, /* YOD */ |
56 | 64.6k | 0xFB3Au, /* FINAL KAF */ |
57 | 64.6k | 0xFB3Bu, /* KAF */ |
58 | 64.6k | 0xFB3Cu, /* LAMED */ |
59 | 64.6k | 0x0000u, /* FINAL MEM */ |
60 | 64.6k | 0xFB3Eu, /* MEM */ |
61 | 64.6k | 0x0000u, /* FINAL NUN */ |
62 | 64.6k | 0xFB40u, /* NUN */ |
63 | 64.6k | 0xFB41u, /* SAMEKH */ |
64 | 64.6k | 0x0000u, /* AYIN */ |
65 | 64.6k | 0xFB43u, /* FINAL PE */ |
66 | 64.6k | 0xFB44u, /* PE */ |
67 | 64.6k | 0x0000u, /* FINAL TSADI */ |
68 | 64.6k | 0xFB46u, /* TSADI */ |
69 | 64.6k | 0xFB47u, /* QOF */ |
70 | 64.6k | 0xFB48u, /* RESH */ |
71 | 64.6k | 0xFB49u, /* SHIN */ |
72 | 64.6k | 0xFB4Au /* TAV */ |
73 | 64.6k | }; |
74 | | |
75 | 64.6k | bool found = (bool) c->unicode->compose (a, b, ab); |
76 | | |
77 | | #ifdef HB_NO_OT_SHAPER_HEBREW_FALLBACK |
78 | | return found; |
79 | | #endif |
80 | | |
81 | 64.6k | if (!found && (c->plan && !c->plan->has_gpos_mark)) |
82 | 0 | { |
83 | | /* Special-case Hebrew presentation forms that are excluded from |
84 | | * standard normalization, but wanted for old fonts. */ |
85 | 0 | switch (b) { |
86 | 0 | case 0x05B4u: /* HIRIQ */ |
87 | 0 | if (a == 0x05D9u) { /* YOD */ |
88 | 0 | *ab = 0xFB1Du; |
89 | 0 | found = true; |
90 | 0 | } |
91 | 0 | break; |
92 | 0 | case 0x05B7u: /* PATAH */ |
93 | 0 | if (a == 0x05F2u) { /* YIDDISH YOD YOD */ |
94 | 0 | *ab = 0xFB1Fu; |
95 | 0 | found = true; |
96 | 0 | } else if (a == 0x05D0u) { /* ALEF */ |
97 | 0 | *ab = 0xFB2Eu; |
98 | 0 | found = true; |
99 | 0 | } |
100 | 0 | break; |
101 | 0 | case 0x05B8u: /* QAMATS */ |
102 | 0 | if (a == 0x05D0u) { /* ALEF */ |
103 | 0 | *ab = 0xFB2Fu; |
104 | 0 | found = true; |
105 | 0 | } |
106 | 0 | break; |
107 | 0 | case 0x05B9u: /* HOLAM */ |
108 | 0 | if (a == 0x05D5u) { /* VAV */ |
109 | 0 | *ab = 0xFB4Bu; |
110 | 0 | found = true; |
111 | 0 | } |
112 | 0 | break; |
113 | 0 | case 0x05BCu: /* DAGESH */ |
114 | 0 | if (a >= 0x05D0u && a <= 0x05EAu) { |
115 | 0 | *ab = sDageshForms[a - 0x05D0u]; |
116 | 0 | found = (*ab != 0); |
117 | 0 | } else if (a == 0xFB2Au) { /* SHIN WITH SHIN DOT */ |
118 | 0 | *ab = 0xFB2Cu; |
119 | 0 | found = true; |
120 | 0 | } else if (a == 0xFB2Bu) { /* SHIN WITH SIN DOT */ |
121 | 0 | *ab = 0xFB2Du; |
122 | 0 | found = true; |
123 | 0 | } |
124 | 0 | break; |
125 | 0 | case 0x05BFu: /* RAFE */ |
126 | 0 | switch (a) { |
127 | 0 | case 0x05D1u: /* BET */ |
128 | 0 | *ab = 0xFB4Cu; |
129 | 0 | found = true; |
130 | 0 | break; |
131 | 0 | case 0x05DBu: /* KAF */ |
132 | 0 | *ab = 0xFB4Du; |
133 | 0 | found = true; |
134 | 0 | break; |
135 | 0 | case 0x05E4u: /* PE */ |
136 | 0 | *ab = 0xFB4Eu; |
137 | 0 | found = true; |
138 | 0 | break; |
139 | 0 | } |
140 | 0 | break; |
141 | 0 | case 0x05C1u: /* SHIN DOT */ |
142 | 0 | if (a == 0x05E9u) { /* SHIN */ |
143 | 0 | *ab = 0xFB2Au; |
144 | 0 | found = true; |
145 | 0 | } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */ |
146 | 0 | *ab = 0xFB2Cu; |
147 | 0 | found = true; |
148 | 0 | } |
149 | 0 | break; |
150 | 0 | case 0x05C2u: /* SIN DOT */ |
151 | 0 | if (a == 0x05E9u) { /* SHIN */ |
152 | 0 | *ab = 0xFB2Bu; |
153 | 0 | found = true; |
154 | 0 | } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */ |
155 | 0 | *ab = 0xFB2Du; |
156 | 0 | found = true; |
157 | 0 | } |
158 | 0 | break; |
159 | 0 | } |
160 | 0 | } |
161 | | |
162 | 64.6k | return found; |
163 | 64.6k | } |
164 | | |
165 | | static void |
166 | | reorder_marks_hebrew (const hb_ot_shape_plan_t *plan HB_UNUSED, |
167 | | hb_buffer_t *buffer, |
168 | | unsigned int start, |
169 | | unsigned int end) |
170 | 62.7k | { |
171 | 62.7k | hb_glyph_info_t *info = buffer->info; |
172 | | |
173 | 75.3k | for (unsigned i = start + 2; i < end; i++) |
174 | 12.5k | { |
175 | 12.5k | unsigned c0 = info_cc (info[i - 2]); |
176 | 12.5k | unsigned c1 = info_cc (info[i - 1]); |
177 | 12.5k | unsigned c2 = info_cc (info[i - 0]); |
178 | | |
179 | 12.5k | if ((c0 == HB_MODIFIED_COMBINING_CLASS_CCC17 || c0 == HB_MODIFIED_COMBINING_CLASS_CCC18) /* patach or qamats */ && |
180 | 12.5k | (c1 == HB_MODIFIED_COMBINING_CLASS_CCC10 || c1 == HB_MODIFIED_COMBINING_CLASS_CCC14) /* sheva or hiriq */ && |
181 | 12.5k | (c2 == HB_MODIFIED_COMBINING_CLASS_CCC22 || c2 == HB_UNICODE_COMBINING_CLASS_BELOW) /* meteg or below */) |
182 | 0 | { |
183 | 0 | buffer->merge_clusters (i - 1, i + 1); |
184 | 0 | hb_swap (info[i - 1], info[i]); |
185 | 0 | break; |
186 | 0 | } |
187 | 12.5k | } |
188 | | |
189 | | |
190 | 62.7k | } |
191 | | |
192 | | const hb_ot_shaper_t _hb_ot_shaper_hebrew = |
193 | | { |
194 | | nullptr, /* collect_features */ |
195 | | nullptr, /* override_features */ |
196 | | nullptr, /* data_create */ |
197 | | nullptr, /* data_destroy */ |
198 | | nullptr, /* preprocess_text */ |
199 | | nullptr, /* postprocess_glyphs */ |
200 | | nullptr, /* decompose */ |
201 | | compose_hebrew, |
202 | | nullptr, /* setup_masks */ |
203 | | reorder_marks_hebrew, |
204 | | HB_TAG ('h','e','b','r'), /* gpos_tag. https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368 */ |
205 | | HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT, |
206 | | HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, |
207 | | true, /* fallback_position */ |
208 | | }; |
209 | | |
210 | | |
211 | | #endif |