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

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

Issue 12438036: Update harfbuzz-ng to 0.9.14 from 0.9.10 (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 7 years, 8 months 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.
11 * 11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE. 16 * DAMAGE.
17 * 17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 * 23 *
24 * Google Author(s): Behdad Esfahbod 24 * Google Author(s): Behdad Esfahbod
25 */ 25 */
26 26
27 #include "hb-ot-shape-complex-indic-private.hh" 27 #include "hb-ot-shape-complex-indic-private.hh"
28 #include "hb-ot-layout-private.hh" 28 #include "hb-ot-layout-private.hh"
29 29
30 /* buffer var allocations */
31 #define indic_category() complex_var_u8_0() /* indic_category_t */
32 #define indic_position() complex_var_u8_1() /* indic_position_t */
33
30 34
31 /* 35 /*
32 * Global Indic shaper options. 36 * Indic shaper.
33 */ 37 */
34 38
35 struct indic_options_t 39
36 { 40 #define IN_HALF_BLOCK(u, Base) (((u) & ~0x7F) == (Base))
37 int initialized : 1; 41
38 int uniscribe_bug_compatible : 1; 42 #define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900))
43 #define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980))
44 #define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00))
45 #define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80))
46 #define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00))
47 #define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80))
48 #define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00))
49 #define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80))
50 #define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00))
51 #define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80))
52 #define IS_KHMR(u) (IN_HALF_BLOCK (u, 0x1780))
53
54
55 #define MATRA_POS_LEFT(u)» POS_PRE_M
56 #define MATRA_POS_RIGHT(u)» ( \
57 » » » » IS_DEVA(u) ? POS_AFTER_SUB : \
58 » » » » IS_BENG(u) ? POS_AFTER_POST : \
59 » » » » IS_GURU(u) ? POS_AFTER_POST : \
60 » » » » IS_GUJR(u) ? POS_AFTER_POST : \
61 » » » » IS_ORYA(u) ? POS_AFTER_POST : \
62 » » » » IS_TAML(u) ? POS_AFTER_POST : \
63 » » » » IS_TELU(u) ? (u <= 0x0C42 ? POS_BEFORE_SUB : P OS_AFTER_SUB) : \
64 » » » » IS_KNDA(u) ? (u < 0x0CC3 || u > 0xCD6 ? POS_BE FORE_SUB : POS_AFTER_SUB) : \
65 » » » » IS_MLYM(u) ? POS_AFTER_POST : \
66 » » » » IS_SINH(u) ? POS_AFTER_SUB : \
67 » » » » IS_KHMR(u) ? POS_AFTER_POST : \
68 » » » » /*default*/ POS_AFTER_SUB \
69 » » » » )
70 #define MATRA_POS_TOP(u)» ( /* BENG and MLYM don't have top matras. */ \
71 » » » » IS_DEVA(u) ? POS_AFTER_SUB : \
72 » » » » IS_GURU(u) ? POS_AFTER_POST : /* Deviate from spec */ \
73 » » » » IS_GUJR(u) ? POS_AFTER_SUB : \
74 » » » » IS_ORYA(u) ? POS_AFTER_MAIN : \
75 » » » » IS_TAML(u) ? POS_AFTER_SUB : \
76 » » » » IS_TELU(u) ? POS_BEFORE_SUB : \
77 » » » » IS_KNDA(u) ? POS_BEFORE_SUB : \
78 » » » » IS_SINH(u) ? POS_AFTER_SUB : \
79 » » » » IS_KHMR(u) ? POS_AFTER_POST : \
80 » » » » /*default*/ POS_AFTER_SUB \
81 » » » » )
82 #define MATRA_POS_BOTTOM(u)» ( \
83 » » » » IS_DEVA(u) ? POS_AFTER_SUB : \
84 » » » » IS_BENG(u) ? POS_AFTER_SUB : \
85 » » » » IS_GURU(u) ? POS_AFTER_POST : \
86 » » » » IS_GUJR(u) ? POS_AFTER_POST : \
87 » » » » IS_ORYA(u) ? POS_AFTER_SUB : \
88 » » » » IS_TAML(u) ? POS_AFTER_POST : \
89 » » » » IS_TELU(u) ? POS_BEFORE_SUB : \
90 » » » » IS_KNDA(u) ? POS_BEFORE_SUB : \
91 » » » » IS_MLYM(u) ? POS_AFTER_POST : \
92 » » » » IS_SINH(u) ? POS_AFTER_SUB : \
93 » » » » IS_KHMR(u) ? POS_AFTER_POST : \
94 » » » » /*default*/ POS_AFTER_SUB \
95 » » » » )
96
97 static inline indic_position_t
98 matra_position (hb_codepoint_t u, indic_position_t side)
99 {
100 switch ((int) side)
101 {
102 case POS_PRE_C:» return MATRA_POS_LEFT (u);
103 case POS_POST_C:» return MATRA_POS_RIGHT (u);
104 case POS_ABOVE_C:» return MATRA_POS_TOP (u);
105 case POS_BELOW_C:» return MATRA_POS_BOTTOM (u);
106 };
107 return side;
108 }
109
110 /* XXX
111 * This is a hack for now. We should move this data into the main Indic table.
112 * Or completely remove it and just check in the tables.
113 */
114 static const hb_codepoint_t ra_chars[] = {
115 0x0930, /* Devanagari */
116 0x09B0, /* Bengali */
117 0x09F0, /* Bengali */
118 0x0A30, /* Gurmukhi */» /* No Reph */
119 0x0AB0, /* Gujarati */
120 0x0B30, /* Oriya */
121 0x0BB0, /* Tamil */» » /* No Reph */
122 0x0C30, /* Telugu */» » /* Reph formed only with ZWJ */
123 0x0CB0, /* Kannada */
124 0x0D30, /* Malayalam */» /* No Reph, Logical Repha */
125
126 0x0DBB, /* Sinhala */»» /* Reph formed only with ZWJ */
127
128 0x179A, /* Khmer */» » /* No Reph, Visual Repha */
39 }; 129 };
40 130
41 union indic_options_union_t { 131 static inline indic_position_t
42 int i; 132 consonant_position (hb_codepoint_t u)
43 indic_options_t opts; 133 {
44 }; 134 if ((u & ~0x007F) == 0x1780)
45 ASSERT_STATIC (sizeof (int) == sizeof (indic_options_union_t)); 135 return POS_BELOW_C; /* In Khmer coeng model, post and below forms should not be reordered. */
46 136 return POS_BASE_C; /* Will recategorize later based on font lookups. */
47 static indic_options_union_t 137 }
48 indic_options_init (void) 138
49 { 139 static inline bool
50 indic_options_union_t u; 140 is_ra (hb_codepoint_t u)
51 u.i = 0; 141 {
52 u.opts.initialized = 1; 142 for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++)
53 143 if (u == ra_chars[i])
54 char *c = getenv ("HB_OT_INDIC_OPTIONS"); 144 return true;
55 u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible"); 145 return false;
56 146 }
57 return u; 147
58 } 148 static inline bool
59 149 is_one_of (const hb_glyph_info_t &info, unsigned int flags)
60 static inline indic_options_t 150 {
61 indic_options (void) 151 /* If it ligated, all bets are off. */
62 { 152 if (is_a_ligature (info)) return false;
63 static indic_options_union_t options; 153 return !!(FLAG (info.indic_category()) & flags);
64 154 }
65 if (unlikely (!options.i)) { 155
66 /* This is idempotent and threadsafe. */ 156 #define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
67 options = indic_options_init (); 157 static inline bool
68 } 158 is_joiner (const hb_glyph_info_t &info)
69 159 {
70 return options.opts; 160 return is_one_of (info, JOINER_FLAGS);
71 } 161 }
162
163 /* Note:
164 *
165 * 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
167 * 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))
169 static inline bool
170 is_consonant (const hb_glyph_info_t &info)
171 {
172 return is_one_of (info, CONSONANT_FLAGS);
173 }
174
175 #define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng))
176 static inline bool
177 is_halant_or_coeng (const hb_glyph_info_t &info)
178 {
179 return is_one_of (info, HALANT_OR_COENG_FLAGS);
180 }
181
182 static inline void
183 set_indic_properties (hb_glyph_info_t &info)
184 {
185 hb_codepoint_t u = info.codepoint;
186 unsigned int type = hb_indic_get_categories (u);
187 indic_category_t cat = (indic_category_t) (type & 0x7F);
188 indic_position_t pos = (indic_position_t) (type >> 8);
189
190
191 /*
192 * Re-assign category
193 */
194
195
196 /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe
197 * treats U+0951..U+0952 all as OT_VD.
198 * TESTS:
199 * U+092E,U+0947,U+0952
200 * U+092E,U+0952,U+0947
201 * U+092E,U+0947,U+0951
202 * U+092E,U+0951,U+0947
203 * */
204 if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0951, 0x0954)))
205 cat = OT_VD;
206
207 if (unlikely (u == 0x17D1))
208 cat = OT_X;
209 if (cat == OT_X &&
210 unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CB, 0x17D3))) /* Khmer Vario us signs */
211 {
212 /* These are like Top Matras. */
213 cat = OT_M;
214 pos = POS_ABOVE_C;
215 }
216 if (u == 0x17C6) /* Khmer Bindu doesn't like to be repositioned. */
217 cat = OT_N;
218
219 if (unlikely (u == 0x17D2)) cat = OT_Coeng; /* Khmer coeng */
220 else if (unlikely (u == 0x200C)) cat = OT_ZWNJ;
221 else if (unlikely (u == 0x200D)) cat = OT_ZWJ;
222 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. */
224
225 if (cat == OT_Repha) {
226 /* 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)
228 * - The ones that are GenCat=Lo is encoded logically, ie. beginning of syll able. (eg. Malayalam)
229 *
230 * We recategorize the first kind to look like a Nukta and attached to the b ase directly.
231 */
232 if (_hb_glyph_info_get_general_category (&info) == HB_UNICODE_GENERAL_CATEGO RY_NON_SPACING_MARK)
233 cat = OT_N;
234 }
235
236
237
238 /*
239 * Re-assign position.
240 */
241
242 if ((FLAG (cat) & CONSONANT_FLAGS))
243 {
244 pos = consonant_position (u);
245 if (is_ra (u))
246 cat = OT_Ra;
247 }
248 else if (cat == OT_M)
249 {
250 pos = matra_position (u, pos);
251 }
252 else if (cat == OT_SM || cat == OT_VD)
253 {
254 pos = POS_SMVD;
255 }
256
257 if (unlikely (u == 0x0B01)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */
258
259
260
261 info.indic_category() = cat;
262 info.indic_position() = pos;
263 }
264
265 /*
266 * Things above this line should ideally be moved to the Indic table itself.
267 */
72 268
73 269
74 /* 270 /*
75 * Indic configurations. Note that we do not want to keep every single script-s pecific 271 * Indic configurations. Note that we do not want to keep every single script-s pecific
76 * behavior in these tables necessarily. This should mainly be used for per-scr ipt 272 * behavior in these tables necessarily. This should mainly be used for per-scr ipt
77 * properties that are cheaper keeping here, than in the code. Ie. if, say, one and 273 * properties that are cheaper keeping here, than in the code. Ie. if, say, one and
78 * only one script has an exception, that one script can be if'ed directly in th e code, 274 * only one script has an exception, that one script can be if'ed directly in th e code,
79 * instead of adding a new flag in these structs. 275 * instead of adding a new flag in these structs.
80 */ 276 */
81 277
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 {HB_SCRIPT_BENGALI, true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MO DE_IMPLICIT}, 312 {HB_SCRIPT_BENGALI, true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MO DE_IMPLICIT},
117 {HB_SCRIPT_GURMUKHI, true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MO DE_IMPLICIT}, 313 {HB_SCRIPT_GURMUKHI, true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MO DE_IMPLICIT},
118 {HB_SCRIPT_GUJARATI, true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MO DE_IMPLICIT}, 314 {HB_SCRIPT_GUJARATI, true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MO DE_IMPLICIT},
119 {HB_SCRIPT_ORIYA, true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MO DE_IMPLICIT}, 315 {HB_SCRIPT_ORIYA, true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MO DE_IMPLICIT},
120 {HB_SCRIPT_TAMIL, true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MO DE_IMPLICIT}, 316 {HB_SCRIPT_TAMIL, true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MO DE_IMPLICIT},
121 {HB_SCRIPT_TELUGU, true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MO DE_EXPLICIT}, 317 {HB_SCRIPT_TELUGU, true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MO DE_EXPLICIT},
122 {HB_SCRIPT_KANNADA, true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MO DE_IMPLICIT}, 318 {HB_SCRIPT_KANNADA, true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MO DE_IMPLICIT},
123 {HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MO DE_LOG_REPHA}, 319 {HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MO DE_LOG_REPHA},
124 {HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MO DE_EXPLICIT}, 320 {HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MO DE_EXPLICIT},
125 {HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT, REPH_MO DE_VIS_REPHA}, 321 {HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT, REPH_MO DE_VIS_REPHA},
126 /* Myanmar does not have the "old_indic" behavior, even though it has a "new" tag. */
127 {HB_SCRIPT_MYANMAR, false,0x1039,BASE_POS_LAST, REPH_POS_DEFAULT, REPH_MO DE_EXPLICIT},
128 }; 322 };
129 323
130 324
131 325
132 /* 326 /*
133 * Indic shaper. 327 * Indic shaper.
134 */ 328 */
135 329
136 struct feature_list_t { 330 struct feature_list_t {
137 hb_tag_t tag; 331 hb_tag_t tag;
138 hb_bool_t is_global; 332 hb_ot_map_feature_flags_t flags;
139 }; 333 };
140 334
141 static const feature_list_t 335 static const feature_list_t
142 indic_features[] = 336 indic_features[] =
143 { 337 {
144 /* 338 /*
145 * Basic features. 339 * Basic features.
146 * These features are applied in order, one at a time, after initial_reorderin g. 340 * These features are applied in order, one at a time, after initial_reorderin g.
147 */ 341 */
148 {HB_TAG('n','u','k','t'), true}, 342 {HB_TAG('n','u','k','t'), F_GLOBAL},
149 {HB_TAG('a','k','h','n'), true}, 343 {HB_TAG('a','k','h','n'), F_GLOBAL},
150 {HB_TAG('r','p','h','f'), false}, 344 {HB_TAG('r','p','h','f'), F_NONE},
151 {HB_TAG('r','k','r','f'), true}, 345 {HB_TAG('r','k','r','f'), F_GLOBAL},
152 {HB_TAG('p','r','e','f'), false}, 346 {HB_TAG('p','r','e','f'), F_NONE},
153 {HB_TAG('h','a','l','f'), false}, 347 {HB_TAG('b','l','w','f'), F_NONE},
154 {HB_TAG('b','l','w','f'), false}, 348 {HB_TAG('h','a','l','f'), F_NONE},
155 {HB_TAG('a','b','v','f'), false}, 349 {HB_TAG('a','b','v','f'), F_NONE},
156 {HB_TAG('p','s','t','f'), false}, 350 {HB_TAG('p','s','t','f'), F_NONE},
157 {HB_TAG('c','f','a','r'), false}, 351 {HB_TAG('c','f','a','r'), F_NONE},
158 {HB_TAG('c','j','c','t'), true}, 352 {HB_TAG('v','a','t','u'), F_GLOBAL},
159 {HB_TAG('v','a','t','u'), true}, 353 {HB_TAG('c','j','c','t'), F_GLOBAL},
160 /* 354 /*
161 * Other features. 355 * Other features.
162 * These features are applied all at once, after final_reordering. 356 * These features are applied all at once, after final_reordering.
163 */ 357 */
164 {HB_TAG('i','n','i','t'), false}, 358 {HB_TAG('i','n','i','t'), F_NONE},
165 {HB_TAG('p','r','e','s'), true}, 359 {HB_TAG('p','r','e','s'), F_GLOBAL},
166 {HB_TAG('a','b','v','s'), true}, 360 {HB_TAG('a','b','v','s'), F_GLOBAL},
167 {HB_TAG('b','l','w','s'), true}, 361 {HB_TAG('b','l','w','s'), F_GLOBAL},
168 {HB_TAG('p','s','t','s'), true}, 362 {HB_TAG('p','s','t','s'), F_GLOBAL},
169 {HB_TAG('h','a','l','n'), true}, 363 {HB_TAG('h','a','l','n'), F_GLOBAL},
170 /* Positioning features, though we don't care about the types. */ 364 /* Positioning features, though we don't care about the types. */
171 {HB_TAG('d','i','s','t'), true}, 365 {HB_TAG('d','i','s','t'), F_GLOBAL},
172 {HB_TAG('a','b','v','m'), true}, 366 {HB_TAG('a','b','v','m'), F_GLOBAL},
173 {HB_TAG('b','l','w','m'), true}, 367 {HB_TAG('b','l','w','m'), F_GLOBAL},
174 }; 368 };
175 369
176 /* 370 /*
177 * Must be in the same order as the indic_features array. 371 * Must be in the same order as the indic_features array.
178 */ 372 */
179 enum { 373 enum {
180 _NUKT, 374 _NUKT,
181 _AKHN, 375 _AKHN,
182 RPHF, 376 RPHF,
183 _RKRF, 377 _RKRF,
184 PREF, 378 PREF,
379 BLWF,
185 HALF, 380 HALF,
186 BLWF,
187 ABVF, 381 ABVF,
188 PSTF, 382 PSTF,
189 CFAR, 383 CFAR,
384 _VATU,
190 _CJCT, 385 _CJCT,
191 _VATU,
192 386
193 INIT, 387 INIT,
194 _PRES, 388 _PRES,
195 _ABVS, 389 _ABVS,
196 _BLWS, 390 _BLWS,
197 _PSTS, 391 _PSTS,
198 _HALN, 392 _HALN,
199 _DIST, 393 _DIST,
200 _ABVM, 394 _ABVM,
201 _BLWM, 395 _BLWM,
(...skipping 16 matching lines...) Expand all
218 hb_buffer_t *buffer); 412 hb_buffer_t *buffer);
219 413
220 static void 414 static void
221 collect_features_indic (hb_ot_shape_planner_t *plan) 415 collect_features_indic (hb_ot_shape_planner_t *plan)
222 { 416 {
223 hb_ot_map_builder_t *map = &plan->map; 417 hb_ot_map_builder_t *map = &plan->map;
224 418
225 /* Do this before any lookups have been applied. */ 419 /* Do this before any lookups have been applied. */
226 map->add_gsub_pause (setup_syllables); 420 map->add_gsub_pause (setup_syllables);
227 421
228 map->add_bool_feature (HB_TAG('l','o','c','l')); 422 map->add_global_bool_feature (HB_TAG('l','o','c','l'));
229 /* The Indic specs do not require ccmp, but we apply it here since if 423 /* The Indic specs do not require ccmp, but we apply it here since if
230 * there is a use of it, it's typically at the beginning. */ 424 * there is a use of it, it's typically at the beginning. */
231 map->add_bool_feature (HB_TAG('c','c','m','p')); 425 map->add_global_bool_feature (HB_TAG('c','c','m','p'));
232 426
233 427
234 unsigned int i = 0; 428 unsigned int i = 0;
235 map->add_gsub_pause (initial_reordering); 429 map->add_gsub_pause (initial_reordering);
236 for (; i < INDIC_BASIC_FEATURES; i++) { 430 for (; i < INDIC_BASIC_FEATURES; i++) {
237 map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); 431 map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANU AL_ZWJ);
238 map->add_gsub_pause (NULL); 432 map->add_gsub_pause (NULL);
239 } 433 }
240 map->add_gsub_pause (final_reordering); 434 map->add_gsub_pause (final_reordering);
241 for (; i < INDIC_NUM_FEATURES; i++) { 435 for (; i < INDIC_NUM_FEATURES; i++) {
242 map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); 436 map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANU AL_ZWJ);
243 } 437 }
244 } 438 }
245 439
246 static void 440 static void
247 override_features_indic (hb_ot_shape_planner_t *plan) 441 override_features_indic (hb_ot_shape_planner_t *plan)
248 { 442 {
249 /* Uniscribe does not apply 'kern'. */ 443 /* Uniscribe does not apply 'kern'. */
250 if (indic_options ().uniscribe_bug_compatible) 444 if (hb_options ().uniscribe_bug_compatible)
251 plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true); 445 plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
252 446
253 plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true); 447 plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
254 } 448 }
255 449
256 450
257 struct would_substitute_feature_t 451 struct would_substitute_feature_t
258 { 452 {
259 inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag) 453 inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag)
260 { 454 {
261 map->get_stage_lookups (0/*GSUB*/, 455 map->get_stage_lookups (0/*GSUB*/,
262 map->get_feature_stage (0/*GSUB*/, feature_tag), 456 map->get_feature_stage (0/*GSUB*/, feature_tag),
263 &lookups, &count); 457 &lookups, &count);
264 } 458 }
265 459
266 inline bool would_substitute (hb_codepoint_t *glyphs, 460 inline bool would_substitute (const hb_codepoint_t *glyphs,
267 » » » » unsigned int glyphs_count, 461 » » » » unsigned int glyphs_count,
268 » » » » bool zero_context, 462 » » » » bool zero_context,
269 » » » » hb_face_t *face) const 463 » » » » hb_face_t *face) const
270 { 464 {
271 for (unsigned int i = 0; i < count; i++) 465 for (unsigned int i = 0; i < count; i++)
272 if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, gly phs, glyphs_count, zero_context)) 466 if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, gly phs, glyphs_count, zero_context))
273 return true; 467 return true;
274 return false; 468 return false;
275 } 469 }
276 470
277 private: 471 private:
278 const hb_ot_map_t::lookup_map_t *lookups; 472 const hb_ot_map_t::lookup_map_t *lookups;
279 unsigned int count; 473 unsigned int count;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 525
332 indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chos en_script[0] & 0x000000FF) != '2'); 526 indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chos en_script[0] & 0x000000FF) != '2');
333 indic_plan->virama_glyph = (hb_codepoint_t) -1; 527 indic_plan->virama_glyph = (hb_codepoint_t) -1;
334 528
335 indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f')); 529 indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'));
336 indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f')); 530 indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'));
337 indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f')); 531 indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'));
338 indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f')); 532 indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'));
339 533
340 for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) 534 for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
341 indic_plan->mask_array[i] = indic_features[i].is_global ? 0 : plan->map.get_ 1_mask (indic_features[i].tag); 535 indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ?
536 » » » » 0 : plan->map.get_1_mask (indic_features[i].tag );
342 537
343 return indic_plan; 538 return indic_plan;
344 } 539 }
345 540
346 static void 541 static void
347 data_destroy_indic (void *data) 542 data_destroy_indic (void *data)
348 { 543 {
349 free (data); 544 free (data);
350 } 545 }
351 546
352 static indic_position_t 547 static indic_position_t
353 consonant_position_from_face (const indic_shape_plan_t *indic_plan, 548 consonant_position_from_face (const indic_shape_plan_t *indic_plan,
354 » » » hb_codepoint_t *glyphs, unsigned int glyphs_len, 549 » » » const hb_codepoint_t glyphs[2],
355 » » » hb_face_t *face) 550 » » » hb_face_t *face)
356 { 551 {
552 /* For old-spec, the order of glyphs is Consonant,Virama,
553 * whereas for new-spec, it's Virama,Consonant. However,
554 * some broken fonts (like Free Sans) simply copied lookups
555 * from old-spec to new-spec without modification.
556 * And oddly enough, Uniscribe seems to respect those lookups.
557 * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds
558 * base at 0. The font however, only has lookups matching
559 * 930,94D in 'blwf', not the expected 94D,930 (with new-spec
560 * table). As such, we simply match both sequences. Seems
561 * to work. */
357 bool zero_context = indic_plan->is_old_spec ? false : true; 562 bool zero_context = indic_plan->is_old_spec ? false : true;
358 if (indic_plan->pref.would_substitute (glyphs, glyphs_len, zero_context, face) ) return POS_BELOW_C; 563 hb_codepoint_t glyphs_r[2] = {glyphs[1], glyphs[0]};
359 if (indic_plan->blwf.would_substitute (glyphs, glyphs_len, zero_context, face) ) return POS_BELOW_C; 564 if (indic_plan->pref.would_substitute (glyphs , 2, zero_context, face) ||
360 if (indic_plan->pstf.would_substitute (glyphs, glyphs_len, zero_context, face) ) return POS_POST_C; 565 indic_plan->pref.would_substitute (glyphs_r, 2, zero_context, face))
566 return POS_POST_C;
567 if (indic_plan->blwf.would_substitute (glyphs , 2, zero_context, face) ||
568 indic_plan->blwf.would_substitute (glyphs_r, 2, zero_context, face))
569 return POS_BELOW_C;
570 if (indic_plan->pstf.would_substitute (glyphs , 2, zero_context, face) ||
571 indic_plan->pstf.would_substitute (glyphs_r, 2, zero_context, face))
572 return POS_POST_C;
361 return POS_BASE_C; 573 return POS_BASE_C;
362 } 574 }
363 575
364 576
365 enum syllable_type_t { 577 enum syllable_type_t {
366 consonant_syllable, 578 consonant_syllable,
367 vowel_syllable, 579 vowel_syllable,
368 standalone_cluster, 580 standalone_cluster,
369 broken_cluster, 581 broken_cluster,
370 non_indic_cluster, 582 non_indic_cluster,
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 620
409 621
410 622
411 static void 623 static void
412 update_consonant_positions (const hb_ot_shape_plan_t *plan, 624 update_consonant_positions (const hb_ot_shape_plan_t *plan,
413 hb_font_t *font, 625 hb_font_t *font,
414 hb_buffer_t *buffer) 626 hb_buffer_t *buffer)
415 { 627 {
416 const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data ; 628 const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data ;
417 629
418 unsigned int consonant_pos = indic_plan->is_old_spec ? 0 : 1;
419 hb_codepoint_t glyphs[2]; 630 hb_codepoint_t glyphs[2];
420 if (indic_plan->get_virama_glyph (font, &glyphs[1 - consonant_pos])) 631 if (indic_plan->get_virama_glyph (font, &glyphs[0]))
421 { 632 {
422 hb_face_t *face = font->face; 633 hb_face_t *face = font->face;
423 unsigned int count = buffer->len; 634 unsigned int count = buffer->len;
424 for (unsigned int i = 0; i < count; i++) 635 for (unsigned int i = 0; i < count; i++)
425 if (buffer->info[i].indic_position() == POS_BASE_C) { 636 if (buffer->info[i].indic_position() == POS_BASE_C) {
426 » glyphs[consonant_pos] = buffer->info[i].codepoint; 637 » glyphs[1] = buffer->info[i].codepoint;
427 » buffer->info[i].indic_position() = consonant_position_from_face (indic_p lan, glyphs, 2, face); 638 » buffer->info[i].indic_position() = consonant_position_from_face (indic_p lan, glyphs, face);
428 } 639 }
429 } 640 }
430 } 641 }
431 642
432 643
433 /* Rules from: 644 /* Rules from:
434 * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ 645 * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
435 646
436 static void 647 static void
437 initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, 648 initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 base = i; 726 base = i;
516 break; 727 break;
517 } 728 }
518 if (info[i].indic_position() == POS_BELOW_C) 729 if (info[i].indic_position() == POS_BELOW_C)
519 seen_below = true; 730 seen_below = true;
520 731
521 /* -> or that is not a pre-base reordering Ra, 732 /* -> or that is not a pre-base reordering Ra,
522 * 733 *
523 * IMPLEMENTATION NOTES: 734 * IMPLEMENTATION NOTES:
524 * 735 *
525 » * Our pre-base reordering Ra's are marked POS_BELOW, so will be ski pped 736 » * Our pre-base reordering Ra's are marked POS_POST_C, so will be sk ipped
526 * by the logic above already. 737 * by the logic above already.
527 */ 738 */
528 739
529 /* -> or arrive at the first consonant. The consonant stopped at wil l 740 /* -> or arrive at the first consonant. The consonant stopped at wil l
530 * be the base. */ 741 * be the base. */
531 base = i; 742 base = i;
532 } 743 }
533 else 744 else
534 { 745 {
535 /* A ZWJ after a Halant stops the base search, and requests an expli cit 746 /* A ZWJ after a Halant stops the base search, and requests an expli cit
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
570 info[i].indic_position() = POS_BELOW_C; 781 info[i].indic_position() = POS_BELOW_C;
571 } 782 }
572 break; 783 break;
573 } 784 }
574 785
575 /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 786 /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
576 * and has more than one consonant, Ra is excluded from candidates for 787 * and has more than one consonant, Ra is excluded from candidates for
577 * base consonants. 788 * base consonants.
578 * 789 *
579 * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ 790 * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */
580 if (has_reph && base == start && start - limit <= 2) { 791 if (has_reph && base == start && limit - base <= 2) {
581 /* Have no other consonant, so Reph is not formed and Ra becomes base. */ 792 /* Have no other consonant, so Reph is not formed and Ra becomes base. */
582 has_reph = false; 793 has_reph = false;
583 } 794 }
584 } 795 }
585 796
586 if (base < end)
587 info[base].indic_position() = POS_BASE_C;
588
589 797
590 /* 2. Decompose and reorder Matras: 798 /* 2. Decompose and reorder Matras:
591 * 799 *
592 * Each matra and any syllable modifier sign in the cluster are moved to the 800 * Each matra and any syllable modifier sign in the cluster are moved to the
593 * appropriate position relative to the consonant(s) in the cluster. The 801 * appropriate position relative to the consonant(s) in the cluster. The
594 * shaping engine decomposes two- or three-part matras into their constituent 802 * shaping engine decomposes two- or three-part matras into their constituent
595 * parts before any repositioning. Matra characters are classified by which 803 * parts before any repositioning. Matra characters are classified by which
596 * consonant in a conjunct they have affinity for and are reordered to the 804 * consonant in a conjunct they have affinity for and are reordered to the
597 * following positions: 805 * following positions:
598 * 806 *
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 break; 845 break;
638 } 846 }
639 break; 847 break;
640 } 848 }
641 849
642 /* Handle beginning Ra */ 850 /* Handle beginning Ra */
643 if (has_reph) 851 if (has_reph)
644 info[start].indic_position() = POS_RA_TO_BECOME_REPH; 852 info[start].indic_position() = POS_RA_TO_BECOME_REPH;
645 853
646 /* For old-style Indic script tags, move the first post-base Halant after 854 /* For old-style Indic script tags, move the first post-base Halant after
647 * last consonant. */ 855 * last consonant. Only do this if there is *not* a Halant after last
856 * consonant. Otherwise it becomes messy. */
648 if (indic_plan->is_old_spec) { 857 if (indic_plan->is_old_spec) {
649 for (unsigned int i = base + 1; i < end; i++) 858 for (unsigned int i = base + 1; i < end; i++)
650 if (info[i].indic_category() == OT_H) { 859 if (info[i].indic_category() == OT_H) {
651 unsigned int j; 860 unsigned int j;
652 for (j = end - 1; j > i; j--) 861 for (j = end - 1; j > i; j--)
653 » if (is_consonant (info[j])) 862 » if (is_consonant (info[j]) || info[j].indic_category() == OT_H)
654 break; 863 break;
655 » if (j > i) { 864 » if (info[j].indic_category() != OT_H && j > i) {
656 /* Move Halant to after last consonant. */ 865 /* Move Halant to after last consonant. */
657 hb_glyph_info_t t = info[i]; 866 hb_glyph_info_t t = info[i];
658 memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); 867 memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0]));
659 info[j] = t; 868 info[j] = t;
660 } 869 }
661 break; 870 break;
662 } 871 }
663 } 872 }
664 873
665 /* Attach misc marks to previous char to move with them. */ 874 /* Attach misc marks to previous char to move with them. */
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
738 /* Base */ 947 /* Base */
739 mask = 0; 948 mask = 0;
740 if (base < end) 949 if (base < end)
741 info[base].mask |= mask; 950 info[base].mask |= mask;
742 /* Post-base */ 951 /* Post-base */
743 mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_p lan->mask_array[PSTF]; 952 mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_p lan->mask_array[PSTF];
744 for (unsigned int i = base + 1; i < end; i++) 953 for (unsigned int i = base + 1; i < end; i++)
745 info[i].mask |= mask; 954 info[i].mask |= mask;
746 } 955 }
747 956
957 if (indic_plan->is_old_spec &&
958 buffer->props.script == HB_SCRIPT_DEVANAGARI)
959 {
960 /* Old-spec eye-lash Ra needs special handling. From the
961 * spec:
962 *
963 * "The feature 'below-base form' is applied to consonants
964 * having below-base forms and following the base consonant.
965 * The exception is vattu, which may appear below half forms
966 * as well as below the base glyph. The feature 'below-base
967 * form' will be applied to all such occurrences of Ra as well."
968 *
969 * Test case: U+0924,U+094D,U+0930,U+094d,U+0915
970 * with Sanskrit 2003 font.
971 *
972 * However, note that Ra,Halant,ZWJ is the correct way to
973 * request eyelash form of Ra, so we wouldbn't inhibit it
974 * in that sequence.
975 *
976 * Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915
977 */
978 for (unsigned int i = start; i + 1 < base; i++)
979 if (info[i ].indic_category() == OT_Ra &&
980 info[i+1].indic_category() == OT_H &&
981 (i + 2 == base ||
982 info[i+2].indic_category() != OT_ZWJ))
983 {
984 info[i ].mask |= indic_plan->mask_array[BLWF];
985 info[i+1].mask |= indic_plan->mask_array[BLWF];
986 }
987 }
988
748 if (indic_plan->mask_array[PREF] && base + 2 < end) 989 if (indic_plan->mask_array[PREF] && base + 2 < end)
749 { 990 {
750 /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ 991 /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
751 for (unsigned int i = base + 1; i + 1 < end; i++) { 992 for (unsigned int i = base + 1; i + 1 < end; i++) {
752 hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint}; 993 hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint};
753 if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true , face)) 994 if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true , face))
754 { 995 {
755 info[i++].mask |= indic_plan->mask_array[PREF]; 996 info[i++].mask |= indic_plan->mask_array[PREF];
756 info[i++].mask |= indic_plan->mask_array[PREF]; 997 info[i++].mask |= indic_plan->mask_array[PREF];
757 998
(...skipping 13 matching lines...) Expand all
771 1012
772 /* Apply ZWJ/ZWNJ effects */ 1013 /* Apply ZWJ/ZWNJ effects */
773 for (unsigned int i = start + 1; i < end; i++) 1014 for (unsigned int i = start + 1; i < end; i++)
774 if (is_joiner (info[i])) { 1015 if (is_joiner (info[i])) {
775 bool non_joiner = info[i].indic_category() == OT_ZWNJ; 1016 bool non_joiner = info[i].indic_category() == OT_ZWNJ;
776 unsigned int j = i; 1017 unsigned int j = i;
777 1018
778 do { 1019 do {
779 j--; 1020 j--;
780 1021
781 » /* A ZWJ disables CJCT, however, it's mere presence is enough 1022 » /* ZWJ/ZWNJ should disable CJCT. They do that by simply
782 » * to disable ligation. No explicit action needed. */ 1023 » * being there, since we don't skip them for the CJCT
1024 » * feature (ie. F_MANUAL_ZWJ) */
783 1025
784 /* A ZWNJ disables HALF. */ 1026 /* A ZWNJ disables HALF. */
785 if (non_joiner) 1027 if (non_joiner)
786 info[j].mask &= ~indic_plan->mask_array[HALF]; 1028 info[j].mask &= ~indic_plan->mask_array[HALF];
787 1029
788 } while (j > start && !is_consonant (info[j])); 1030 } while (j > start && !is_consonant (info[j]));
789 } 1031 }
790 } 1032 }
791 1033
792 1034
793 static void 1035 static void
794 initial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan, 1036 initial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan,
795 hb_face_t *face, 1037 hb_face_t *face,
796 hb_buffer_t *buffer, 1038 hb_buffer_t *buffer,
797 unsigned int start, unsigned int end) 1039 unsigned int start, unsigned int end)
798 { 1040 {
799 /* We made the vowels look like consonants. So let's call the consonant logic ! */ 1041 /* We made the vowels look like consonants. So let's call the consonant logic ! */
800 initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1042 initial_reordering_consonant_syllable (plan, face, buffer, start, end);
801 } 1043 }
802 1044
803 static void 1045 static void
804 initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, 1046 initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
805 hb_face_t *face, 1047 hb_face_t *face,
806 hb_buffer_t *buffer, 1048 hb_buffer_t *buffer,
807 unsigned int start, unsigned int end) 1049 unsigned int start, unsigned int end)
808 { 1050 {
809 /* We treat NBSP/dotted-circle as if they are consonants, so we should just ch ain. 1051 /* We treat NBSP/dotted-circle as if they are consonants, so we should just ch ain.
810 * Only if not in compatibility mode that is... */ 1052 * Only if not in compatibility mode that is... */
811 1053
812 if (indic_options ().uniscribe_bug_compatible) 1054 if (hb_options ().uniscribe_bug_compatible)
813 { 1055 {
814 /* For dotted-circle, this is what Uniscribe does: 1056 /* For dotted-circle, this is what Uniscribe does:
815 * If dotted-circle is the last glyph, it just does nothing. 1057 * If dotted-circle is the last glyph, it just does nothing.
816 * Ie. It doesn't form Reph. */ 1058 * Ie. It doesn't form Reph. */
817 if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) 1059 if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE)
818 return; 1060 return;
819 } 1061 }
820 1062
821 initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1063 initial_reordering_consonant_syllable (plan, face, buffer, start, end);
822 } 1064 }
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
955 */ 1197 */
956 1198
957 /* Find base again */ 1199 /* Find base again */
958 unsigned int base; 1200 unsigned int base;
959 for (base = start; base < end; base++) 1201 for (base = start; base < end; base++)
960 if (info[base].indic_position() >= POS_BASE_C) { 1202 if (info[base].indic_position() >= POS_BASE_C) {
961 if (start < base && info[base].indic_position() > POS_BASE_C) 1203 if (start < base && info[base].indic_position() > POS_BASE_C)
962 base--; 1204 base--;
963 break; 1205 break;
964 } 1206 }
1207 if (base == end && start < base &&
1208 info[base - 1].indic_category() != OT_ZWJ)
1209 base--;
1210 while (start < base &&
1211 (info[base].indic_category() == OT_H ||
1212 info[base].indic_category() == OT_N))
1213 base--;
965 1214
966 1215
967 /* o Reorder matras: 1216 /* o Reorder matras:
968 * 1217 *
969 * If a pre-base matra character had been reordered before applying basic 1218 * If a pre-base matra character had been reordered before applying basic
970 * features, the glyph can be moved closer to the main consonant based on 1219 * features, the glyph can be moved closer to the main consonant based on
971 * whether half-forms had been formed. Actual position for the matra is 1220 * whether half-forms had been formed. Actual position for the matra is
972 * defined as “after last standalone halant glyph, after initial matra 1221 * defined as “after last standalone halant glyph, after initial matra
973 * position and before the main consonant”. If ZWJ or ZWNJ follow this 1222 * position and before the main consonant”. If ZWJ or ZWNJ follow this
974 * halant, position is moved after it. 1223 * halant, position is moved after it.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1006 if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M) 1255 if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M)
1007 { 1256 {
1008 /* Now go see if there's actually any matras... */ 1257 /* Now go see if there's actually any matras... */
1009 for (unsigned int i = new_pos; i > start; i--) 1258 for (unsigned int i = new_pos; i > start; i--)
1010 if (info[i - 1].indic_position () == POS_PRE_M) 1259 if (info[i - 1].indic_position () == POS_PRE_M)
1011 { 1260 {
1012 unsigned int old_pos = i - 1; 1261 unsigned int old_pos = i - 1;
1013 hb_glyph_info_t tmp = info[old_pos]; 1262 hb_glyph_info_t tmp = info[old_pos];
1014 memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * siz eof (info[0])); 1263 memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * siz eof (info[0]));
1015 info[new_pos] = tmp; 1264 info[new_pos] = tmp;
1265 if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. * /
1266 base--;
1016 new_pos--; 1267 new_pos--;
1017 } 1268 }
1018 buffer->merge_clusters (new_pos, MIN (end, base + 1)); 1269 buffer->merge_clusters (new_pos, MIN (end, base + 1));
1019 } else { 1270 } else {
1020 for (unsigned int i = start; i < base; i++) 1271 for (unsigned int i = start; i < base; i++)
1021 if (info[i].indic_position () == POS_PRE_M) { 1272 if (info[i].indic_position () == POS_PRE_M) {
1022 buffer->merge_clusters (i, MIN (end, base + 1)); 1273 buffer->merge_clusters (i, MIN (end, base + 1));
1023 break; 1274 break;
1024 } 1275 }
1025 } 1276 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1064 * 1315 *
1065 * Note: in old-implementation fonts, where classifications were 1316 * Note: in old-implementation fonts, where classifications were
1066 * fixed in shaping engine, there was no case where reph position 1317 * fixed in shaping engine, there was no case where reph position
1067 * will be found on this step. 1318 * will be found on this step.
1068 */ 1319 */
1069 { 1320 {
1070 new_reph_pos = start + 1; 1321 new_reph_pos = start + 1;
1071 while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 1322 while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
1072 new_reph_pos++; 1323 new_reph_pos++;
1073 1324
1074 if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 1325 if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos]))
1326 {
1075 /* ->If ZWJ or ZWNJ are following this halant, position is moved after i t. */ 1327 /* ->If ZWJ or ZWNJ are following this halant, position is moved after i t. */
1076 if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 1328 if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
1077 new_reph_pos++; 1329 new_reph_pos++;
1078 goto reph_move; 1330 goto reph_move;
1079 } 1331 }
1080 } 1332 }
1081 1333
1082 /* 3. If reph should be repositioned after the main consonant: find th e 1334 /* 3. If reph should be repositioned after the main consonant: find th e
1083 * first consonant not ligated with main, or find the first 1335 * first consonant not ligated with main, or find the first
1084 * consonant that is not a potential pre-base reordering Ra. 1336 * consonant that is not a potential pre-base reordering Ra.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1116 * is post-main, it will skip above-base matras that also have a 1368 * is post-main, it will skip above-base matras that also have a
1117 * post-main position. 1369 * post-main position.
1118 */ 1370 */
1119 reph_step_5: 1371 reph_step_5:
1120 { 1372 {
1121 /* Copied from step 2. */ 1373 /* Copied from step 2. */
1122 new_reph_pos = start + 1; 1374 new_reph_pos = start + 1;
1123 while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 1375 while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
1124 new_reph_pos++; 1376 new_reph_pos++;
1125 1377
1126 if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 1378 if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos]))
1379 {
1127 /* ->If ZWJ or ZWNJ are following this halant, position is moved after i t. */ 1380 /* ->If ZWJ or ZWNJ are following this halant, position is moved after i t. */
1128 if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 1381 if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
1129 new_reph_pos++; 1382 new_reph_pos++;
1130 goto reph_move; 1383 goto reph_move;
1131 } 1384 }
1132 } 1385 }
1133 1386
1134 /* 6. Otherwise, reorder reph to the end of the syllable. 1387 /* 6. Otherwise, reorder reph to the end of the syllable.
1135 */ 1388 */
1136 { 1389 {
1137 new_reph_pos = end - 1; 1390 new_reph_pos = end - 1;
1138 while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_ SMVD) 1391 while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_ SMVD)
1139 new_reph_pos--; 1392 new_reph_pos--;
1140 1393
1141 /* 1394 /*
1142 * If the Reph is to be ending up after a Matra,Halant sequence, 1395 * If the Reph is to be ending up after a Matra,Halant sequence,
1143 * position it before that Halant so it can interact with the Matra. 1396 * position it before that Halant so it can interact with the Matra.
1144 * However, if it's a plain Consonant,Halant we shouldn't do that. 1397 * However, if it's a plain Consonant,Halant we shouldn't do that.
1145 * Uniscribe doesn't do this. 1398 * Uniscribe doesn't do this.
1146 * TEST: U+0930,U+094D,U+0915,U+094B,U+094D 1399 * TEST: U+0930,U+094D,U+0915,U+094B,U+094D
1147 */ 1400 */
1148 if (!indic_options ().uniscribe_bug_compatible && 1401 if (!hb_options ().uniscribe_bug_compatible &&
1149 unlikely (is_halant_or_coeng (info[new_reph_pos]))) { 1402 unlikely (is_halant_or_coeng (info[new_reph_pos]))) {
1150 for (unsigned int i = base + 1; i < new_reph_pos; i++) 1403 for (unsigned int i = base + 1; i < new_reph_pos; i++)
1151 if (info[i].indic_category() == OT_M) { 1404 if (info[i].indic_category() == OT_M) {
1152 /* Ok, got it. */ 1405 /* Ok, got it. */
1153 new_reph_pos--; 1406 new_reph_pos--;
1154 } 1407 }
1155 } 1408 }
1156 goto reph_move; 1409 goto reph_move;
1157 } 1410 }
1158 1411
1159 reph_move: 1412 reph_move:
1160 { 1413 {
1161 /* Yay, one big cluster! Merge before moving. */ 1414 /* Yay, one big cluster! Merge before moving. */
1162 buffer->merge_clusters (start, end); 1415 buffer->merge_clusters (start, end);
1163 1416
1164 /* Move */ 1417 /* Move */
1165 hb_glyph_info_t reph = info[start]; 1418 hb_glyph_info_t reph = info[start];
1166 memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof ( info[0])); 1419 memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof ( info[0]));
1167 info[new_reph_pos] = reph; 1420 info[new_reph_pos] = reph;
1421 if (start < base && base <= new_reph_pos)
1422 base--;
1168 } 1423 }
1169 } 1424 }
1170 1425
1171 1426
1172 /* o Reorder pre-base reordering consonants: 1427 /* o Reorder pre-base reordering consonants:
1173 * 1428 *
1174 * If a pre-base reordering consonant is found, reorder it according to 1429 * If a pre-base reordering consonant is found, reorder it according to
1175 * the following rules: 1430 * the following rules:
1176 */ 1431 */
1177 1432
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1213 for (unsigned int i = base + 1; i < old_pos; i++) 1468 for (unsigned int i = base + 1; i < old_pos; i++)
1214 if (info[i].indic_category() == OT_M) 1469 if (info[i].indic_category() == OT_M)
1215 { 1470 {
1216 new_pos--; 1471 new_pos--;
1217 break; 1472 break;
1218 } 1473 }
1219 } 1474 }
1220 } 1475 }
1221 1476
1222 if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) 1477 if (new_pos > start && is_halant_or_coeng (info[new_pos - 1]))
1478 {
1223 /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 1479 /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
1224 if (new_pos < end && is_joiner (info[new_pos])) 1480 if (new_pos < end && is_joiner (info[new_pos]))
1225 new_pos++; 1481 new_pos++;
1482 }
1226 1483
1227 { 1484 {
1228 unsigned int old_pos = i; 1485 unsigned int old_pos = i;
1229 buffer->merge_clusters (new_pos, old_pos + 1); 1486 buffer->merge_clusters (new_pos, old_pos + 1);
1230 hb_glyph_info_t tmp = info[old_pos]; 1487 hb_glyph_info_t tmp = info[old_pos];
1231 memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * s izeof (info[0])); 1488 memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * s izeof (info[0]));
1232 info[new_pos] = tmp; 1489 info[new_pos] = tmp;
1490 if (new_pos <= base && base < old_pos)
1491 base++;
1233 } 1492 }
1234 } 1493 }
1235 1494
1236 break; 1495 break;
1237 } 1496 }
1238 } 1497 }
1239 1498
1240 1499
1241 /* Apply 'init' to the Left Matra if it's a word start. */ 1500 /* Apply 'init' to the Left Matra if it's a word start. */
1242 if (info[start].indic_position () == POS_PRE_M && 1501 if (info[start].indic_position () == POS_PRE_M &&
1243 (!start || 1502 (!start ||
1244 !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & 1503 !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) &
1245 FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATE GORY_NON_SPACING_MARK)))) 1504 FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATE GORY_NON_SPACING_MARK))))
1246 info[start].mask |= indic_plan->mask_array[INIT]; 1505 info[start].mask |= indic_plan->mask_array[INIT];
1247 1506
1248 1507
1249 /* 1508 /*
1250 * Finish off the clusters and go home! 1509 * Finish off the clusters and go home!
1251 */ 1510 */
1252 if (indic_options ().uniscribe_bug_compatible) 1511 if (hb_options ().uniscribe_bug_compatible)
1253 { 1512 {
1254 /* Uniscribe merges the entire cluster. 1513 /* Uniscribe merges the entire cluster.
1255 * This means, half forms are submerged into the main consonants cluster. 1514 * This means, half forms are submerged into the main consonants cluster.
1256 * This is unnecessary, and makes cursor positioning harder, but that's what 1515 * This is unnecessary, and makes cursor positioning harder, but that's what
1257 * Uniscribe does. */ 1516 * Uniscribe does. */
1258 buffer->merge_clusters (start, end); 1517 buffer->merge_clusters (start, end);
1259 } 1518 }
1260 } 1519 }
1261 1520
1262 1521
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
1358 * The Uniscribe behavior is now documented in the newly published Sinhala 1617 * The Uniscribe behavior is now documented in the newly published Sinhala
1359 * spec in 2012: 1618 * spec in 2012:
1360 * 1619 *
1361 * http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shapi ng 1620 * http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shapi ng
1362 */ 1621 */
1363 1622
1364 const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan- >data; 1623 const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan- >data;
1365 1624
1366 hb_codepoint_t glyph; 1625 hb_codepoint_t glyph;
1367 1626
1368 if (indic_options ().uniscribe_bug_compatible || 1627 if (hb_options ().uniscribe_bug_compatible ||
1369 (c->font->get_glyph (ab, 0, &glyph) && 1628 (c->font->get_glyph (ab, 0, &glyph) &&
1370 indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face))) 1629 indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face)))
1371 { 1630 {
1372 /* Ok, safe to use Uniscribe-style decomposition. */ 1631 /* Ok, safe to use Uniscribe-style decomposition. */
1373 *a = 0x0DD9; 1632 *a = 0x0DD9;
1374 *b = ab; 1633 *b = ab;
1375 return true; 1634 return true;
1376 } 1635 }
1377 } 1636 }
1378 1637
(...skipping 22 matching lines...) Expand all
1401 "indic", 1660 "indic",
1402 collect_features_indic, 1661 collect_features_indic,
1403 override_features_indic, 1662 override_features_indic,
1404 data_create_indic, 1663 data_create_indic,
1405 data_destroy_indic, 1664 data_destroy_indic,
1406 NULL, /* preprocess_text */ 1665 NULL, /* preprocess_text */
1407 normalization_preference_indic, 1666 normalization_preference_indic,
1408 decompose_indic, 1667 decompose_indic,
1409 compose_indic, 1668 compose_indic,
1410 setup_masks_indic, 1669 setup_masks_indic,
1411 false, /* zero_width_attached_marks */ 1670 HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
1412 false, /* fallback_position */ 1671 false, /* fallback_position */
1413 }; 1672 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698