OLD | NEW |
1 /* | 1 /* |
2 * Copyright © 2011,2012 Google, Inc. | 2 * Copyright © 2011,2012 Google, Inc. |
3 * | 3 * |
4 * This is part of HarfBuzz, a text shaping library. | 4 * This is part of HarfBuzz, a text shaping library. |
5 * | 5 * |
6 * Permission is hereby granted, without written agreement and without | 6 * Permission is hereby granted, without written agreement and without |
7 * license or royalty fees, to use, copy, modify, and distribute this | 7 * license or royalty fees, to use, copy, modify, and distribute this |
8 * software and its documentation for any purpose, provided that the | 8 * software and its documentation for any purpose, provided that the |
9 * above copyright notice and the following two paragraphs appear in | 9 * above copyright notice and the following two paragraphs appear in |
10 * all copies of this software. | 10 * all copies of this software. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 * | 55 * |
56 * - When a font has a precomposed character for a sequence but the 'ccmp' | 56 * - When a font has a precomposed character for a sequence but the 'ccmp' |
57 * feature in the font is not adequate, use the precomposed character | 57 * feature in the font is not adequate, use the precomposed character |
58 * which typically has better mark positioning. | 58 * which typically has better mark positioning. |
59 * | 59 * |
60 * - When a font does not support a combining mark, but supports it precompose
d | 60 * - When a font does not support a combining mark, but supports it precompose
d |
61 * with previous base, use that. This needs the itemizer to have this | 61 * with previous base, use that. This needs the itemizer to have this |
62 * knowledge too. We need to provide assistance to the itemizer. | 62 * knowledge too. We need to provide assistance to the itemizer. |
63 * | 63 * |
64 * - When a font does not support a character but supports its decomposition, | 64 * - When a font does not support a character but supports its decomposition, |
65 * well, use the decomposition. | 65 * well, use the decomposition (preferring the canonical decomposition, but |
| 66 * falling back to the compatibility decomposition if necessary). The |
| 67 * compatibility decomposition is really nice to have, for characters like |
| 68 * ellipsis, or various-sized space characters. |
66 * | 69 * |
67 * - The Indic shaper requests decomposed output. This will handle splitting | 70 * - The complex shapers can customize the compose and decompose functions to |
68 * matra for the Indic shaper. | 71 * offload some of their requirements to the normalizer. For example, the |
| 72 * Indic shaper may want to disallow recomposing of two matras. |
| 73 * |
| 74 * - We try compatibility decomposition if decomposing through canonical |
| 75 * decomposition alone failed to find a sequence that the font supports. |
| 76 * We don't try compatibility decomposition recursively during the canonical |
| 77 * decomposition phase. This has minimal impact. There are only a handful |
| 78 * of Greek letter that have canonical decompositions that include character
s |
| 79 * with compatibility decomposition. Those can be found using this command: |
| 80 * |
| 81 * egrep "`echo -n ';('; grep ';<' UnicodeData.txt | cut -d';' -f1 | tr '\n
' '|'; echo ') '`" UnicodeData.txt |
69 */ | 82 */ |
70 | 83 |
71 static void | 84 static hb_bool_t |
72 output_glyph (hb_buffer_t *buffer, hb_codepoint_t glyph) | 85 decompose_func (hb_unicode_funcs_t *unicode, |
73 { | 86 » » hb_codepoint_t ab, |
74 buffer->output_glyph (glyph); | 87 » » hb_codepoint_t *a, |
| 88 » » hb_codepoint_t *b) |
| 89 { |
| 90 /* XXX FIXME, move these to complex shapers and propagage to normalizer.*/ |
| 91 switch (ab) { |
| 92 case 0x0AC9 : return false; |
| 93 |
| 94 case 0x0931 : return false; |
| 95 case 0x0B94 : return false; |
| 96 |
| 97 /* These ones have Unicode decompositions, but we do it |
| 98 * this way to be close to what Uniscribe does. */ |
| 99 case 0x0DDA : *a = 0x0DD9; *b= 0x0DDA; return true; |
| 100 case 0x0DDC : *a = 0x0DD9; *b= 0x0DDC; return true; |
| 101 case 0x0DDD : *a = 0x0DD9; *b= 0x0DDD; return true; |
| 102 case 0x0DDE : *a = 0x0DD9; *b= 0x0DDE; return true; |
| 103 |
| 104 case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true; |
| 105 case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true; |
| 106 case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true; |
| 107 case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true; |
| 108 case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true; |
| 109 case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true; |
| 110 case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true; |
| 111 case 0x1925 : *a = 0x1920; *b= 0x1923; return true; |
| 112 case 0x1926 : *a = 0x1920; *b= 0x1924; return true; |
| 113 case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true; |
| 114 case 0x1112E : *a = 0x11127; *b= 0x11131; return true; |
| 115 case 0x1112F : *a = 0x11127; *b= 0x11132; return true; |
| 116 #if 0 |
| 117 case 0x0B57 : *a = 0xno decomp, -> RIGHT; return true; |
| 118 case 0x1C29 : *a = 0xno decomp, -> LEFT; return true; |
| 119 case 0xA9C0 : *a = 0xno decomp, -> RIGHT; return true; |
| 120 case 0x111BF : *a = 0xno decomp, -> ABOVE; return true; |
| 121 #endif |
| 122 } |
| 123 return unicode->decompose (ab, a, b); |
| 124 } |
| 125 |
| 126 static hb_bool_t |
| 127 compose_func (hb_unicode_funcs_t *unicode, |
| 128 » hb_codepoint_t a, |
| 129 » hb_codepoint_t b, |
| 130 » hb_codepoint_t *ab) |
| 131 { |
| 132 /* XXX, this belongs to indic normalizer. */ |
| 133 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (a))) |
| 134 return false; |
| 135 /* XXX, add composition-exclusion exceptions to Indic shaper. */ |
| 136 if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; } |
| 137 |
| 138 /* XXX, these belong to the hebew / default shaper. */ |
| 139 /* Hebrew presentation-form shaping. |
| 140 * https://bugzilla.mozilla.org/show_bug.cgi?id=728866 */ |
| 141 // Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA; |
| 142 // note that some letters do not have a dagesh presForm encoded |
| 143 static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = { |
| 144 0xFB30, // ALEF |
| 145 0xFB31, // BET |
| 146 0xFB32, // GIMEL |
| 147 0xFB33, // DALET |
| 148 0xFB34, // HE |
| 149 0xFB35, // VAV |
| 150 0xFB36, // ZAYIN |
| 151 0, // HET |
| 152 0xFB38, // TET |
| 153 0xFB39, // YOD |
| 154 0xFB3A, // FINAL KAF |
| 155 0xFB3B, // KAF |
| 156 0xFB3C, // LAMED |
| 157 0, // FINAL MEM |
| 158 0xFB3E, // MEM |
| 159 0, // FINAL NUN |
| 160 0xFB40, // NUN |
| 161 0xFB41, // SAMEKH |
| 162 0, // AYIN |
| 163 0xFB43, // FINAL PE |
| 164 0xFB44, // PE |
| 165 0, // FINAL TSADI |
| 166 0xFB46, // TSADI |
| 167 0xFB47, // QOF |
| 168 0xFB48, // RESH |
| 169 0xFB49, // SHIN |
| 170 0xFB4A // TAV |
| 171 }; |
| 172 |
| 173 hb_bool_t found = unicode->compose (a, b, ab); |
| 174 |
| 175 if (!found && (b & ~0x7F) == 0x0580) { |
| 176 // special-case Hebrew presentation forms that are excluded from |
| 177 // standard normalization, but wanted for old fonts |
| 178 switch (b) { |
| 179 case 0x05B4: // HIRIQ |
| 180 » if (a == 0x05D9) { // YOD |
| 181 » *ab = 0xFB1D; |
| 182 » found = true; |
| 183 » } |
| 184 » break; |
| 185 case 0x05B7: // patah |
| 186 » if (a == 0x05F2) { // YIDDISH YOD YOD |
| 187 » *ab = 0xFB1F; |
| 188 » found = true; |
| 189 » } else if (a == 0x05D0) { // ALEF |
| 190 » *ab = 0xFB2E; |
| 191 » found = true; |
| 192 » } |
| 193 » break; |
| 194 case 0x05B8: // QAMATS |
| 195 » if (a == 0x05D0) { // ALEF |
| 196 » *ab = 0xFB2F; |
| 197 » found = true; |
| 198 » } |
| 199 » break; |
| 200 case 0x05B9: // HOLAM |
| 201 » if (a == 0x05D5) { // VAV |
| 202 » *ab = 0xFB4B; |
| 203 » found = true; |
| 204 » } |
| 205 » break; |
| 206 case 0x05BC: // DAGESH |
| 207 » if (a >= 0x05D0 && a <= 0x05EA) { |
| 208 » *ab = sDageshForms[a - 0x05D0]; |
| 209 » found = (*ab != 0); |
| 210 » } else if (a == 0xFB2A) { // SHIN WITH SHIN DOT |
| 211 » *ab = 0xFB2C; |
| 212 » found = true; |
| 213 » } else if (a == 0xFB2B) { // SHIN WITH SIN DOT |
| 214 » *ab = 0xFB2D; |
| 215 » found = true; |
| 216 » } |
| 217 » break; |
| 218 case 0x05BF: // RAFE |
| 219 » switch (a) { |
| 220 » case 0x05D1: // BET |
| 221 » *ab = 0xFB4C; |
| 222 » found = true; |
| 223 » break; |
| 224 » case 0x05DB: // KAF |
| 225 » *ab = 0xFB4D; |
| 226 » found = true; |
| 227 » break; |
| 228 » case 0x05E4: // PE |
| 229 » *ab = 0xFB4E; |
| 230 » found = true; |
| 231 » break; |
| 232 » } |
| 233 » break; |
| 234 case 0x05C1: // SHIN DOT |
| 235 » if (a == 0x05E9) { // SHIN |
| 236 » *ab = 0xFB2A; |
| 237 » found = true; |
| 238 » } else if (a == 0xFB49) { // SHIN WITH DAGESH |
| 239 » *ab = 0xFB2C; |
| 240 » found = true; |
| 241 » } |
| 242 » break; |
| 243 case 0x05C2: // SIN DOT |
| 244 » if (a == 0x05E9) { // SHIN |
| 245 » *ab = 0xFB2B; |
| 246 » found = true; |
| 247 » } else if (a == 0xFB49) { // SHIN WITH DAGESH |
| 248 » *ab = 0xFB2D; |
| 249 » found = true; |
| 250 » } |
| 251 » break; |
| 252 } |
| 253 } |
| 254 |
| 255 return found; |
| 256 } |
| 257 |
| 258 |
| 259 static inline void |
| 260 set_glyph (hb_glyph_info_t &info, hb_font_t *font) |
| 261 { |
| 262 font->get_glyph (info.codepoint, 0, &info.glyph_index()); |
| 263 } |
| 264 |
| 265 static inline void |
| 266 output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph) |
| 267 { |
| 268 buffer->cur().glyph_index() = glyph; |
| 269 buffer->output_glyph (unichar); |
75 _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode); | 270 _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode); |
76 } | 271 } |
77 | 272 |
78 static bool | 273 static inline void |
79 decompose (hb_font_t *font, hb_buffer_t *buffer, | 274 next_char (hb_buffer_t *buffer, hb_codepoint_t glyph) |
80 » bool shortest, | 275 { |
81 » hb_codepoint_t ab) | 276 buffer->cur().glyph_index() = glyph; |
82 { | 277 buffer->next_glyph (); |
83 hb_codepoint_t a, b, glyph; | 278 } |
84 | 279 |
85 if (!hb_unicode_decompose (buffer->unicode, ab, &a, &b) || | 280 static inline void |
86 (b && !hb_font_get_glyph (font, b, 0, &glyph))) | 281 skip_char (hb_buffer_t *buffer) |
87 return false; | 282 { |
88 | 283 buffer->skip_glyph (); |
89 bool has_a = hb_font_get_glyph (font, a, 0, &glyph); | 284 } |
| 285 |
| 286 /* Returns 0 if didn't decompose, number of resulting characters otherwise. */ |
| 287 static inline unsigned int |
| 288 decompose (hb_font_t *font, hb_buffer_t *buffer, bool shortest, hb_codepoint_t a
b) |
| 289 { |
| 290 hb_codepoint_t a, b, a_glyph, b_glyph; |
| 291 |
| 292 if (!decompose_func (buffer->unicode, ab, &a, &b) || |
| 293 (b && !font->get_glyph (b, 0, &b_glyph))) |
| 294 return 0; |
| 295 |
| 296 bool has_a = font->get_glyph (a, 0, &a_glyph); |
90 if (shortest && has_a) { | 297 if (shortest && has_a) { |
91 /* Output a and b */ | 298 /* Output a and b */ |
92 output_glyph (buffer, a); | 299 output_char (buffer, a, a_glyph); |
93 if (b) | 300 if (likely (b)) { |
94 output_glyph (buffer, b); | 301 output_char (buffer, b, b_glyph); |
95 return true; | 302 return 2; |
96 } | 303 } |
97 | 304 return 1; |
98 if (decompose (font, buffer, shortest, a)) { | 305 } |
99 if (b) | 306 |
100 output_glyph (buffer, b); | 307 unsigned int ret; |
101 return true; | 308 if ((ret = decompose (font, buffer, shortest, a))) { |
| 309 if (b) { |
| 310 output_char (buffer, b, b_glyph); |
| 311 return ret + 1; |
| 312 } |
| 313 return ret; |
102 } | 314 } |
103 | 315 |
104 if (has_a) { | 316 if (has_a) { |
105 output_glyph (buffer, a); | 317 output_char (buffer, a, a_glyph); |
106 if (b) | 318 if (likely (b)) { |
107 output_glyph (buffer, b); | 319 output_char (buffer, b, b_glyph); |
108 return true; | 320 return 2; |
109 } | 321 } |
110 | 322 return 1; |
111 return false; | 323 } |
112 } | 324 |
113 | 325 return 0; |
114 static void | 326 } |
115 decompose_current_glyph (hb_font_t *font, hb_buffer_t *buffer, | 327 |
116 » » » bool shortest) | 328 /* Returns 0 if didn't decompose, number of resulting characters otherwise. */ |
117 { | 329 static inline bool |
118 if (decompose (font, buffer, shortest, buffer->cur().codepoint)) | 330 decompose_compatibility (hb_font_t *font, hb_buffer_t *buffer, hb_codepoint_t u) |
119 buffer->skip_glyph (); | 331 { |
| 332 unsigned int len, i; |
| 333 hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN]; |
| 334 hb_codepoint_t glyphs[HB_UNICODE_MAX_DECOMPOSITION_LEN]; |
| 335 |
| 336 len = buffer->unicode->decompose_compatibility (u, decomposed); |
| 337 if (!len) |
| 338 return 0; |
| 339 |
| 340 for (i = 0; i < len; i++) |
| 341 if (!font->get_glyph (decomposed[i], 0, &glyphs[i])) |
| 342 return 0; |
| 343 |
| 344 for (i = 0; i < len; i++) |
| 345 output_char (buffer, decomposed[i], glyphs[i]); |
| 346 |
| 347 return len; |
| 348 } |
| 349 |
| 350 /* Returns true if recomposition may be benefitial. */ |
| 351 static inline bool |
| 352 decompose_current_character (hb_font_t *font, hb_buffer_t *buffer, bool shortest
) |
| 353 { |
| 354 hb_codepoint_t glyph; |
| 355 unsigned int len = 1; |
| 356 |
| 357 /* Kind of a cute waterfall here... */ |
| 358 if (shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph)) |
| 359 next_char (buffer, glyph); |
| 360 else if ((len = decompose (font, buffer, shortest, buffer->cur().codepoint))) |
| 361 skip_char (buffer); |
| 362 else if (!shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph)) |
| 363 next_char (buffer, glyph); |
| 364 else if ((len = decompose_compatibility (font, buffer, buffer->cur().codepoint
))) |
| 365 skip_char (buffer); |
120 else | 366 else |
| 367 next_char (buffer, glyph); /* glyph is initialized in earlier branches. */ |
| 368 |
| 369 /* |
| 370 * A recomposition would only be useful if we decomposed into at least three |
| 371 * characters... |
| 372 */ |
| 373 return len > 2; |
| 374 } |
| 375 |
| 376 static inline void |
| 377 handle_variation_selector_cluster (hb_font_t *font, hb_buffer_t *buffer, unsigne
d int end) |
| 378 { |
| 379 for (; buffer->idx < end - 1;) { |
| 380 if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepo
int))) { |
| 381 /* The next two lines are some ugly lines... But work. */ |
| 382 font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buff
er->cur().glyph_index()); |
| 383 buffer->replace_glyphs (2, 1, &buffer->cur().codepoint); |
| 384 } else { |
| 385 set_glyph (buffer->cur(), font); |
| 386 buffer->next_glyph (); |
| 387 } |
| 388 } |
| 389 if (likely (buffer->idx < end)) { |
| 390 set_glyph (buffer->cur(), font); |
121 buffer->next_glyph (); | 391 buffer->next_glyph (); |
122 } | 392 } |
123 | 393 } |
124 static void | 394 |
125 decompose_single_char_cluster (hb_font_t *font, hb_buffer_t *buffer, | 395 /* Returns true if recomposition may be benefitial. */ |
126 » » » bool will_recompose) | 396 static inline bool |
127 { | 397 decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer, unsigned int
end) |
128 hb_codepoint_t glyph; | |
129 | |
130 /* If recomposing and font supports this, we're good to go */ | |
131 if (will_recompose && hb_font_get_glyph (font, buffer->cur().codepoint, 0, &gl
yph)) { | |
132 buffer->next_glyph (); | |
133 return; | |
134 } | |
135 | |
136 decompose_current_glyph (font, buffer, will_recompose); | |
137 } | |
138 | |
139 static void | |
140 decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer, | |
141 » » » unsigned int end) | |
142 { | 398 { |
143 /* TODO Currently if there's a variation-selector we give-up, it's just too ha
rd. */ | 399 /* TODO Currently if there's a variation-selector we give-up, it's just too ha
rd. */ |
144 for (unsigned int i = buffer->idx; i < end; i++) | 400 for (unsigned int i = buffer->idx; i < end; i++) |
145 if (unlikely (_hb_unicode_is_variation_selector (buffer->info[i].codepoint))
) { | 401 if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepo
int))) { |
146 while (buffer->idx < end) | 402 handle_variation_selector_cluster (font, buffer, end); |
147 » buffer->next_glyph (); | 403 return false; |
148 return; | |
149 } | 404 } |
150 | 405 |
151 while (buffer->idx < end) | 406 while (buffer->idx < end) |
152 decompose_current_glyph (font, buffer, false); | 407 decompose_current_character (font, buffer, false); |
153 } | 408 /* We can be smarter here and only return true if there are at least two ccc!=
0 marks. |
| 409 * But does not matter. */ |
| 410 return true; |
| 411 } |
| 412 |
| 413 static inline bool |
| 414 decompose_cluster (hb_font_t *font, hb_buffer_t *buffer, bool short_circuit, uns
igned int end) |
| 415 { |
| 416 if (likely (buffer->idx + 1 == end)) |
| 417 return decompose_current_character (font, buffer, short_circuit); |
| 418 else |
| 419 return decompose_multi_char_cluster (font, buffer, end); |
| 420 } |
| 421 |
154 | 422 |
155 static int | 423 static int |
156 compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) | 424 compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) |
157 { | 425 { |
158 unsigned int a = _hb_glyph_info_get_modified_combining_class (pa); | 426 unsigned int a = _hb_glyph_info_get_modified_combining_class (pa); |
159 unsigned int b = _hb_glyph_info_get_modified_combining_class (pb); | 427 unsigned int b = _hb_glyph_info_get_modified_combining_class (pb); |
160 | 428 |
161 return a < b ? -1 : a == b ? 0 : +1; | 429 return a < b ? -1 : a == b ? 0 : +1; |
162 } | 430 } |
163 | 431 |
| 432 |
164 void | 433 void |
165 _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer, | 434 _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer, |
166 hb_ot_shape_normalization_mode_t mode) | 435 hb_ot_shape_normalization_mode_t mode) |
167 { | 436 { |
168 bool recompose = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED; | 437 bool short_circuit = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED && |
169 bool has_multichar_clusters = false; | 438 » » mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITIC
S_NO_SHORT_CIRCUIT; |
| 439 bool can_use_recompose = false; |
170 unsigned int count; | 440 unsigned int count; |
171 | 441 |
172 /* We do a fairly straightforward yet custom normalization process in three | 442 /* We do a fairly straightforward yet custom normalization process in three |
173 * separate rounds: decompose, reorder, recompose (if desired). Currently | 443 * separate rounds: decompose, reorder, recompose (if desired). Currently |
174 * this makes two buffer swaps. We can make it faster by moving the last | 444 * this makes two buffer swaps. We can make it faster by moving the last |
175 * two rounds into the inner loop for the first round, but it's more readable | 445 * two rounds into the inner loop for the first round, but it's more readable |
176 * this way. */ | 446 * this way. */ |
177 | 447 |
178 | 448 |
179 /* First round, decompose */ | 449 /* First round, decompose */ |
180 | 450 |
181 buffer->clear_output (); | 451 buffer->clear_output (); |
182 count = buffer->len; | 452 count = buffer->len; |
183 for (buffer->idx = 0; buffer->idx < count;) | 453 for (buffer->idx = 0; buffer->idx < count;) |
184 { | 454 { |
185 unsigned int end; | 455 unsigned int end; |
186 for (end = buffer->idx + 1; end < count; end++) | 456 for (end = buffer->idx + 1; end < count; end++) |
187 if (buffer->cur().cluster != buffer->info[end].cluster) | 457 if (buffer->cur().cluster != buffer->info[end].cluster) |
188 break; | 458 break; |
189 | 459 |
190 if (buffer->idx + 1 == end) | 460 can_use_recompose = decompose_cluster (font, buffer, short_circuit, end) ||
can_use_recompose; |
191 decompose_single_char_cluster (font, buffer, recompose); | |
192 else { | |
193 decompose_multi_char_cluster (font, buffer, end); | |
194 has_multichar_clusters = true; | |
195 } | |
196 } | 461 } |
197 buffer->swap_buffers (); | 462 buffer->swap_buffers (); |
198 | 463 |
199 | 464 |
200 if (mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL && !has_multichar_clu
sters) | 465 if (mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL && !can_use_recompose
) |
201 return; /* Done! */ | 466 return; /* Done! */ |
202 | 467 |
203 | 468 |
204 /* Second round, reorder (inplace) */ | 469 /* Second round, reorder (inplace) */ |
205 | 470 |
206 count = buffer->len; | 471 count = buffer->len; |
207 for (unsigned int i = 0; i < count; i++) | 472 for (unsigned int i = 0; i < count; i++) |
208 { | 473 { |
209 if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0) | 474 if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0) |
210 continue; | 475 continue; |
(...skipping 10 matching lines...) Expand all Loading... |
221 i = end; | 486 i = end; |
222 continue; | 487 continue; |
223 } | 488 } |
224 | 489 |
225 hb_bubble_sort (buffer->info + i, end - i, compare_combining_class); | 490 hb_bubble_sort (buffer->info + i, end - i, compare_combining_class); |
226 | 491 |
227 i = end; | 492 i = end; |
228 } | 493 } |
229 | 494 |
230 | 495 |
231 if (!recompose) | 496 if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED) |
232 return; | 497 return; |
233 | 498 |
234 /* Third round, recompose */ | 499 /* Third round, recompose */ |
235 | 500 |
236 /* As noted in the comment earlier, we don't try to combine | 501 /* As noted in the comment earlier, we don't try to combine |
237 * ccc=0 chars with their previous Starter. */ | 502 * ccc=0 chars with their previous Starter. */ |
238 | 503 |
239 buffer->clear_output (); | 504 buffer->clear_output (); |
240 count = buffer->len; | 505 count = buffer->len; |
241 unsigned int starter = 0; | 506 unsigned int starter = 0; |
242 buffer->next_glyph (); | 507 buffer->next_glyph (); |
243 while (buffer->idx < count) | 508 while (buffer->idx < count) |
244 { | 509 { |
245 hb_codepoint_t composed, glyph; | 510 hb_codepoint_t composed, glyph; |
246 if (/* If mode is NOT COMPOSED_FULL (ie. it's COMPOSED_DIACRITICS), we don't
try to | 511 if (/* If mode is NOT COMPOSED_FULL (ie. it's COMPOSED_DIACRITICS), we don't
try to |
247 * compose a CCC=0 character with it's preceding starter. */ | 512 * compose a CCC=0 character with it's preceding starter. */ |
248 (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL || | 513 (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL || |
249 _hb_glyph_info_get_modified_combining_class (&buffer->cur()) != 0) && | 514 _hb_glyph_info_get_modified_combining_class (&buffer->cur()) != 0) && |
250 /* If there's anything between the starter and this char, they should ha
ve CCC | 515 /* If there's anything between the starter and this char, they should ha
ve CCC |
251 * smaller than this character's. */ | 516 * smaller than this character's. */ |
252 (starter == buffer->out_len - 1 || | 517 (starter == buffer->out_len - 1 || |
253 _hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_gly
ph_info_get_modified_combining_class (&buffer->cur())) && | 518 _hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_gly
ph_info_get_modified_combining_class (&buffer->cur())) && |
254 /* And compose. */ | 519 /* And compose. */ |
255 » hb_unicode_compose (buffer->unicode, | 520 » compose_func (buffer->unicode, |
256 » » » buffer->out_info[starter].codepoint, | 521 » » buffer->out_info[starter].codepoint, |
257 » » » buffer->cur().codepoint, | 522 » » buffer->cur().codepoint, |
258 » » » &composed) && | 523 » » &composed) && |
259 /* And the font has glyph for the composite. */ | 524 /* And the font has glyph for the composite. */ |
260 » hb_font_get_glyph (font, composed, 0, &glyph)) | 525 » font->get_glyph (composed, 0, &glyph)) |
261 { | 526 { |
262 /* Composes. Modify starter and carry on. */ | 527 /* Composes. */ |
263 buffer->out_info[starter].codepoint = composed; | 528 buffer->next_glyph (); /* Copy to out-buffer. */ |
264 /* XXX update cluster */ | 529 if (unlikely (buffer->in_error)) |
| 530 return; |
| 531 buffer->merge_out_clusters (starter, buffer->out_len); |
| 532 buffer->out_len--; /* Remove the second composable. */ |
| 533 buffer->out_info[starter].codepoint = composed; /* Modify starter and carr
y on. */ |
| 534 set_glyph (buffer->out_info[starter], font); |
265 _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unic
ode); | 535 _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unic
ode); |
266 | 536 |
267 buffer->skip_glyph (); | |
268 continue; | 537 continue; |
269 } | 538 } |
270 | 539 |
271 /* Blocked, or doesn't compose. */ | 540 /* Blocked, or doesn't compose. */ |
272 buffer->next_glyph (); | 541 buffer->next_glyph (); |
273 | 542 |
274 if (_hb_glyph_info_get_modified_combining_class (&buffer->prev()) == 0) | 543 if (_hb_glyph_info_get_modified_combining_class (&buffer->prev()) == 0) |
275 starter = buffer->out_len - 1; | 544 starter = buffer->out_len - 1; |
276 } | 545 } |
277 buffer->swap_buffers (); | 546 buffer->swap_buffers (); |
278 | 547 |
279 } | 548 } |
OLD | NEW |