OLD | NEW |
1 /* | 1 /* |
2 * Copyright © 2011,2012 Google, Inc. | 2 * Copyright © 2011,2012 Google, Inc. |
3 * | 3 * |
4 * This is part of HarfBuzz, a text shaping library. | 4 * This is part of HarfBuzz, a text shaping library. |
5 * | 5 * |
6 * Permission is hereby granted, without written agreement and without | 6 * Permission is hereby granted, without written agreement and without |
7 * license or royalty fees, to use, copy, modify, and distribute this | 7 * license or royalty fees, to use, copy, modify, and distribute this |
8 * software and its documentation for any purpose, provided that the | 8 * software and its documentation for any purpose, provided that the |
9 * above copyright notice and the following two paragraphs appear in | 9 * above copyright notice and the following two paragraphs appear in |
10 * all copies of this software. | 10 * all copies of this software. |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 0x0BB0, /* Tamil */ /* No Reph */ | 121 0x0BB0, /* Tamil */ /* No Reph */ |
122 0x0C30, /* Telugu */ /* Reph formed only with ZWJ */ | 122 0x0C30, /* Telugu */ /* Reph formed only with ZWJ */ |
123 0x0CB0, /* Kannada */ | 123 0x0CB0, /* Kannada */ |
124 0x0D30, /* Malayalam */ /* No Reph, Logical Repha */ | 124 0x0D30, /* Malayalam */ /* No Reph, Logical Repha */ |
125 | 125 |
126 0x0DBB, /* Sinhala */ /* Reph formed only with ZWJ */ | 126 0x0DBB, /* Sinhala */ /* Reph formed only with ZWJ */ |
127 | 127 |
128 0x179A, /* Khmer */ /* No Reph, Visual Repha */ | 128 0x179A, /* Khmer */ /* No Reph, Visual Repha */ |
129 }; | 129 }; |
130 | 130 |
131 static inline indic_position_t | |
132 consonant_position (hb_codepoint_t u) | |
133 { | |
134 if ((u & ~0x007F) == 0x1780) | |
135 return POS_BELOW_C; /* In Khmer coeng model, post and below forms should not
be reordered. */ | |
136 return POS_BASE_C; /* Will recategorize later based on font lookups. */ | |
137 } | |
138 | |
139 static inline bool | 131 static inline bool |
140 is_ra (hb_codepoint_t u) | 132 is_ra (hb_codepoint_t u) |
141 { | 133 { |
142 for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++) | 134 for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++) |
143 if (u == ra_chars[i]) | 135 if (u == ra_chars[i]) |
144 return true; | 136 return true; |
145 return false; | 137 return false; |
146 } | 138 } |
147 | 139 |
148 static inline bool | 140 static inline bool |
149 is_one_of (const hb_glyph_info_t &info, unsigned int flags) | 141 is_one_of (const hb_glyph_info_t &info, unsigned int flags) |
150 { | 142 { |
151 /* If it ligated, all bets are off. */ | 143 /* If it ligated, all bets are off. */ |
152 if (is_a_ligature (info)) return false; | 144 if (_hb_glyph_info_ligated (&info)) return false; |
153 return !!(FLAG (info.indic_category()) & flags); | 145 return !!(FLAG (info.indic_category()) & flags); |
154 } | 146 } |
155 | 147 |
156 #define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ)) | 148 #define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ)) |
157 static inline bool | 149 static inline bool |
158 is_joiner (const hb_glyph_info_t &info) | 150 is_joiner (const hb_glyph_info_t &info) |
159 { | 151 { |
160 return is_one_of (info, JOINER_FLAGS); | 152 return is_one_of (info, JOINER_FLAGS); |
161 } | 153 } |
162 | 154 |
| 155 #define MEDIAL_FLAGS (FLAG (OT_CM) | FLAG (OT_CM2)) |
| 156 |
163 /* Note: | 157 /* Note: |
164 * | 158 * |
165 * We treat Vowels and placeholders as if they were consonants. This is safe be
cause Vowels | 159 * We treat Vowels and placeholders as if they were consonants. This is safe be
cause Vowels |
166 * cannot happen in a consonant syllable. The plus side however is, we can call
the | 160 * cannot happen in a consonant syllable. The plus side however is, we can call
the |
167 * consonant syllable logic from the vowel syllable function and get it all righ
t! */ | 161 * consonant syllable logic from the vowel syllable function and get it all righ
t! */ |
168 #define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CM) | FLAG (OT_Ra) | FLAG (OT_V)
| FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE)) | 162 #define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V)
| FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE)) |
169 static inline bool | 163 static inline bool |
170 is_consonant (const hb_glyph_info_t &info) | 164 is_consonant (const hb_glyph_info_t &info) |
171 { | 165 { |
172 return is_one_of (info, CONSONANT_FLAGS); | 166 return is_one_of (info, CONSONANT_FLAGS); |
173 } | 167 } |
174 | 168 |
175 #define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng)) | 169 #define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng)) |
176 static inline bool | 170 static inline bool |
177 is_halant_or_coeng (const hb_glyph_info_t &info) | 171 is_halant_or_coeng (const hb_glyph_info_t &info) |
178 { | 172 { |
179 return is_one_of (info, HALANT_OR_COENG_FLAGS); | 173 return is_one_of (info, HALANT_OR_COENG_FLAGS); |
180 } | 174 } |
181 | 175 |
182 static inline void | 176 static inline void |
183 set_indic_properties (hb_glyph_info_t &info) | 177 set_indic_properties (hb_glyph_info_t &info) |
184 { | 178 { |
185 hb_codepoint_t u = info.codepoint; | 179 hb_codepoint_t u = info.codepoint; |
186 unsigned int type = hb_indic_get_categories (u); | 180 unsigned int type = hb_indic_get_categories (u); |
187 indic_category_t cat = (indic_category_t) (type & 0x7F); | 181 indic_category_t cat = (indic_category_t) (type & 0x7F); |
188 indic_position_t pos = (indic_position_t) (type >> 8); | 182 indic_position_t pos = (indic_position_t) (type >> 8); |
189 | 183 |
190 | 184 |
191 /* | 185 /* |
192 * Re-assign category | 186 * Re-assign category |
193 */ | 187 */ |
194 | 188 |
195 | 189 |
196 /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe | 190 /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe |
197 * treats U+0951..U+0952 all as OT_VD. | 191 * treats U+0951..U+0954 all behave similarly. |
198 * TESTS: | 192 * TESTS: |
199 * U+092E,U+0947,U+0952 | 193 * U+092E,U+0947,U+0952 |
200 * U+092E,U+0952,U+0947 | 194 * U+092E,U+0952,U+0947 |
201 * U+092E,U+0947,U+0951 | 195 * U+092E,U+0947,U+0951 |
202 * U+092E,U+0951,U+0947 | 196 * U+092E,U+0951,U+0947 |
203 * */ | 197 */ |
204 if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0951, 0x0954))) | 198 if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0951, 0x0954))) |
205 cat = OT_VD; | 199 cat = OT_A; |
206 | 200 |
207 if (unlikely (u == 0x17D1)) | 201 if (unlikely (u == 0x17D1)) |
208 cat = OT_X; | 202 cat = OT_X; |
209 if (cat == OT_X && | 203 if (cat == OT_X && |
210 unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CB, 0x17D3))) /* Khmer Vario
us signs */ | 204 unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CB, 0x17D3))) /* Khmer Vario
us signs */ |
211 { | 205 { |
212 /* These are like Top Matras. */ | 206 /* These are like Top Matras. */ |
213 cat = OT_M; | 207 cat = OT_M; |
214 pos = POS_ABOVE_C; | 208 pos = POS_ABOVE_C; |
215 } | 209 } |
216 if (u == 0x17C6) /* Khmer Bindu doesn't like to be repositioned. */ | 210 if (u == 0x17C6) /* Khmer Bindu doesn't like to be repositioned. */ |
217 cat = OT_N; | 211 cat = OT_N; |
218 | 212 |
219 if (unlikely (u == 0x17D2)) cat = OT_Coeng; /* Khmer coeng */ | 213 if (unlikely (u == 0x17D2)) cat = OT_Coeng; /* Khmer coeng */ |
220 else if (unlikely (u == 0x200C)) cat = OT_ZWNJ; | 214 else if (unlikely (u == 0x200C)) cat = OT_ZWNJ; |
221 else if (unlikely (u == 0x200D)) cat = OT_ZWJ; | 215 else if (unlikely (u == 0x200D)) cat = OT_ZWJ; |
222 else if (unlikely (u == 0x25CC)) cat = OT_DOTTEDCIRCLE; | 216 else if (unlikely (u == 0x25CC)) cat = OT_DOTTEDCIRCLE; |
223 else if (unlikely (u == 0x0A71)) cat = OT_SM; /* GURMUKHI ADDAK. More like co
nsonant medial. like 0A75. */ | 217 else if (unlikely (u == 0x0A71)) cat = OT_SM; /* GURMUKHI ADDAK. Move it to t
he end. */ |
| 218 else if (unlikely (u == 0xA982)) cat = OT_SM; /* Javanese repha. */ |
| 219 else if (unlikely (u == 0xA9BE)) cat = OT_CM2; /* Javanese medial ya. */ |
| 220 else if (unlikely (u == 0xA9BD)) { cat = OT_M; pos = POS_POST_C; } /* Javanese
vocalic r. */ |
224 | 221 |
225 if (cat == OT_Repha) { | 222 if (cat == OT_Repha) { |
226 /* There are two kinds of characters marked as Repha: | 223 /* There are two kinds of characters marked as Repha: |
227 * - The ones that are GenCat=Mn are already positioned visually, ie. after
base. (eg. Khmer) | 224 * - The ones that are GenCat=Mn are already positioned visually, ie. after
base. (eg. Khmer) |
228 * - The ones that are GenCat=Lo is encoded logically, ie. beginning of syll
able. (eg. Malayalam) | 225 * - The ones that are GenCat=Lo is encoded logically, ie. beginning of syll
able. (eg. Malayalam) |
229 * | 226 * |
230 * We recategorize the first kind to look like a Nukta and attached to the b
ase directly. | 227 * We recategorize the first kind to look like a Nukta and attached to the b
ase directly. |
231 */ | 228 */ |
232 if (_hb_glyph_info_get_general_category (&info) == HB_UNICODE_GENERAL_CATEGO
RY_NON_SPACING_MARK) | 229 if (_hb_glyph_info_get_general_category (&info) == HB_UNICODE_GENERAL_CATEGO
RY_NON_SPACING_MARK) |
233 cat = OT_N; | 230 cat = OT_N; |
234 } | 231 } |
235 | 232 |
236 | 233 |
237 | 234 |
238 /* | 235 /* |
239 * Re-assign position. | 236 * Re-assign position. |
240 */ | 237 */ |
241 | 238 |
242 if ((FLAG (cat) & CONSONANT_FLAGS)) | 239 if ((FLAG (cat) & CONSONANT_FLAGS)) |
243 { | 240 { |
244 pos = consonant_position (u); | 241 pos = POS_BASE_C; |
245 if (is_ra (u)) | 242 if (is_ra (u)) |
246 cat = OT_Ra; | 243 cat = OT_Ra; |
247 } | 244 } |
248 else if (cat == OT_M) | 245 else if (cat == OT_M) |
249 { | 246 { |
250 pos = matra_position (u, pos); | 247 pos = matra_position (u, pos); |
251 } | 248 } |
252 else if (cat == OT_SM || cat == OT_VD) | 249 else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_A
vag)))) |
253 { | 250 { |
254 pos = POS_SMVD; | 251 pos = POS_SMVD; |
255 } | 252 } |
256 | 253 |
257 if (unlikely (u == 0x0B01)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub
in the spec. */ | 254 if (unlikely (u == 0x0B01)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub
in the spec. */ |
258 | 255 |
259 | 256 |
260 | 257 |
261 info.indic_category() = cat; | 258 info.indic_category() = cat; |
262 info.indic_position() = pos; | 259 info.indic_position() = pos; |
263 } | 260 } |
264 | 261 |
265 /* | 262 /* |
266 * Things above this line should ideally be moved to the Indic table itself. | 263 * Things above this line should ideally be moved to the Indic table itself. |
267 */ | 264 */ |
268 | 265 |
269 | 266 |
270 /* | 267 /* |
271 * Indic configurations. Note that we do not want to keep every single script-s
pecific | 268 * Indic configurations. Note that we do not want to keep every single script-s
pecific |
272 * behavior in these tables necessarily. This should mainly be used for per-scr
ipt | 269 * behavior in these tables necessarily. This should mainly be used for per-scr
ipt |
273 * properties that are cheaper keeping here, than in the code. Ie. if, say, one
and | 270 * properties that are cheaper keeping here, than in the code. Ie. if, say, one
and |
274 * only one script has an exception, that one script can be if'ed directly in th
e code, | 271 * only one script has an exception, that one script can be if'ed directly in th
e code, |
275 * instead of adding a new flag in these structs. | 272 * instead of adding a new flag in these structs. |
276 */ | 273 */ |
277 | 274 |
278 enum base_position_t { | 275 enum base_position_t { |
279 BASE_POS_FIRST, | 276 BASE_POS_FIRST, |
| 277 BASE_POS_LAST_SINHALA, |
280 BASE_POS_LAST | 278 BASE_POS_LAST |
281 }; | 279 }; |
282 enum reph_position_t { | 280 enum reph_position_t { |
283 REPH_POS_DEFAULT = POS_BEFORE_POST, | |
284 | |
285 REPH_POS_AFTER_MAIN = POS_AFTER_MAIN, | 281 REPH_POS_AFTER_MAIN = POS_AFTER_MAIN, |
286 REPH_POS_BEFORE_SUB = POS_BEFORE_SUB, | 282 REPH_POS_BEFORE_SUB = POS_BEFORE_SUB, |
287 REPH_POS_AFTER_SUB = POS_AFTER_SUB, | 283 REPH_POS_AFTER_SUB = POS_AFTER_SUB, |
288 REPH_POS_BEFORE_POST = POS_BEFORE_POST, | 284 REPH_POS_BEFORE_POST = POS_BEFORE_POST, |
289 REPH_POS_AFTER_POST = POS_AFTER_POST | 285 REPH_POS_AFTER_POST = POS_AFTER_POST, |
| 286 REPH_POS_DONT_CARE = POS_RA_TO_BECOME_REPH |
290 }; | 287 }; |
291 enum reph_mode_t { | 288 enum reph_mode_t { |
292 REPH_MODE_IMPLICIT, /* Reph formed out of initial Ra,H sequence. */ | 289 REPH_MODE_IMPLICIT, /* Reph formed out of initial Ra,H sequence. */ |
293 REPH_MODE_EXPLICIT, /* Reph formed out of initial Ra,H,ZWJ sequence. */ | 290 REPH_MODE_EXPLICIT, /* Reph formed out of initial Ra,H,ZWJ sequence. */ |
294 REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */ | 291 REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */ |
295 REPH_MODE_LOG_REPHA /* Encoded Repha character, needs reordering. */ | 292 REPH_MODE_LOG_REPHA /* Encoded Repha character, needs reordering. */ |
296 }; | 293 }; |
| 294 enum blwf_mode_t { |
| 295 BLWF_MODE_PRE_AND_POST, /* Below-forms feature applied to pre-base and post-ba
se. */ |
| 296 BLWF_MODE_POST_ONLY /* Below-forms feature applied to post-base only. */ |
| 297 }; |
| 298 enum pref_len_t { |
| 299 PREF_LEN_1 = 1, |
| 300 PREF_LEN_2 = 2, |
| 301 PREF_LEN_DONT_CARE = PREF_LEN_2 |
| 302 }; |
297 struct indic_config_t | 303 struct indic_config_t |
298 { | 304 { |
299 hb_script_t script; | 305 hb_script_t script; |
300 bool has_old_spec; | 306 bool has_old_spec; |
301 hb_codepoint_t virama; | 307 hb_codepoint_t virama; |
302 base_position_t base_pos; | 308 base_position_t base_pos; |
303 reph_position_t reph_pos; | 309 reph_position_t reph_pos; |
304 reph_mode_t reph_mode; | 310 reph_mode_t reph_mode; |
| 311 blwf_mode_t blwf_mode; |
| 312 pref_len_t pref_len; |
305 }; | 313 }; |
306 | 314 |
307 static const indic_config_t indic_configs[] = | 315 static const indic_config_t indic_configs[] = |
308 { | 316 { |
309 /* Default. Should be first. */ | 317 /* Default. Should be first. */ |
310 {HB_SCRIPT_INVALID,» false, 0,BASE_POS_LAST, REPH_POS_DEFAULT, REPH_MO
DE_IMPLICIT}, | 318 {HB_SCRIPT_INVALID,» false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MO
DE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1}, |
311 {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MO
DE_IMPLICIT}, | 319 {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MO
DE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, |
312 {HB_SCRIPT_BENGALI,» true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MO
DE_IMPLICIT}, | 320 {HB_SCRIPT_BENGALI,» true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MO
DE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, |
313 {HB_SCRIPT_GURMUKHI,» true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MO
DE_IMPLICIT}, | 321 {HB_SCRIPT_GURMUKHI,» true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MO
DE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, |
314 {HB_SCRIPT_GUJARATI,» true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MO
DE_IMPLICIT}, | 322 {HB_SCRIPT_GUJARATI,» true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MO
DE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, |
315 {HB_SCRIPT_ORIYA,» true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MO
DE_IMPLICIT}, | 323 {HB_SCRIPT_ORIYA,» true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MO
DE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, |
316 {HB_SCRIPT_TAMIL,» true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MO
DE_IMPLICIT}, | 324 {HB_SCRIPT_TAMIL,» true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MO
DE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, |
317 {HB_SCRIPT_TELUGU,» true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MO
DE_EXPLICIT}, | 325 {HB_SCRIPT_TELUGU,» true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MO
DE_EXPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2}, |
318 {HB_SCRIPT_KANNADA,» true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MO
DE_IMPLICIT}, | 326 {HB_SCRIPT_KANNADA,» true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MO
DE_IMPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2}, |
319 {HB_SCRIPT_MALAYALAM,»true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MO
DE_LOG_REPHA}, | 327 {HB_SCRIPT_MALAYALAM,»true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MO
DE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, |
320 {HB_SCRIPT_SINHALA,» false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MO
DE_EXPLICIT}, | 328 {HB_SCRIPT_SINHALA,» false,0x0DCA,BASE_POS_LAST_SINHALA, |
321 {HB_SCRIPT_KHMER,» false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT, REPH_MO
DE_VIS_REPHA}, | 329 » » » » » » REPH_POS_AFTER_MAIN, REPH_MO
DE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, |
| 330 {HB_SCRIPT_KHMER,» false,0x17D2,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MO
DE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, |
| 331 {HB_SCRIPT_JAVANESE,» false,0xA9C0,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MO
DE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1}, |
322 }; | 332 }; |
323 | 333 |
324 | 334 |
325 | 335 |
326 /* | 336 /* |
327 * Indic shaper. | 337 * Indic shaper. |
328 */ | 338 */ |
329 | 339 |
330 struct feature_list_t { | 340 struct feature_list_t { |
331 hb_tag_t tag; | 341 hb_tag_t tag; |
332 hb_ot_map_feature_flags_t flags; | 342 hb_ot_map_feature_flags_t flags; |
333 }; | 343 }; |
334 | 344 |
335 static const feature_list_t | 345 static const feature_list_t |
336 indic_features[] = | 346 indic_features[] = |
337 { | 347 { |
338 /* | 348 /* |
339 * Basic features. | 349 * Basic features. |
340 * These features are applied in order, one at a time, after initial_reorderin
g. | 350 * These features are applied in order, one at a time, after initial_reorderin
g. |
341 */ | 351 */ |
342 {HB_TAG('n','u','k','t'), F_GLOBAL}, | 352 {HB_TAG('n','u','k','t'), F_GLOBAL}, |
343 {HB_TAG('a','k','h','n'), F_GLOBAL}, | 353 {HB_TAG('a','k','h','n'), F_GLOBAL}, |
344 {HB_TAG('r','p','h','f'), F_NONE}, | 354 {HB_TAG('r','p','h','f'), F_NONE}, |
345 {HB_TAG('r','k','r','f'), F_GLOBAL}, | 355 {HB_TAG('r','k','r','f'), F_GLOBAL}, |
346 {HB_TAG('p','r','e','f'), F_NONE}, | 356 {HB_TAG('p','r','e','f'), F_NONE}, |
347 {HB_TAG('b','l','w','f'), F_NONE}, | 357 {HB_TAG('b','l','w','f'), F_NONE}, |
| 358 {HB_TAG('a','b','v','f'), F_NONE}, |
348 {HB_TAG('h','a','l','f'), F_NONE}, | 359 {HB_TAG('h','a','l','f'), F_NONE}, |
349 {HB_TAG('a','b','v','f'), F_NONE}, | |
350 {HB_TAG('p','s','t','f'), F_NONE}, | 360 {HB_TAG('p','s','t','f'), F_NONE}, |
351 {HB_TAG('c','f','a','r'), F_NONE}, | |
352 {HB_TAG('v','a','t','u'), F_GLOBAL}, | 361 {HB_TAG('v','a','t','u'), F_GLOBAL}, |
353 {HB_TAG('c','j','c','t'), F_GLOBAL}, | 362 {HB_TAG('c','j','c','t'), F_GLOBAL}, |
| 363 {HB_TAG('c','f','a','r'), F_NONE}, |
354 /* | 364 /* |
355 * Other features. | 365 * Other features. |
356 * These features are applied all at once, after final_reordering. | 366 * These features are applied all at once, after final_reordering. |
| 367 * Default Bengali font in Windows for example has intermixed |
| 368 * lookups for init,pres,abvs,blws features. |
357 */ | 369 */ |
358 {HB_TAG('i','n','i','t'), F_NONE}, | 370 {HB_TAG('i','n','i','t'), F_NONE}, |
359 {HB_TAG('p','r','e','s'), F_GLOBAL}, | 371 {HB_TAG('p','r','e','s'), F_GLOBAL}, |
360 {HB_TAG('a','b','v','s'), F_GLOBAL}, | 372 {HB_TAG('a','b','v','s'), F_GLOBAL}, |
361 {HB_TAG('b','l','w','s'), F_GLOBAL}, | 373 {HB_TAG('b','l','w','s'), F_GLOBAL}, |
362 {HB_TAG('p','s','t','s'), F_GLOBAL}, | 374 {HB_TAG('p','s','t','s'), F_GLOBAL}, |
363 {HB_TAG('h','a','l','n'), F_GLOBAL}, | 375 {HB_TAG('h','a','l','n'), F_GLOBAL}, |
364 /* Positioning features, though we don't care about the types. */ | 376 /* Positioning features, though we don't care about the types. */ |
365 {HB_TAG('d','i','s','t'), F_GLOBAL}, | 377 {HB_TAG('d','i','s','t'), F_GLOBAL}, |
366 {HB_TAG('a','b','v','m'), F_GLOBAL}, | 378 {HB_TAG('a','b','v','m'), F_GLOBAL}, |
367 {HB_TAG('b','l','w','m'), F_GLOBAL}, | 379 {HB_TAG('b','l','w','m'), F_GLOBAL}, |
368 }; | 380 }; |
369 | 381 |
370 /* | 382 /* |
371 * Must be in the same order as the indic_features array. | 383 * Must be in the same order as the indic_features array. |
372 */ | 384 */ |
373 enum { | 385 enum { |
374 _NUKT, | 386 _NUKT, |
375 _AKHN, | 387 _AKHN, |
376 RPHF, | 388 RPHF, |
377 _RKRF, | 389 _RKRF, |
378 PREF, | 390 PREF, |
379 BLWF, | 391 BLWF, |
| 392 ABVF, |
380 HALF, | 393 HALF, |
381 ABVF, | |
382 PSTF, | 394 PSTF, |
383 CFAR, | |
384 _VATU, | 395 _VATU, |
385 _CJCT, | 396 _CJCT, |
| 397 CFAR, |
386 | 398 |
387 INIT, | 399 INIT, |
388 _PRES, | 400 _PRES, |
389 _ABVS, | 401 _ABVS, |
390 _BLWS, | 402 _BLWS, |
391 _PSTS, | 403 _PSTS, |
392 _HALN, | 404 _HALN, |
393 _DIST, | 405 _DIST, |
394 _ABVM, | 406 _ABVM, |
395 _BLWM, | 407 _BLWM, |
396 | 408 |
397 INDIC_NUM_FEATURES, | 409 INDIC_NUM_FEATURES, |
398 INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */ | 410 INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */ |
399 }; | 411 }; |
400 | 412 |
401 static void | 413 static void |
402 setup_syllables (const hb_ot_shape_plan_t *plan, | 414 setup_syllables (const hb_ot_shape_plan_t *plan, |
403 hb_font_t *font, | 415 hb_font_t *font, |
404 hb_buffer_t *buffer); | 416 hb_buffer_t *buffer); |
405 static void | 417 static void |
406 initial_reordering (const hb_ot_shape_plan_t *plan, | 418 initial_reordering (const hb_ot_shape_plan_t *plan, |
407 hb_font_t *font, | 419 hb_font_t *font, |
408 hb_buffer_t *buffer); | 420 hb_buffer_t *buffer); |
409 static void | 421 static void |
410 final_reordering (const hb_ot_shape_plan_t *plan, | 422 final_reordering (const hb_ot_shape_plan_t *plan, |
411 hb_font_t *font, | 423 hb_font_t *font, |
412 hb_buffer_t *buffer); | 424 hb_buffer_t *buffer); |
| 425 static void |
| 426 clear_syllables (const hb_ot_shape_plan_t *plan, |
| 427 hb_font_t *font, |
| 428 hb_buffer_t *buffer); |
413 | 429 |
414 static void | 430 static void |
415 collect_features_indic (hb_ot_shape_planner_t *plan) | 431 collect_features_indic (hb_ot_shape_planner_t *plan) |
416 { | 432 { |
417 hb_ot_map_builder_t *map = &plan->map; | 433 hb_ot_map_builder_t *map = &plan->map; |
418 | 434 |
419 /* Do this before any lookups have been applied. */ | 435 /* Do this before any lookups have been applied. */ |
420 map->add_gsub_pause (setup_syllables); | 436 map->add_gsub_pause (setup_syllables); |
421 | 437 |
422 map->add_global_bool_feature (HB_TAG('l','o','c','l')); | 438 map->add_global_bool_feature (HB_TAG('l','o','c','l')); |
423 /* The Indic specs do not require ccmp, but we apply it here since if | 439 /* The Indic specs do not require ccmp, but we apply it here since if |
424 * there is a use of it, it's typically at the beginning. */ | 440 * there is a use of it, it's typically at the beginning. */ |
425 map->add_global_bool_feature (HB_TAG('c','c','m','p')); | 441 map->add_global_bool_feature (HB_TAG('c','c','m','p')); |
426 | 442 |
427 | 443 |
428 unsigned int i = 0; | 444 unsigned int i = 0; |
429 map->add_gsub_pause (initial_reordering); | 445 map->add_gsub_pause (initial_reordering); |
430 for (; i < INDIC_BASIC_FEATURES; i++) { | 446 for (; i < INDIC_BASIC_FEATURES; i++) { |
431 map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANU
AL_ZWJ); | 447 map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANU
AL_ZWJ); |
432 map->add_gsub_pause (NULL); | 448 map->add_gsub_pause (NULL); |
433 } | 449 } |
434 map->add_gsub_pause (final_reordering); | 450 map->add_gsub_pause (final_reordering); |
435 for (; i < INDIC_NUM_FEATURES; i++) { | 451 for (; i < INDIC_NUM_FEATURES; i++) { |
436 map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANU
AL_ZWJ); | 452 map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANU
AL_ZWJ); |
437 } | 453 } |
| 454 |
| 455 map->add_global_bool_feature (HB_TAG('c','a','l','t')); |
| 456 map->add_global_bool_feature (HB_TAG('c','l','i','g')); |
| 457 |
| 458 map->add_gsub_pause (clear_syllables); |
438 } | 459 } |
439 | 460 |
440 static void | 461 static void |
441 override_features_indic (hb_ot_shape_planner_t *plan) | 462 override_features_indic (hb_ot_shape_planner_t *plan) |
442 { | 463 { |
443 /* Uniscribe does not apply 'kern'. */ | 464 /* Uniscribe does not apply 'kern' in Khmer. */ |
444 if (hb_options ().uniscribe_bug_compatible) | 465 if (hb_options ().uniscribe_bug_compatible) |
445 plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL); | 466 { |
| 467 switch ((hb_tag_t) plan->props.script) |
| 468 { |
| 469 case HB_SCRIPT_KHMER: |
| 470 » plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL); |
| 471 » break; |
| 472 } |
| 473 } |
446 | 474 |
447 plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); | 475 plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); |
448 } | 476 } |
449 | 477 |
450 | 478 |
451 struct would_substitute_feature_t | 479 struct would_substitute_feature_t |
452 { | 480 { |
453 inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag) | 481 inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_cont
ext_) |
454 { | 482 { |
| 483 zero_context = zero_context_; |
455 map->get_stage_lookups (0/*GSUB*/, | 484 map->get_stage_lookups (0/*GSUB*/, |
456 map->get_feature_stage (0/*GSUB*/, feature_tag), | 485 map->get_feature_stage (0/*GSUB*/, feature_tag), |
457 &lookups, &count); | 486 &lookups, &count); |
458 } | 487 } |
459 | 488 |
460 inline bool would_substitute (const hb_codepoint_t *glyphs, | 489 inline bool would_substitute (const hb_codepoint_t *glyphs, |
461 unsigned int glyphs_count, | 490 unsigned int glyphs_count, |
462 bool zero_context, | |
463 hb_face_t *face) const | 491 hb_face_t *face) const |
464 { | 492 { |
465 for (unsigned int i = 0; i < count; i++) | 493 for (unsigned int i = 0; i < count; i++) |
466 if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, gly
phs, glyphs_count, zero_context)) | 494 if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, gly
phs, glyphs_count, zero_context)) |
467 return true; | 495 return true; |
468 return false; | 496 return false; |
469 } | 497 } |
470 | 498 |
471 private: | 499 private: |
472 const hb_ot_map_t::lookup_map_t *lookups; | 500 const hb_ot_map_t::lookup_map_t *lookups; |
473 unsigned int count; | 501 unsigned int count; |
| 502 bool zero_context; |
474 }; | 503 }; |
475 | 504 |
476 struct indic_shape_plan_t | 505 struct indic_shape_plan_t |
477 { | 506 { |
478 ASSERT_POD (); | 507 ASSERT_POD (); |
479 | 508 |
480 inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const | 509 inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const |
481 { | 510 { |
482 hb_codepoint_t glyph = virama_glyph; | 511 hb_codepoint_t glyph = virama_glyph; |
483 if (unlikely (virama_glyph == (hb_codepoint_t) -1)) | 512 if (unlikely (virama_glyph == (hb_codepoint_t) -1)) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
519 indic_plan->config = &indic_configs[0]; | 548 indic_plan->config = &indic_configs[0]; |
520 for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++) | 549 for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++) |
521 if (plan->props.script == indic_configs[i].script) { | 550 if (plan->props.script == indic_configs[i].script) { |
522 indic_plan->config = &indic_configs[i]; | 551 indic_plan->config = &indic_configs[i]; |
523 break; | 552 break; |
524 } | 553 } |
525 | 554 |
526 indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chos
en_script[0] & 0x000000FF) != '2'); | 555 indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chos
en_script[0] & 0x000000FF) != '2'); |
527 indic_plan->virama_glyph = (hb_codepoint_t) -1; | 556 indic_plan->virama_glyph = (hb_codepoint_t) -1; |
528 | 557 |
529 indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f')); | 558 /* Use zero-context would_substitute() matching for new-spec of the main |
530 indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f')); | 559 * Indic scripts, but not for old-spec or scripts with one spec only. */ |
531 indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f')); | 560 bool zero_context = indic_plan->config->has_old_spec || !indic_plan->is_old_sp
ec; |
532 indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f')); | 561 indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context); |
| 562 indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context); |
| 563 indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context); |
| 564 indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context); |
533 | 565 |
534 for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) | 566 for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) |
535 indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ? | 567 indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ? |
536 0 : plan->map.get_1_mask (indic_features[i].tag
); | 568 0 : plan->map.get_1_mask (indic_features[i].tag
); |
537 | 569 |
538 return indic_plan; | 570 return indic_plan; |
539 } | 571 } |
540 | 572 |
541 static void | 573 static void |
542 data_destroy_indic (void *data) | 574 data_destroy_indic (void *data) |
543 { | 575 { |
544 free (data); | 576 free (data); |
545 } | 577 } |
546 | 578 |
547 static indic_position_t | 579 static indic_position_t |
548 consonant_position_from_face (const indic_shape_plan_t *indic_plan, | 580 consonant_position_from_face (const indic_shape_plan_t *indic_plan, |
549 » » » const hb_codepoint_t glyphs[2], | 581 » » » const hb_codepoint_t consonant, |
| 582 » » » const hb_codepoint_t virama, |
550 hb_face_t *face) | 583 hb_face_t *face) |
551 { | 584 { |
552 /* For old-spec, the order of glyphs is Consonant,Virama, | 585 /* For old-spec, the order of glyphs is Consonant,Virama, |
553 * whereas for new-spec, it's Virama,Consonant. However, | 586 * whereas for new-spec, it's Virama,Consonant. However, |
554 * some broken fonts (like Free Sans) simply copied lookups | 587 * some broken fonts (like Free Sans) simply copied lookups |
555 * from old-spec to new-spec without modification. | 588 * from old-spec to new-spec without modification. |
556 * And oddly enough, Uniscribe seems to respect those lookups. | 589 * And oddly enough, Uniscribe seems to respect those lookups. |
557 * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds | 590 * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds |
558 * base at 0. The font however, only has lookups matching | 591 * base at 0. The font however, only has lookups matching |
559 * 930,94D in 'blwf', not the expected 94D,930 (with new-spec | 592 * 930,94D in 'blwf', not the expected 94D,930 (with new-spec |
560 * table). As such, we simply match both sequences. Seems | 593 * table). As such, we simply match both sequences. Seems |
561 * to work. */ | 594 * to work. */ |
562 bool zero_context = indic_plan->is_old_spec ? false : true; | 595 hb_codepoint_t glyphs[3] = {virama, consonant, virama}; |
563 hb_codepoint_t glyphs_r[2] = {glyphs[1], glyphs[0]}; | 596 if (indic_plan->blwf.would_substitute (glyphs , 2, face) || |
564 if (indic_plan->pref.would_substitute (glyphs , 2, zero_context, face) || | 597 indic_plan->blwf.would_substitute (glyphs+1, 2, face)) |
565 indic_plan->pref.would_substitute (glyphs_r, 2, zero_context, face)) | 598 return POS_BELOW_C; |
| 599 if (indic_plan->pstf.would_substitute (glyphs , 2, face) || |
| 600 indic_plan->pstf.would_substitute (glyphs+1, 2, face)) |
566 return POS_POST_C; | 601 return POS_POST_C; |
567 if (indic_plan->blwf.would_substitute (glyphs , 2, zero_context, face) || | 602 unsigned int pref_len = indic_plan->config->pref_len; |
568 indic_plan->blwf.would_substitute (glyphs_r, 2, zero_context, face)) | 603 if ((pref_len == PREF_LEN_2 && |
569 return POS_BELOW_C; | 604 (indic_plan->pref.would_substitute (glyphs , 2, face) || |
570 if (indic_plan->pstf.would_substitute (glyphs , 2, zero_context, face) || | 605 indic_plan->pref.would_substitute (glyphs+1, 2, face))) |
571 indic_plan->pstf.would_substitute (glyphs_r, 2, zero_context, face)) | 606 || (pref_len == PREF_LEN_1 && |
| 607 indic_plan->pref.would_substitute (glyphs+1, 1, face))) |
572 return POS_POST_C; | 608 return POS_POST_C; |
573 return POS_BASE_C; | 609 return POS_BASE_C; |
574 } | 610 } |
575 | 611 |
576 | 612 |
577 enum syllable_type_t { | 613 enum syllable_type_t { |
578 consonant_syllable, | 614 consonant_syllable, |
579 vowel_syllable, | 615 vowel_syllable, |
580 standalone_cluster, | 616 standalone_cluster, |
| 617 avagraha_cluster, |
581 broken_cluster, | 618 broken_cluster, |
582 non_indic_cluster, | 619 non_indic_cluster, |
583 }; | 620 }; |
584 | 621 |
585 #include "hb-ot-shape-complex-indic-machine.hh" | 622 #include "hb-ot-shape-complex-indic-machine.hh" |
586 | 623 |
587 | 624 |
588 static void | 625 static void |
589 setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, | 626 setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, |
590 hb_buffer_t *buffer, | 627 hb_buffer_t *buffer, |
(...skipping 29 matching lines...) Expand all Loading... |
620 | 657 |
621 | 658 |
622 | 659 |
623 static void | 660 static void |
624 update_consonant_positions (const hb_ot_shape_plan_t *plan, | 661 update_consonant_positions (const hb_ot_shape_plan_t *plan, |
625 hb_font_t *font, | 662 hb_font_t *font, |
626 hb_buffer_t *buffer) | 663 hb_buffer_t *buffer) |
627 { | 664 { |
628 const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data
; | 665 const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data
; |
629 | 666 |
630 hb_codepoint_t glyphs[2]; | 667 if (indic_plan->config->base_pos != BASE_POS_LAST) |
631 if (indic_plan->get_virama_glyph (font, &glyphs[0])) | 668 return; |
| 669 |
| 670 hb_codepoint_t virama; |
| 671 if (indic_plan->get_virama_glyph (font, &virama)) |
632 { | 672 { |
633 hb_face_t *face = font->face; | 673 hb_face_t *face = font->face; |
634 unsigned int count = buffer->len; | 674 unsigned int count = buffer->len; |
635 for (unsigned int i = 0; i < count; i++) | 675 for (unsigned int i = 0; i < count; i++) |
636 if (buffer->info[i].indic_position() == POS_BASE_C) { | 676 if (buffer->info[i].indic_position() == POS_BASE_C) { |
637 » glyphs[1] = buffer->info[i].codepoint; | 677 » hb_codepoint_t consonant = buffer->info[i].codepoint; |
638 » buffer->info[i].indic_position() = consonant_position_from_face (indic_p
lan, glyphs, face); | 678 » buffer->info[i].indic_position() = consonant_position_from_face (indic_p
lan, consonant, virama, face); |
639 } | 679 } |
640 } | 680 } |
641 } | 681 } |
642 | 682 |
643 | 683 |
644 /* Rules from: | 684 /* Rules from: |
645 * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ | 685 * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ |
646 | 686 |
647 static void | 687 static void |
648 initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, | 688 initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, |
(...skipping 20 matching lines...) Expand all Loading... |
669 */ | 709 */ |
670 | 710 |
671 unsigned int base = end; | 711 unsigned int base = end; |
672 bool has_reph = false; | 712 bool has_reph = false; |
673 | 713 |
674 { | 714 { |
675 /* -> If the syllable starts with Ra + Halant (in a script that has Reph) | 715 /* -> If the syllable starts with Ra + Halant (in a script that has Reph) |
676 * and has more than one consonant, Ra is excluded from candidates for | 716 * and has more than one consonant, Ra is excluded from candidates for |
677 * base consonants. */ | 717 * base consonants. */ |
678 unsigned int limit = start; | 718 unsigned int limit = start; |
679 if (indic_plan->mask_array[RPHF] && | 719 if (indic_plan->config->reph_pos != REPH_POS_DONT_CARE && |
| 720 » indic_plan->mask_array[RPHF] && |
680 start + 3 <= end && | 721 start + 3 <= end && |
681 ( | 722 ( |
682 (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (inf
o[start + 2])) || | 723 (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (inf
o[start + 2])) || |
683 (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2]
.indic_category() == OT_ZWJ) | 724 (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2]
.indic_category() == OT_ZWJ) |
684 )) | 725 )) |
685 { | 726 { |
686 /* See if it matches the 'rphf' feature. */ | 727 /* See if it matches the 'rphf' feature. */ |
687 hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoi
nt}; | 728 hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoi
nt}; |
688 if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true
, face)) | 729 if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face
)) |
689 { | 730 { |
690 limit += 2; | 731 limit += 2; |
691 while (limit < end && is_joiner (info[limit])) | 732 while (limit < end && is_joiner (info[limit])) |
692 limit++; | 733 limit++; |
693 base = start; | 734 base = start; |
694 has_reph = true; | 735 has_reph = true; |
695 } | 736 } |
696 } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[star
t].indic_category() == OT_Repha) | 737 } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[star
t].indic_category() == OT_Repha) |
697 { | 738 { |
698 limit += 1; | 739 limit += 1; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
750 * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */ | 791 * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */ |
751 if (start < i && | 792 if (start < i && |
752 info[i].indic_category() == OT_ZWJ && | 793 info[i].indic_category() == OT_ZWJ && |
753 info[i - 1].indic_category() == OT_H) | 794 info[i - 1].indic_category() == OT_H) |
754 break; | 795 break; |
755 } | 796 } |
756 } while (i > limit); | 797 } while (i > limit); |
757 } | 798 } |
758 break; | 799 break; |
759 | 800 |
760 case BASE_POS_FIRST: | 801 case BASE_POS_LAST_SINHALA: |
761 { | 802 { |
762 » /* In scripts without half forms (eg. Khmer), the first consonant is alw
ays the base. */ | 803 /* Sinhala base positioning is slightly different from main Indic, in th
at: |
| 804 » * 1. It's ZWJ behavior is different, |
| 805 » * 2. We don't need to look into the font for consonant positions. |
| 806 » */ |
763 | 807 |
764 if (!has_reph) | 808 if (!has_reph) |
765 base = limit; | 809 base = limit; |
766 | 810 |
767 /* Find the last base consonant that is not blocked by ZWJ. If there is | 811 /* Find the last base consonant that is not blocked by ZWJ. If there is |
768 * a ZWJ right before a base consonant, that would request a subjoined f
orm. */ | 812 * a ZWJ right before a base consonant, that would request a subjoined f
orm. */ |
769 for (unsigned int i = limit; i < end; i++) | 813 for (unsigned int i = limit; i < end; i++) |
770 » if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) | 814 » if (is_consonant (info[i])) |
771 { | 815 { |
772 if (limit < i && info[i - 1].indic_category() == OT_ZWJ) | 816 if (limit < i && info[i - 1].indic_category() == OT_ZWJ) |
773 break; | 817 break; |
774 else | 818 else |
775 base = i; | 819 base = i; |
776 } | 820 } |
777 | 821 |
778 /* Mark all subsequent consonants as below. */ | 822 /* Mark all subsequent consonants as below. */ |
779 for (unsigned int i = base + 1; i < end; i++) | 823 for (unsigned int i = base + 1; i < end; i++) |
780 » if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) | 824 » if (is_consonant (info[i])) |
781 info[i].indic_position() = POS_BELOW_C; | 825 info[i].indic_position() = POS_BELOW_C; |
782 } | 826 } |
783 break; | 827 break; |
| 828 |
| 829 case BASE_POS_FIRST: |
| 830 { |
| 831 /* The first consonant is always the base. */ |
| 832 |
| 833 assert (indic_plan->config->reph_mode == REPH_MODE_VIS_REPHA); |
| 834 assert (!has_reph); |
| 835 |
| 836 base = start; |
| 837 |
| 838 /* Mark all subsequent consonants as below. */ |
| 839 for (unsigned int i = base + 1; i < end; i++) |
| 840 if (is_consonant (info[i])) |
| 841 info[i].indic_position() = POS_BELOW_C; |
| 842 } |
| 843 break; |
784 } | 844 } |
785 | 845 |
786 /* -> If the syllable starts with Ra + Halant (in a script that has Reph) | 846 /* -> If the syllable starts with Ra + Halant (in a script that has Reph) |
787 * and has more than one consonant, Ra is excluded from candidates for | 847 * and has more than one consonant, Ra is excluded from candidates for |
788 * base consonants. | 848 * base consonants. |
789 * | 849 * |
790 * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ | 850 * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ |
791 if (has_reph && base == start && limit - base <= 2) { | 851 if (has_reph && base == start && limit - base <= 2) { |
792 /* Have no other consonant, so Reph is not formed and Ra becomes base. */ | 852 /* Have no other consonant, so Reph is not formed and Ra becomes base. */ |
793 has_reph = false; | 853 has_reph = false; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
869 } | 929 } |
870 break; | 930 break; |
871 } | 931 } |
872 } | 932 } |
873 | 933 |
874 /* Attach misc marks to previous char to move with them. */ | 934 /* Attach misc marks to previous char to move with them. */ |
875 { | 935 { |
876 indic_position_t last_pos = POS_START; | 936 indic_position_t last_pos = POS_START; |
877 for (unsigned int i = start; i < end; i++) | 937 for (unsigned int i = start; i < end; i++) |
878 { | 938 { |
879 if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG
(OT_RS) | HALANT_OR_COENG_FLAGS))) | 939 if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG
(OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS))) |
880 { | 940 { |
881 info[i].indic_position() = last_pos; | 941 info[i].indic_position() = last_pos; |
882 if (unlikely (info[i].indic_category() == OT_H && | 942 if (unlikely (info[i].indic_category() == OT_H && |
883 info[i].indic_position() == POS_PRE_M)) | 943 info[i].indic_position() == POS_PRE_M)) |
884 { | 944 { |
885 /* | 945 /* |
886 * Uniscribe doesn't move the Halant with Left Matra. | 946 * Uniscribe doesn't move the Halant with Left Matra. |
887 * TEST: U+092B,U+093F,U+094DE | 947 * TEST: U+092B,U+093F,U+094DE |
888 * We follow. This is important for the Sinhala | 948 * We follow. This is important for the Sinhala |
889 * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA | 949 * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA |
890 * where U+0DD9 is a left matra and U+0DCA is the virama. | 950 * where U+0DD9 is a left matra and U+0DCA is the virama. |
891 * We don't want to move the virama with the left matra. | 951 * We don't want to move the virama with the left matra. |
892 * TEST: U+0D9A,U+0DDA | 952 * TEST: U+0D9A,U+0DDA |
893 */ | 953 */ |
894 for (unsigned int j = i; j > start; j--) | 954 for (unsigned int j = i; j > start; j--) |
895 if (info[j - 1].indic_position() != POS_PRE_M) { | 955 if (info[j - 1].indic_position() != POS_PRE_M) { |
896 info[i].indic_position() = info[j - 1].indic_position(); | 956 info[i].indic_position() = info[j - 1].indic_position(); |
897 break; | 957 break; |
898 } | 958 } |
899 } | 959 } |
900 } else if (info[i].indic_position() != POS_SMVD) { | 960 } else if (info[i].indic_position() != POS_SMVD) { |
901 last_pos = (indic_position_t) info[i].indic_position(); | 961 last_pos = (indic_position_t) info[i].indic_position(); |
902 } | 962 } |
903 } | 963 } |
904 } | 964 } |
905 /* Re-attach ZWJ, ZWNJ, and halant to next char, for after-base consonants. */ | 965 /* For post-base consonants let them own anything before them |
| 966 * since the last consonant or matra. */ |
906 { | 967 { |
907 unsigned int last_halant = end; | 968 unsigned int last = base; |
908 for (unsigned int i = base + 1; i < end; i++) | 969 for (unsigned int i = base + 1; i < end; i++) |
909 if (is_halant_or_coeng (info[i])) | 970 if (is_consonant (info[i])) |
910 last_halant = i; | 971 { |
911 else if (is_consonant (info[i])) { | 972 » for (unsigned int j = last + 1; j < i; j++) |
912 » for (unsigned int j = last_halant; j < i; j++) | 973 » if (info[j].indic_position() < POS_SMVD) |
913 » if (info[j].indic_position() != POS_SMVD) | |
914 info[j].indic_position() = info[i].indic_position(); | 974 info[j].indic_position() = info[i].indic_position(); |
915 } | 975 » last = i; |
| 976 } else if (info[i].indic_category() == OT_M) |
| 977 last = i; |
916 } | 978 } |
917 | 979 |
| 980 |
918 { | 981 { |
919 /* Things are out-of-control for post base positions, they may shuffle | 982 /* Use syllable() for sort accounting temporarily. */ |
920 * around like crazy, so merge clusters. For pre-base stuff, we handle | 983 unsigned int syllable = info[start].syllable(); |
921 * cluster issues in final reordering. */ | 984 for (unsigned int i = start; i < end; i++) |
922 buffer->merge_clusters (base, end); | 985 info[i].syllable() = i - start; |
| 986 |
923 /* Sit tight, rock 'n roll! */ | 987 /* Sit tight, rock 'n roll! */ |
924 hb_bubble_sort (info + start, end - start, compare_indic_order); | 988 hb_bubble_sort (info + start, end - start, compare_indic_order); |
925 /* Find base again */ | 989 /* Find base again */ |
926 base = end; | 990 base = end; |
927 for (unsigned int i = start; i < end; i++) | 991 for (unsigned int i = start; i < end; i++) |
928 if (info[i].indic_position() == POS_BASE_C) { | 992 if (info[i].indic_position() == POS_BASE_C) |
929 base = i; | 993 { |
| 994 » base = i; |
930 break; | 995 break; |
931 } | 996 } |
| 997 /* Things are out-of-control for post base positions, they may shuffle |
| 998 * around like crazy. In old-spec mode, we move halants around, so in |
| 999 * that case merge all clusters after base. Otherwise, check the sort |
| 1000 * order and merge as needed. |
| 1001 * For pre-base stuff, we handle cluster issues in final reordering. */ |
| 1002 if (indic_plan->is_old_spec || end - base > 127) |
| 1003 buffer->merge_clusters (base, end); |
| 1004 else |
| 1005 { |
| 1006 /* Note! syllable() is a one-byte field. */ |
| 1007 for (unsigned int i = base; i < end; i++) |
| 1008 if (info[i].syllable() != 255) |
| 1009 { |
| 1010 unsigned int max = i; |
| 1011 unsigned int j = start + info[i].syllable(); |
| 1012 while (j != i) |
| 1013 { |
| 1014 max = MAX (max, j); |
| 1015 unsigned int next = start + info[j].syllable(); |
| 1016 info[j].syllable() = 255; /* So we don't process j later again. */ |
| 1017 j = next; |
| 1018 } |
| 1019 if (i != max) |
| 1020 buffer->merge_clusters (i, max + 1); |
| 1021 } |
| 1022 } |
| 1023 |
| 1024 /* Put syllable back in. */ |
| 1025 for (unsigned int i = start; i < end; i++) |
| 1026 info[i].syllable() = syllable; |
932 } | 1027 } |
933 | 1028 |
934 /* Setup masks now */ | 1029 /* Setup masks now */ |
935 | 1030 |
936 { | 1031 { |
937 hb_mask_t mask; | 1032 hb_mask_t mask; |
938 | 1033 |
939 /* Reph */ | 1034 /* Reph */ |
940 for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_T
O_BECOME_REPH; i++) | 1035 for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_T
O_BECOME_REPH; i++) |
941 info[i].mask |= indic_plan->mask_array[RPHF]; | 1036 info[i].mask |= indic_plan->mask_array[RPHF]; |
942 | 1037 |
943 /* Pre-base */ | 1038 /* Pre-base */ |
944 mask = indic_plan->mask_array[HALF]; | 1039 mask = indic_plan->mask_array[HALF]; |
| 1040 if (!indic_plan->is_old_spec && |
| 1041 indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST) |
| 1042 mask |= indic_plan->mask_array[BLWF]; |
945 for (unsigned int i = start; i < base; i++) | 1043 for (unsigned int i = start; i < base; i++) |
946 info[i].mask |= mask; | 1044 info[i].mask |= mask; |
947 /* Base */ | 1045 /* Base */ |
948 mask = 0; | 1046 mask = 0; |
949 if (base < end) | 1047 if (base < end) |
950 info[base].mask |= mask; | 1048 info[base].mask |= mask; |
951 /* Post-base */ | 1049 /* Post-base */ |
952 mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_p
lan->mask_array[PSTF]; | 1050 mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_p
lan->mask_array[PSTF]; |
953 for (unsigned int i = base + 1; i < end; i++) | 1051 for (unsigned int i = base + 1; i < end; i++) |
954 info[i].mask |= mask; | 1052 info[i].mask |= mask; |
(...skipping 24 matching lines...) Expand all Loading... |
979 if (info[i ].indic_category() == OT_Ra && | 1077 if (info[i ].indic_category() == OT_Ra && |
980 info[i+1].indic_category() == OT_H && | 1078 info[i+1].indic_category() == OT_H && |
981 (i + 2 == base || | 1079 (i + 2 == base || |
982 info[i+2].indic_category() != OT_ZWJ)) | 1080 info[i+2].indic_category() != OT_ZWJ)) |
983 { | 1081 { |
984 info[i ].mask |= indic_plan->mask_array[BLWF]; | 1082 info[i ].mask |= indic_plan->mask_array[BLWF]; |
985 info[i+1].mask |= indic_plan->mask_array[BLWF]; | 1083 info[i+1].mask |= indic_plan->mask_array[BLWF]; |
986 } | 1084 } |
987 } | 1085 } |
988 | 1086 |
989 if (indic_plan->mask_array[PREF] && base + 2 < end) | 1087 unsigned int pref_len = indic_plan->config->pref_len; |
| 1088 if (indic_plan->mask_array[PREF] && base + pref_len < end) |
990 { | 1089 { |
| 1090 assert (1 <= pref_len && pref_len <= 2); |
991 /* Find a Halant,Ra sequence and mark it for pre-base reordering processing.
*/ | 1091 /* Find a Halant,Ra sequence and mark it for pre-base reordering processing.
*/ |
992 for (unsigned int i = base + 1; i + 1 < end; i++) { | 1092 for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) { |
993 hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint}; | 1093 hb_codepoint_t glyphs[2]; |
994 if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true
, face)) | 1094 for (unsigned int j = 0; j < pref_len; j++) |
| 1095 glyphs[j] = info[i + j].codepoint; |
| 1096 if (indic_plan->pref.would_substitute (glyphs, pref_len, face)) |
995 { | 1097 { |
996 » info[i++].mask |= indic_plan->mask_array[PREF]; | 1098 » for (unsigned int j = 0; j < pref_len; j++) |
997 » info[i++].mask |= indic_plan->mask_array[PREF]; | 1099 » info[i++].mask |= indic_plan->mask_array[PREF]; |
998 | 1100 |
999 /* Mark the subsequent stuff with 'cfar'. Used in Khmer. | 1101 /* Mark the subsequent stuff with 'cfar'. Used in Khmer. |
1000 * Read the feature spec. | 1102 * Read the feature spec. |
1001 * This allows distinguishing the following cases with MS Khmer fonts: | 1103 * This allows distinguishing the following cases with MS Khmer fonts: |
1002 * U+1784,U+17D2,U+179A,U+17D2,U+1782 | 1104 * U+1784,U+17D2,U+179A,U+17D2,U+1782 |
1003 * U+1784,U+17D2,U+1782,U+17D2,U+179A | 1105 * U+1784,U+17D2,U+1782,U+17D2,U+179A |
1004 */ | 1106 */ |
1005 » for (; i < end; i++) | 1107 » if (indic_plan->mask_array[CFAR]) |
1006 » info[i].mask |= indic_plan->mask_array[CFAR]; | 1108 » for (; i < end; i++) |
| 1109 » info[i].mask |= indic_plan->mask_array[CFAR]; |
1007 | 1110 |
1008 break; | 1111 break; |
1009 } | 1112 } |
1010 } | 1113 } |
1011 } | 1114 } |
1012 | 1115 |
1013 /* Apply ZWJ/ZWNJ effects */ | 1116 /* Apply ZWJ/ZWNJ effects */ |
1014 for (unsigned int i = start + 1; i < end; i++) | 1117 for (unsigned int i = start + 1; i < end; i++) |
1015 if (is_joiner (info[i])) { | 1118 if (is_joiner (info[i])) { |
1016 bool non_joiner = info[i].indic_category() == OT_ZWNJ; | 1119 bool non_joiner = info[i].indic_category() == OT_ZWNJ; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1067 initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan, | 1170 initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan, |
1068 hb_face_t *face, | 1171 hb_face_t *face, |
1069 hb_buffer_t *buffer, | 1172 hb_buffer_t *buffer, |
1070 unsigned int start, unsigned int end) | 1173 unsigned int start, unsigned int end) |
1071 { | 1174 { |
1072 /* We already inserted dotted-circles, so just call the standalone_cluster. */ | 1175 /* We already inserted dotted-circles, so just call the standalone_cluster. */ |
1073 initial_reordering_standalone_cluster (plan, face, buffer, start, end); | 1176 initial_reordering_standalone_cluster (plan, face, buffer, start, end); |
1074 } | 1177 } |
1075 | 1178 |
1076 static void | 1179 static void |
| 1180 initial_reordering_avagraha_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, |
| 1181 hb_face_t *face HB_UNUSED, |
| 1182 hb_buffer_t *buffer HB_UNUSED, |
| 1183 unsigned int start HB_UNUSED, unsigned int
end HB_UNUSED) |
| 1184 { |
| 1185 /* Nothing to do right now. If we ever switch to using the output |
| 1186 * buffer in the reordering process, we'd need to next_glyph() here. */ |
| 1187 } |
| 1188 |
| 1189 static void |
1077 initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, | 1190 initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, |
1078 hb_face_t *face HB_UNUSED, | 1191 hb_face_t *face HB_UNUSED, |
1079 hb_buffer_t *buffer HB_UNUSED, | 1192 hb_buffer_t *buffer HB_UNUSED, |
1080 unsigned int start HB_UNUSED, unsigned int
end HB_UNUSED) | 1193 unsigned int start HB_UNUSED, unsigned int
end HB_UNUSED) |
1081 { | 1194 { |
1082 /* Nothing to do right now. If we ever switch to using the output | 1195 /* Nothing to do right now. If we ever switch to using the output |
1083 * buffer in the reordering process, we'd need to next_glyph() here. */ | 1196 * buffer in the reordering process, we'd need to next_glyph() here. */ |
1084 } | 1197 } |
1085 | 1198 |
1086 | 1199 |
1087 static void | 1200 static void |
1088 initial_reordering_syllable (const hb_ot_shape_plan_t *plan, | 1201 initial_reordering_syllable (const hb_ot_shape_plan_t *plan, |
1089 hb_face_t *face, | 1202 hb_face_t *face, |
1090 hb_buffer_t *buffer, | 1203 hb_buffer_t *buffer, |
1091 unsigned int start, unsigned int end) | 1204 unsigned int start, unsigned int end) |
1092 { | 1205 { |
1093 syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllabl
e() & 0x0F); | 1206 syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllabl
e() & 0x0F); |
1094 switch (syllable_type) { | 1207 switch (syllable_type) { |
1095 case consonant_syllable: initial_reordering_consonant_syllable (plan, fac
e, buffer, start, end); return; | 1208 case consonant_syllable: initial_reordering_consonant_syllable (plan, fac
e, buffer, start, end); return; |
1096 case vowel_syllable: initial_reordering_vowel_syllable (plan, fac
e, buffer, start, end); return; | 1209 case vowel_syllable: initial_reordering_vowel_syllable (plan, fac
e, buffer, start, end); return; |
1097 case standalone_cluster: initial_reordering_standalone_cluster (plan, fac
e, buffer, start, end); return; | 1210 case standalone_cluster: initial_reordering_standalone_cluster (plan, fac
e, buffer, start, end); return; |
| 1211 case avagraha_cluster: initial_reordering_avagraha_cluster (plan, fac
e, buffer, start, end); return; |
1098 case broken_cluster: initial_reordering_broken_cluster (plan, fac
e, buffer, start, end); return; | 1212 case broken_cluster: initial_reordering_broken_cluster (plan, fac
e, buffer, start, end); return; |
1099 case non_indic_cluster: initial_reordering_non_indic_cluster (plan, fac
e, buffer, start, end); return; | 1213 case non_indic_cluster: initial_reordering_non_indic_cluster (plan, fac
e, buffer, start, end); return; |
1100 } | 1214 } |
1101 } | 1215 } |
1102 | 1216 |
1103 static inline void | 1217 static inline void |
1104 insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, | 1218 insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, |
1105 hb_font_t *font, | 1219 hb_font_t *font, |
1106 hb_buffer_t *buffer) | 1220 hb_buffer_t *buffer) |
1107 { | 1221 { |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1257 /* Now go see if there's actually any matras... */ | 1371 /* Now go see if there's actually any matras... */ |
1258 for (unsigned int i = new_pos; i > start; i--) | 1372 for (unsigned int i = new_pos; i > start; i--) |
1259 if (info[i - 1].indic_position () == POS_PRE_M) | 1373 if (info[i - 1].indic_position () == POS_PRE_M) |
1260 { | 1374 { |
1261 unsigned int old_pos = i - 1; | 1375 unsigned int old_pos = i - 1; |
1262 hb_glyph_info_t tmp = info[old_pos]; | 1376 hb_glyph_info_t tmp = info[old_pos]; |
1263 memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * siz
eof (info[0])); | 1377 memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * siz
eof (info[0])); |
1264 info[new_pos] = tmp; | 1378 info[new_pos] = tmp; |
1265 if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. *
/ | 1379 if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. *
/ |
1266 base--; | 1380 base--; |
| 1381 buffer->merge_clusters (new_pos, MIN (end, base + 1)); |
1267 new_pos--; | 1382 new_pos--; |
1268 } | 1383 } |
1269 buffer->merge_clusters (new_pos, MIN (end, base + 1)); | |
1270 } else { | 1384 } else { |
1271 for (unsigned int i = start; i < base; i++) | 1385 for (unsigned int i = start; i < base; i++) |
1272 if (info[i].indic_position () == POS_PRE_M) { | 1386 if (info[i].indic_position () == POS_PRE_M) { |
1273 buffer->merge_clusters (i, MIN (end, base + 1)); | 1387 buffer->merge_clusters (i, MIN (end, base + 1)); |
1274 break; | 1388 break; |
1275 } | 1389 } |
1276 } | 1390 } |
1277 } | 1391 } |
1278 | 1392 |
1279 | 1393 |
1280 /* o Reorder reph: | 1394 /* o Reorder reph: |
1281 * | 1395 * |
1282 * Reph’s original position is always at the beginning of the syllable, | 1396 * Reph’s original position is always at the beginning of the syllable, |
1283 * (i.e. it is not reordered at the character reordering stage). However, | 1397 * (i.e. it is not reordered at the character reordering stage). However, |
1284 * it will be reordered according to the basic-forms shaping results. | 1398 * it will be reordered according to the basic-forms shaping results. |
1285 * Possible positions for reph, depending on the script, are; after main, | 1399 * Possible positions for reph, depending on the script, are; after main, |
1286 * before post-base consonant forms, and after post-base consonant forms. | 1400 * before post-base consonant forms, and after post-base consonant forms. |
1287 */ | 1401 */ |
1288 | 1402 |
1289 /* If there's anything after the Ra that has the REPH pos, it ought to be hala
nt. | 1403 /* Two cases: |
1290 * Which means that the font has failed to ligate the Reph. In which case, we | 1404 * |
1291 * shouldn't move. */ | 1405 * - If repha is encoded as a sequence of characters (Ra,H or Ra,H,ZWJ), then |
| 1406 * we should only move it if the sequence ligated to the repha form. |
| 1407 * |
| 1408 * - If repha is encoded separately and in the logical position, we should onl
y |
| 1409 * move it if it did NOT ligate. If it ligated, it's probably the font tryi
ng |
| 1410 * to make it work without the reordering. |
| 1411 */ |
1292 if (start + 1 < end && | 1412 if (start + 1 < end && |
1293 info[start].indic_position() == POS_RA_TO_BECOME_REPH && | 1413 info[start].indic_position() == POS_RA_TO_BECOME_REPH && |
1294 info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH) | 1414 ((info[start].indic_category() == OT_Repha) ^ |
| 1415 _hb_glyph_info_ligated (&info[start]))) |
1295 { | 1416 { |
1296 unsigned int new_reph_pos; | 1417 unsigned int new_reph_pos; |
1297 reph_position_t reph_pos = indic_plan->config->reph_pos; | 1418 reph_position_t reph_pos = indic_plan->config->reph_pos; |
1298 | 1419 |
1299 /* XXX Figure out old behavior too */ | 1420 assert (reph_pos != REPH_POS_DONT_CARE); |
1300 | 1421 |
1301 /* 1. If reph should be positioned after post-base consonant forms, | 1422 /* 1. If reph should be positioned after post-base consonant forms, |
1302 * proceed to step 5. | 1423 * proceed to step 5. |
1303 */ | 1424 */ |
1304 if (reph_pos == REPH_POS_AFTER_POST) | 1425 if (reph_pos == REPH_POS_AFTER_POST) |
1305 { | 1426 { |
1306 goto reph_step_5; | 1427 goto reph_step_5; |
1307 } | 1428 } |
1308 | 1429 |
1309 /* 2. If the reph repositioning class is not after post-base: target | 1430 /* 2. If the reph repositioning class is not after post-base: target |
(...skipping 21 matching lines...) Expand all Loading... |
1331 } | 1452 } |
1332 } | 1453 } |
1333 | 1454 |
1334 /* 3. If reph should be repositioned after the main consonant: find th
e | 1455 /* 3. If reph should be repositioned after the main consonant: find th
e |
1335 * first consonant not ligated with main, or find the first | 1456 * first consonant not ligated with main, or find the first |
1336 * consonant that is not a potential pre-base reordering Ra. | 1457 * consonant that is not a potential pre-base reordering Ra. |
1337 */ | 1458 */ |
1338 if (reph_pos == REPH_POS_AFTER_MAIN) | 1459 if (reph_pos == REPH_POS_AFTER_MAIN) |
1339 { | 1460 { |
1340 new_reph_pos = base; | 1461 new_reph_pos = base; |
1341 /* XXX Skip potential pre-base reordering Ra. */ | |
1342 while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <
= POS_AFTER_MAIN) | 1462 while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <
= POS_AFTER_MAIN) |
1343 new_reph_pos++; | 1463 new_reph_pos++; |
1344 if (new_reph_pos < end) | 1464 if (new_reph_pos < end) |
1345 goto reph_move; | 1465 goto reph_move; |
1346 } | 1466 } |
1347 | 1467 |
1348 /* 4. If reph should be positioned before post-base consonant, find | 1468 /* 4. If reph should be positioned before post-base consonant, find |
1349 * first post-base classified consonant not ligated with main. If n
o | 1469 * first post-base classified consonant not ligated with main. If n
o |
1350 * consonant is found, the target position should be before the | 1470 * consonant is found, the target position should be before the |
1351 * first matra, syllable modifier sign or vedic sign. | 1471 * first matra, syllable modifier sign or vedic sign. |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1404 if (info[i].indic_category() == OT_M) { | 1524 if (info[i].indic_category() == OT_M) { |
1405 /* Ok, got it. */ | 1525 /* Ok, got it. */ |
1406 new_reph_pos--; | 1526 new_reph_pos--; |
1407 } | 1527 } |
1408 } | 1528 } |
1409 goto reph_move; | 1529 goto reph_move; |
1410 } | 1530 } |
1411 | 1531 |
1412 reph_move: | 1532 reph_move: |
1413 { | 1533 { |
1414 /* Yay, one big cluster! Merge before moving. */ | 1534 buffer->merge_clusters (start, new_reph_pos + 1); |
1415 buffer->merge_clusters (start, end); | |
1416 | 1535 |
1417 /* Move */ | 1536 /* Move */ |
1418 hb_glyph_info_t reph = info[start]; | 1537 hb_glyph_info_t reph = info[start]; |
1419 memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (
info[0])); | 1538 memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (
info[0])); |
1420 info[new_reph_pos] = reph; | 1539 info[new_reph_pos] = reph; |
1421 if (start < base && base <= new_reph_pos) | 1540 if (start < base && base <= new_reph_pos) |
1422 base--; | 1541 base--; |
1423 } | 1542 } |
1424 } | 1543 } |
1425 | 1544 |
1426 | 1545 |
1427 /* o Reorder pre-base reordering consonants: | 1546 /* o Reorder pre-base reordering consonants: |
1428 * | 1547 * |
1429 * If a pre-base reordering consonant is found, reorder it according to | 1548 * If a pre-base reordering consonant is found, reorder it according to |
1430 * the following rules: | 1549 * the following rules: |
1431 */ | 1550 */ |
1432 | 1551 |
1433 if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't b
e any pre-base reordering Ra. */ | 1552 if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't b
e any pre-base reordering Ra. */ |
1434 { | 1553 { |
| 1554 unsigned int pref_len = indic_plan->config->pref_len; |
1435 for (unsigned int i = base + 1; i < end; i++) | 1555 for (unsigned int i = base + 1; i < end; i++) |
1436 if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) | 1556 if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) |
1437 { | 1557 { |
1438 /* 1. Only reorder a glyph produced by substitution during applica
tion | 1558 /* 1. Only reorder a glyph produced by substitution during applica
tion |
1439 * of the <pref> feature. (Note that a font may shape a Ra cons
onant with | 1559 * of the <pref> feature. (Note that a font may shape a Ra cons
onant with |
1440 * the feature generally but block it in certain contexts.) | 1560 * the feature generally but block it in certain contexts.) |
1441 */ | 1561 */ |
1442 » if (i + 1 == end || (info[i + 1].mask & indic_plan->mask_array[PREF]) ==
0) | 1562 /* Note: We just check that something got substituted. We don't check t
hat |
| 1563 » * the <pref> feature actually did it... |
| 1564 » * |
| 1565 » * If pref len is longer than one, then only reorder if it ligated. If |
| 1566 » * pref len is one, only reorder if it didn't ligate with other things.
*/ |
| 1567 » if (_hb_glyph_info_substituted (&info[i]) && |
| 1568 » ((pref_len == 1) ^ _hb_glyph_info_ligated (&info[i]))) |
1443 { | 1569 { |
1444 /* | 1570 /* |
1445 * 2. Try to find a target position the same way as for pre-base
matra. | 1571 * 2. Try to find a target position the same way as for pre-base
matra. |
1446 * If it is found, reorder pre-base consonant glyph. | 1572 * If it is found, reorder pre-base consonant glyph. |
1447 * | 1573 * |
1448 * 3. If position is not found, reorder immediately before main | 1574 * 3. If position is not found, reorder immediately before main |
1449 * consonant. | 1575 * consonant. |
1450 */ | 1576 */ |
1451 | 1577 |
1452 unsigned int new_pos = base; | 1578 unsigned int new_pos = base; |
1453 /* Malayalam / Tamil do not have "half" forms or explicit virama forms
. | 1579 /* Malayalam / Tamil do not have "half" forms or explicit virama forms
. |
1454 * The glyphs formed by 'half' are Chillus or ligated explicit viramas
. | 1580 * The glyphs formed by 'half' are Chillus or ligated explicit viramas
. |
1455 * We want to position matra after them. | 1581 * We want to position matra after them. |
1456 */ | 1582 */ |
1457 if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.scrip
t != HB_SCRIPT_TAMIL) | 1583 if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.scrip
t != HB_SCRIPT_TAMIL) |
1458 { | 1584 { |
1459 while (new_pos > start && | 1585 while (new_pos > start && |
1460 !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_
FLAGS))) | 1586 !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_
FLAGS))) |
1461 new_pos--; | 1587 new_pos--; |
1462 | 1588 |
1463 » /* In Khmer coeng model, a V,Ra can go *after* matras. If it goes a
fter a | 1589 » /* In Khmer coeng model, a H,Ra can go *after* matras. If it goes a
fter a |
1464 * split matra, it should be reordered to *before* the left part of
such matra. */ | 1590 * split matra, it should be reordered to *before* the left part of
such matra. */ |
1465 if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) | 1591 if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) |
1466 { | 1592 { |
1467 unsigned int old_pos = i; | 1593 unsigned int old_pos = i; |
1468 for (unsigned int i = base + 1; i < old_pos; i++) | 1594 for (unsigned int i = base + 1; i < old_pos; i++) |
1469 if (info[i].indic_category() == OT_M) | 1595 if (info[i].indic_category() == OT_M) |
1470 { | 1596 { |
1471 new_pos--; | 1597 new_pos--; |
1472 break; | 1598 break; |
1473 } | 1599 } |
(...skipping 29 matching lines...) Expand all Loading... |
1503 !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & | 1629 !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & |
1504 FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATE
GORY_NON_SPACING_MARK)))) | 1630 FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATE
GORY_NON_SPACING_MARK)))) |
1505 info[start].mask |= indic_plan->mask_array[INIT]; | 1631 info[start].mask |= indic_plan->mask_array[INIT]; |
1506 | 1632 |
1507 | 1633 |
1508 /* | 1634 /* |
1509 * Finish off the clusters and go home! | 1635 * Finish off the clusters and go home! |
1510 */ | 1636 */ |
1511 if (hb_options ().uniscribe_bug_compatible) | 1637 if (hb_options ().uniscribe_bug_compatible) |
1512 { | 1638 { |
1513 /* Uniscribe merges the entire cluster. | 1639 switch ((hb_tag_t) plan->props.script) |
1514 * This means, half forms are submerged into the main consonants cluster. | 1640 { |
1515 * This is unnecessary, and makes cursor positioning harder, but that's what | 1641 case HB_SCRIPT_TAMIL: |
1516 * Uniscribe does. */ | 1642 case HB_SCRIPT_SINHALA: |
1517 buffer->merge_clusters (start, end); | 1643 break; |
| 1644 |
| 1645 default: |
| 1646 » /* Uniscribe merges the entire cluster... Except for Tamil & Sinhala. |
| 1647 » * This means, half forms are submerged into the main consonants cluster
. |
| 1648 » * This is unnecessary, and makes cursor positioning harder, but that's
what |
| 1649 » * Uniscribe does. */ |
| 1650 » buffer->merge_clusters (start, end); |
| 1651 » break; |
| 1652 } |
1518 } | 1653 } |
1519 } | 1654 } |
1520 | 1655 |
1521 | 1656 |
1522 static void | 1657 static void |
1523 final_reordering (const hb_ot_shape_plan_t *plan, | 1658 final_reordering (const hb_ot_shape_plan_t *plan, |
1524 hb_font_t *font HB_UNUSED, | 1659 hb_font_t *font HB_UNUSED, |
1525 hb_buffer_t *buffer) | 1660 hb_buffer_t *buffer) |
1526 { | 1661 { |
1527 unsigned int count = buffer->len; | 1662 unsigned int count = buffer->len; |
1528 if (unlikely (!count)) return; | 1663 if (unlikely (!count)) return; |
1529 | 1664 |
1530 hb_glyph_info_t *info = buffer->info; | 1665 hb_glyph_info_t *info = buffer->info; |
1531 unsigned int last = 0; | 1666 unsigned int last = 0; |
1532 unsigned int last_syllable = info[0].syllable(); | 1667 unsigned int last_syllable = info[0].syllable(); |
1533 for (unsigned int i = 1; i < count; i++) | 1668 for (unsigned int i = 1; i < count; i++) |
1534 if (last_syllable != info[i].syllable()) { | 1669 if (last_syllable != info[i].syllable()) { |
1535 final_reordering_syllable (plan, buffer, last, i); | 1670 final_reordering_syllable (plan, buffer, last, i); |
1536 last = i; | 1671 last = i; |
1537 last_syllable = info[last].syllable(); | 1672 last_syllable = info[last].syllable(); |
1538 } | 1673 } |
1539 final_reordering_syllable (plan, buffer, last, count); | 1674 final_reordering_syllable (plan, buffer, last, count); |
1540 | 1675 |
1541 /* Zero syllables now... */ | |
1542 for (unsigned int i = 0; i < count; i++) | |
1543 info[i].syllable() = 0; | |
1544 | |
1545 HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); | 1676 HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); |
1546 HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); | 1677 HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); |
1547 } | 1678 } |
1548 | 1679 |
1549 | 1680 |
| 1681 static void |
| 1682 clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, |
| 1683 hb_font_t *font HB_UNUSED, |
| 1684 hb_buffer_t *buffer) |
| 1685 { |
| 1686 hb_glyph_info_t *info = buffer->info; |
| 1687 unsigned int count = buffer->len; |
| 1688 for (unsigned int i = 0; i < count; i++) |
| 1689 info[i].syllable() = 0; |
| 1690 } |
| 1691 |
| 1692 |
1550 static hb_ot_shape_normalization_mode_t | 1693 static hb_ot_shape_normalization_mode_t |
1551 normalization_preference_indic (const hb_segment_properties_t *props HB_UNUSED) | 1694 normalization_preference_indic (const hb_segment_properties_t *props HB_UNUSED) |
1552 { | 1695 { |
1553 return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT; | 1696 return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT; |
1554 } | 1697 } |
1555 | 1698 |
1556 static bool | 1699 static bool |
1557 decompose_indic (const hb_ot_shape_normalize_context_t *c, | 1700 decompose_indic (const hb_ot_shape_normalize_context_t *c, |
1558 hb_codepoint_t ab, | 1701 hb_codepoint_t ab, |
1559 hb_codepoint_t *a, | 1702 hb_codepoint_t *a, |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1619 * | 1762 * |
1620 * http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shapi
ng | 1763 * http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shapi
ng |
1621 */ | 1764 */ |
1622 | 1765 |
1623 const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan-
>data; | 1766 const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan-
>data; |
1624 | 1767 |
1625 hb_codepoint_t glyph; | 1768 hb_codepoint_t glyph; |
1626 | 1769 |
1627 if (hb_options ().uniscribe_bug_compatible || | 1770 if (hb_options ().uniscribe_bug_compatible || |
1628 (c->font->get_glyph (ab, 0, &glyph) && | 1771 (c->font->get_glyph (ab, 0, &glyph) && |
1629 » indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face))) | 1772 » indic_plan->pstf.would_substitute (&glyph, 1, c->font->face))) |
1630 { | 1773 { |
1631 /* Ok, safe to use Uniscribe-style decomposition. */ | 1774 /* Ok, safe to use Uniscribe-style decomposition. */ |
1632 *a = 0x0DD9; | 1775 *a = 0x0DD9; |
1633 *b = ab; | 1776 *b = ab; |
1634 return true; | 1777 return true; |
1635 } | 1778 } |
1636 } | 1779 } |
1637 | 1780 |
1638 return c->unicode->decompose (ab, a, b); | 1781 return c->unicode->decompose (ab, a, b); |
1639 } | 1782 } |
(...skipping 23 matching lines...) Expand all Loading... |
1663 data_create_indic, | 1806 data_create_indic, |
1664 data_destroy_indic, | 1807 data_destroy_indic, |
1665 NULL, /* preprocess_text */ | 1808 NULL, /* preprocess_text */ |
1666 normalization_preference_indic, | 1809 normalization_preference_indic, |
1667 decompose_indic, | 1810 decompose_indic, |
1668 compose_indic, | 1811 compose_indic, |
1669 setup_masks_indic, | 1812 setup_masks_indic, |
1670 HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, | 1813 HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, |
1671 false, /* fallback_position */ | 1814 false, /* fallback_position */ |
1672 }; | 1815 }; |
OLD | NEW |