Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc

Issue 70193010: Update harfbuzz-ng to 0.9.24 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698