hb-ot-shape-complex-indic.cc revision 2307268e01d27a999b56a2f573dfcee8b2a7949b
1b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod/* 227aba594c90b4444c35273a38f5fedc8e09d9a88Behdad Esfahbod * Copyright © 2011,2012 Google, Inc. 3b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 4b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * This is part of HarfBuzz, a text shaping library. 5b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 6b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * Permission is hereby granted, without written agreement and without 7b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this 8b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * software and its documentation for any purpose, provided that the 9b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * above copyright notice and the following two paragraphs appear in 10b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * all copies of this software. 11b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 12b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * DAMAGE. 17b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 18b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 24b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * Google Author(s): Behdad Esfahbod 25b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod */ 26b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 273ed4634ec349fa9e943ad23718c04be4dd4bba62Behdad Esfahbod#include "hb-ot-shape-complex-indic-private.hh" 2849c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod#include "hb-ot-layout-private.hh" 29352372ae5ea0998e40cf9fe43c22b6b610a5764eBehdad Esfahbod 303a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod/* buffer var allocations */ 313a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define indic_category() complex_var_u8_0() /* indic_category_t */ 323a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define indic_position() complex_var_u8_1() /* indic_position_t */ 333a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 343a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 353a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod/* 363a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Indic shaper. 373a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 383a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 393a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 403a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IN_HALF_BLOCK(u, Base) (((u) & ~0x7F) == (Base)) 413a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 423a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900)) 433a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980)) 443a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00)) 453a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80)) 463a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00)) 473a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80)) 483a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00)) 493a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80)) 503a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00)) 513a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80)) 523a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_KHMR(u) (IN_HALF_BLOCK (u, 0x1780)) 533a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 543a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 553a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define MATRA_POS_LEFT(u) POS_PRE_M 563a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define MATRA_POS_RIGHT(u) ( \ 573a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_DEVA(u) ? POS_AFTER_SUB : \ 583a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_BENG(u) ? POS_AFTER_POST : \ 593a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_GURU(u) ? POS_AFTER_POST : \ 603a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_GUJR(u) ? POS_AFTER_POST : \ 613a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_ORYA(u) ? POS_AFTER_POST : \ 623a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_TAML(u) ? POS_AFTER_POST : \ 633a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_TELU(u) ? (u <= 0x0C42 ? POS_BEFORE_SUB : POS_AFTER_SUB) : \ 643a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_KNDA(u) ? (u < 0x0CC3 || u > 0xCD6 ? POS_BEFORE_SUB : POS_AFTER_SUB) : \ 653a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_MLYM(u) ? POS_AFTER_POST : \ 663a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_SINH(u) ? POS_AFTER_SUB : \ 673a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_KHMR(u) ? POS_AFTER_POST : \ 683a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /*default*/ POS_AFTER_SUB \ 693a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod ) 703a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define MATRA_POS_TOP(u) ( /* BENG and MLYM don't have top matras. */ \ 713a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_DEVA(u) ? POS_AFTER_SUB : \ 723a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_GURU(u) ? POS_AFTER_POST : /* Deviate from spec */ \ 733a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_GUJR(u) ? POS_AFTER_SUB : \ 743a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_ORYA(u) ? POS_AFTER_MAIN : \ 753a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_TAML(u) ? POS_AFTER_SUB : \ 763a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_TELU(u) ? POS_BEFORE_SUB : \ 773a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_KNDA(u) ? POS_BEFORE_SUB : \ 783a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_SINH(u) ? POS_AFTER_SUB : \ 793a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_KHMR(u) ? POS_AFTER_POST : \ 803a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /*default*/ POS_AFTER_SUB \ 813a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod ) 823a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define MATRA_POS_BOTTOM(u) ( \ 833a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_DEVA(u) ? POS_AFTER_SUB : \ 843a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_BENG(u) ? POS_AFTER_SUB : \ 853a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_GURU(u) ? POS_AFTER_POST : \ 863a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_GUJR(u) ? POS_AFTER_POST : \ 873a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_ORYA(u) ? POS_AFTER_SUB : \ 883a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_TAML(u) ? POS_AFTER_POST : \ 893a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_TELU(u) ? POS_BEFORE_SUB : \ 903a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_KNDA(u) ? POS_BEFORE_SUB : \ 913a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_MLYM(u) ? POS_AFTER_POST : \ 923a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_SINH(u) ? POS_AFTER_SUB : \ 933a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_KHMR(u) ? POS_AFTER_POST : \ 943a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /*default*/ POS_AFTER_SUB \ 953a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod ) 963a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 973a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline indic_position_t 983a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodmatra_position (hb_codepoint_t u, indic_position_t side) 993a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1003a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod switch ((int) side) 1013a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 1023a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod case POS_PRE_C: return MATRA_POS_LEFT (u); 1033a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod case POS_POST_C: return MATRA_POS_RIGHT (u); 1043a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod case POS_ABOVE_C: return MATRA_POS_TOP (u); 1053a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod case POS_BELOW_C: return MATRA_POS_BOTTOM (u); 1063a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod }; 1073a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return side; 1083a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1093a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1103a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod/* XXX 1113a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * This is a hack for now. We should move this data into the main Indic table. 1123a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Or completely remove it and just check in the tables. 1133a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 1143a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic const hb_codepoint_t ra_chars[] = { 1153a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0930, /* Devanagari */ 1163a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x09B0, /* Bengali */ 1173a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x09F0, /* Bengali */ 1183a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0A30, /* Gurmukhi */ /* No Reph */ 1193a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0AB0, /* Gujarati */ 1203a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0B30, /* Oriya */ 1213a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0BB0, /* Tamil */ /* No Reph */ 1223a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0C30, /* Telugu */ /* Reph formed only with ZWJ */ 1233a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0CB0, /* Kannada */ 1243a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0D30, /* Malayalam */ /* No Reph, Logical Repha */ 1253a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1263a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0DBB, /* Sinhala */ /* Reph formed only with ZWJ */ 1273a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1283a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x179A, /* Khmer */ /* No Reph, Visual Repha */ 1293a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod}; 1303a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1313a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1323a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_ra (hb_codepoint_t u) 1333a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1343a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++) 1353a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (u == ra_chars[i]) 1363a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return true; 1373a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return false; 1383a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1393a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1403a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1413a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_one_of (const hb_glyph_info_t &info, unsigned int flags) 1423a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1433a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* If it ligated, all bets are off. */ 144a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod if (_hb_glyph_info_ligated (&info)) return false; 1453a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return !!(FLAG (info.indic_category()) & flags); 1463a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1473a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1483a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ)) 1493a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1503a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_joiner (const hb_glyph_info_t &info) 1513a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1523a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return is_one_of (info, JOINER_FLAGS); 1533a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1543a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 155c16012e9019ec59c2200a3cc29b8a37ea70eda70Behdad Esfahbod#define MEDIAL_FLAGS (FLAG (OT_CM) | FLAG (OT_CM2)) 156c16012e9019ec59c2200a3cc29b8a37ea70eda70Behdad Esfahbod 1573a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod/* Note: 1583a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * 1593a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels 1603a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * cannot happen in a consonant syllable. The plus side however is, we can call the 1613a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * consonant syllable logic from the vowel syllable function and get it all right! */ 162c16012e9019ec59c2200a3cc29b8a37ea70eda70Behdad Esfahbod#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE)) 1633a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1643a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_consonant (const hb_glyph_info_t &info) 1653a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1663a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return is_one_of (info, CONSONANT_FLAGS); 1673a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1683a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1693a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng)) 1703a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1713a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_halant_or_coeng (const hb_glyph_info_t &info) 1723a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1733a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return is_one_of (info, HALANT_OR_COENG_FLAGS); 1743a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1753a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1763a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline void 1773a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodset_indic_properties (hb_glyph_info_t &info) 1783a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1793a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod hb_codepoint_t u = info.codepoint; 1803a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod unsigned int type = hb_indic_get_categories (u); 1813a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod indic_category_t cat = (indic_category_t) (type & 0x7F); 1823a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod indic_position_t pos = (indic_position_t) (type >> 8); 1833a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1843a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1853a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* 1863a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Re-assign category 1873a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 1883a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1893a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1903a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe 191c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod * treats a whole bunch of characters similarly. 192c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod * TESTS: For example, for U+0951: 1933a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * U+092E,U+0947,U+0952 1943a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * U+092E,U+0952,U+0947 1953a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * U+092E,U+0947,U+0951 1963a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * U+092E,U+0951,U+0947 197c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod * U+092E,U+0951,U+0952 198c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod * U+092E,U+0952,U+0951 1993756efaf4e14ec3b5b1def700a1b5985f162372bBehdad Esfahbod */ 200c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0x0951, 0x0952, 201e848bfae7c975a6fae434daf8e3db4d69914df9fBehdad Esfahbod 0x1CD0, 0x1CD2, 20272ead0cc72dac4d1c985ead065bb820f93f14a1dBehdad Esfahbod 0x1CD4, 0x1CE1) || 20337bf2c9224e32fdc99c20158c6dc0a4602ec1292Behdad Esfahbod u == 0x1CF4)) 20426c836e53d55a2e2d4c17fd9ea1884eec33ce015Behdad Esfahbod cat = OT_A; 205c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod /* The following act more like the Bindus. */ 206c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0953, 0x0954))) 207c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod cat = OT_SM; 208e848bfae7c975a6fae434daf8e3db4d69914df9fBehdad Esfahbod /* Cantillation marks. */ 209e848bfae7c975a6fae434daf8e3db4d69914df9fBehdad Esfahbod else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xA8E0, 0xA8F1))) 210e848bfae7c975a6fae434daf8e3db4d69914df9fBehdad Esfahbod cat = OT_VD; 211131e17ff9ae792cafa7a500043acb373802ee872Behdad Esfahbod /* The following act like consonants. */ 2122307268e01d27a999b56a2f573dfcee8b2a7949bBehdad Esfahbod else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0x0A72, 0x0A73, 2132307268e01d27a999b56a2f573dfcee8b2a7949bBehdad Esfahbod 0x1CF5, 0x1CF6))) 214131e17ff9ae792cafa7a500043acb373802ee872Behdad Esfahbod cat = OT_C; 215ecb98babbaa065940b40ca8954a454f0e2cdcff0Behdad Esfahbod /* TODO: The following should only be allowed after a Visarga. 216ecb98babbaa065940b40ca8954a454f0e2cdcff0Behdad Esfahbod * For now, just treat them like regular tone marks. */ 217ecb98babbaa065940b40ca8954a454f0e2cdcff0Behdad Esfahbod else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1CE2, 0x1CE8))) 218ecb98babbaa065940b40ca8954a454f0e2cdcff0Behdad Esfahbod cat = OT_A; 219e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod /* TODO: The following should only be allowed after some of 220e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod * the nasalization marks, maybe only for U+1CE9..U+1CF1. 221e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod * For now, just treat them like tone marks. */ 222e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod else if (unlikely (u == 0x1CED)) 223e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod cat = OT_A; 224a498565cedf0441ae723c5e5969f637d792a15e7Behdad Esfahbod /* The following are Visarga variants. */ 225a498565cedf0441ae723c5e5969f637d792a15e7Behdad Esfahbod else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1CF2, 0x1CF3))) 226a498565cedf0441ae723c5e5969f637d792a15e7Behdad Esfahbod { 227a498565cedf0441ae723c5e5969f637d792a15e7Behdad Esfahbod cat = OT_SM; 228a498565cedf0441ae723c5e5969f637d792a15e7Behdad Esfahbod ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_VISARGA == OT_SM); 229a498565cedf0441ae723c5e5969f637d792a15e7Behdad Esfahbod } 230d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod /* The following take marks in standalone clusters, similar to Avagraha. */ 231d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0xA8F2, 0xA8F7, 232d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod 0x1CE9, 0x1CEC, 233d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod 0x1CEE, 0x1CF1))) 234d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod { 235d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod cat = OT_Symbol; 236d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol); 237d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod } 2383a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2393a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (unlikely (u == 0x17D1)) 2403a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_X; 2413a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (cat == OT_X && 2420682ddd05c22a400ff5ce97d4ea4b52a18b845aeBehdad Esfahbod unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CB, 0x17D3) || 2430682ddd05c22a400ff5ce97d4ea4b52a18b845aeBehdad Esfahbod u == 0x17DD)) /* Khmer Various signs */ 2443a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2453a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* These are like Top Matras. */ 2463a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_M; 2473a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = POS_ABOVE_C; 2483a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2493a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (u == 0x17C6) /* Khmer Bindu doesn't like to be repositioned. */ 2503a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_N; 2513a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2523a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (unlikely (u == 0x17D2)) cat = OT_Coeng; /* Khmer coeng */ 2533a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (unlikely (u == 0x200C)) cat = OT_ZWNJ; 2543a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (unlikely (u == 0x200D)) cat = OT_ZWJ; 2553a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (unlikely (u == 0x25CC)) cat = OT_DOTTEDCIRCLE; 2563756efaf4e14ec3b5b1def700a1b5985f162372bBehdad Esfahbod else if (unlikely (u == 0x0A71)) cat = OT_SM; /* GURMUKHI ADDAK. Move it to the end. */ 257c16012e9019ec59c2200a3cc29b8a37ea70eda70Behdad Esfahbod else if (unlikely (u == 0xA982)) cat = OT_SM; /* Javanese repha. */ 258c16012e9019ec59c2200a3cc29b8a37ea70eda70Behdad Esfahbod else if (unlikely (u == 0xA9BE)) cat = OT_CM2; /* Javanese medial ya. */ 259c16012e9019ec59c2200a3cc29b8a37ea70eda70Behdad Esfahbod else if (unlikely (u == 0xA9BD)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */ 2603a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2613a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (cat == OT_Repha) { 2623a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* There are two kinds of characters marked as Repha: 2633a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * - The ones that are GenCat=Mn are already positioned visually, ie. after base. (eg. Khmer) 2643a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * - The ones that are GenCat=Lo is encoded logically, ie. beginning of syllable. (eg. Malayalam) 2653a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * 2663a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * We recategorize the first kind to look like a Nukta and attached to the base directly. 2673a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 2683a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (_hb_glyph_info_get_general_category (&info) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 2693a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_N; 2703a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2713a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2723a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2733a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2743a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* 2753a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Re-assign position. 2763a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 2773a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2783a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if ((FLAG (cat) & CONSONANT_FLAGS)) 2793a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 280c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod pos = POS_BASE_C; 2813a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (is_ra (u)) 2823a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_Ra; 2833a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2843a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (cat == OT_M) 2853a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2863a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = matra_position (u, pos); 2873a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2889f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol)))) 2893a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2903a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = POS_SMVD; 2913a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2923a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2933a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (unlikely (u == 0x0B01)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */ 2943a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2953a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2963a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2973a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod info.indic_category() = cat; 2983a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod info.indic_position() = pos; 2993a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 3003a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 3013a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod/* 3023a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Things above this line should ideally be moved to the Indic table itself. 3033a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 3043a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 3051d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 30611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 30711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic configurations. Note that we do not want to keep every single script-specific 30811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * behavior in these tables necessarily. This should mainly be used for per-script 30911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * properties that are cheaper keeping here, than in the code. Ie. if, say, one and 31011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * only one script has an exception, that one script can be if'ed directly in the code, 31111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * instead of adding a new flag in these structs. 31211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 31311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 31411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum base_position_t { 31511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_FIRST, 316e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod BASE_POS_LAST_SINHALA, 31711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_LAST 31811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 31911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_position_t { 32011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_MAIN = POS_AFTER_MAIN, 32111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_SUB = POS_BEFORE_SUB, 32211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_SUB = POS_AFTER_SUB, 32311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_POST = POS_BEFORE_POST, 32474f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod REPH_POS_AFTER_POST = POS_AFTER_POST, 32574f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod REPH_POS_DONT_CARE = POS_RA_TO_BECOME_REPH 32611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 32711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_mode_t { 32811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_IMPLICIT, /* Reph formed out of initial Ra,H sequence. */ 32911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_EXPLICIT, /* Reph formed out of initial Ra,H,ZWJ sequence. */ 33011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */ 33111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_LOG_REPHA /* Encoded Repha character, needs reordering. */ 33211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 3338acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbodenum blwf_mode_t { 3348acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod BLWF_MODE_PRE_AND_POST, /* Below-forms feature applied to pre-base and post-base. */ 3358acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod BLWF_MODE_POST_ONLY /* Below-forms feature applied to post-base only. */ 3368acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod}; 33774f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbodenum pref_len_t { 33874f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod PREF_LEN_1 = 1, 33974f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod PREF_LEN_2 = 2, 34074f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod PREF_LEN_DONT_CARE = PREF_LEN_2 34174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod}; 34211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstruct indic_config_t 34311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 34411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_script_t script; 34511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool has_old_spec; 34611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_codepoint_t virama; 34711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base_position_t base_pos; 34811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos; 34911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_mode_t reph_mode; 3508acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod blwf_mode_t blwf_mode; 35174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod pref_len_t pref_len; 35211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 35311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 35411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstatic const indic_config_t indic_configs[] = 35511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 35611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Default. Should be first. */ 35774f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1}, 35874f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 35974f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_BENGALI, true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 36074f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_GURMUKHI, true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 36174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_GUJARATI, true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 36274f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_ORIYA, true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 36374f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_TAMIL, true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, 36474f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_TELUGU, true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2}, 36574f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_KANNADA, true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2}, 36674f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, 367e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod {HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_LAST_SINHALA, 36874f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 36974f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, 3708f9ec92dfce5c469fb85ad301296b5dde1b2ab0aBehdad Esfahbod {HB_SCRIPT_JAVANESE, false,0xA9C0,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1}, 37111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 37211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 37311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 37411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 37511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 37611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic shaper. 37711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 3789ccc6382ba43760167c134c18c1c4ada4b8c3f22Behdad Esfahbod 379eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstruct feature_list_t { 380c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_tag_t tag; 381ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod hb_ot_map_feature_flags_t flags; 382eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod}; 383eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 384eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstatic const feature_list_t 38585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodindic_features[] = 386b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 38785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 38885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Basic features. 38985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied in order, one at a time, after initial_reordering. 39085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 391a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('n','u','k','t'), F_GLOBAL}, 392a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('a','k','h','n'), F_GLOBAL}, 393a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('r','p','h','f'), F_NONE}, 394a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('r','k','r','f'), F_GLOBAL}, 395a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('p','r','e','f'), F_NONE}, 396a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('b','l','w','f'), F_NONE}, 397a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('a','b','v','f'), F_NONE}, 398a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod {HB_TAG('h','a','l','f'), F_NONE}, 399a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('p','s','t','f'), F_NONE}, 400a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('v','a','t','u'), F_GLOBAL}, 401a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('c','j','c','t'), F_GLOBAL}, 402a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod {HB_TAG('c','f','a','r'), F_NONE}, 40385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 40485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Other features. 40585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied all at once, after final_reordering. 406a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod * Default Bengali font in Windows for example has intermixed 407a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod * lookups for init,pres,abvs,blws features. 40885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 409ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('i','n','i','t'), F_NONE}, 410ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('p','r','e','s'), F_GLOBAL}, 411ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('a','b','v','s'), F_GLOBAL}, 412ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('b','l','w','s'), F_GLOBAL}, 413ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('p','s','t','s'), F_GLOBAL}, 414ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('h','a','l','n'), F_GLOBAL}, 41585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* Positioning features, though we don't care about the types. */ 416ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('d','i','s','t'), F_GLOBAL}, 417ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('a','b','v','m'), F_GLOBAL}, 418ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('b','l','w','m'), F_GLOBAL}, 419c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod}; 420c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod 42185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod/* 42285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Must be in the same order as the indic_features array. 42385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 424c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbodenum { 425c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod _NUKT, 426e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod _AKHN, 427c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod RPHF, 428df6d45c693c417bf311e6fa49f18a8558542e525Behdad Esfahbod _RKRF, 429c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PREF, 430167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod BLWF, 43129f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod ABVF, 432a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod HALF, 433c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PSTF, 43485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _VATU, 43570d656571194d2bd32671244530edbe159722cecBehdad Esfahbod _CJCT, 436a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod CFAR, 43785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 43885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INIT, 43985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PRES, 44085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVS, 44185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWS, 44285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PSTS, 44385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _HALN, 44485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _DIST, 44585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVM, 44685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWM, 44785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 44885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_NUM_FEATURES, 44985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */ 450b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod}; 451b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 452743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 453166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan, 454166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font, 455166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer); 456166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 4578bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 458afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 4593e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 460f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbodstatic void 4618bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 462afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 4633e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 46430145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbodstatic void 46530145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbodclear_syllables (const hb_ot_shape_plan_t *plan, 46630145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_font_t *font, 46730145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_buffer_t *buffer); 468b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 469693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 47016c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodcollect_features_indic (hb_ot_shape_planner_t *plan) 471b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 47216c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_ot_map_builder_t *map = &plan->map; 47316c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod 474166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Do this before any lookups have been applied. */ 475166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod map->add_gsub_pause (setup_syllables); 476166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 477e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod map->add_global_bool_feature (HB_TAG('l','o','c','l')); 478a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod /* The Indic specs do not require ccmp, but we apply it here since if 479a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod * there is a use of it, it's typically at the beginning. */ 480e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod map->add_global_bool_feature (HB_TAG('c','c','m','p')); 481f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 482f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 48385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod unsigned int i = 0; 48485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_gsub_pause (initial_reordering); 48585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_BASIC_FEATURES; i++) { 486a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ); 4873e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (NULL); 488412b91889d9a1ae477e8b6907d0b9a76e78a6c91Behdad Esfahbod } 4893e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (final_reordering); 49085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_NUM_FEATURES; i++) { 491a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ); 49285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 49342d0f55cbc68285e22d713df7062e520af708c82Behdad Esfahbod 49442d0f55cbc68285e22d713df7062e520af708c82Behdad Esfahbod map->add_global_bool_feature (HB_TAG('c','a','l','t')); 49542d0f55cbc68285e22d713df7062e520af708c82Behdad Esfahbod map->add_global_bool_feature (HB_TAG('c','l','i','g')); 49642d0f55cbc68285e22d713df7062e520af708c82Behdad Esfahbod 49730145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod map->add_gsub_pause (clear_syllables); 498b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 499b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 500693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 50116c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodoverride_features_indic (hb_ot_shape_planner_t *plan) 502d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod{ 503eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod /* Uniscribe does not apply 'kern' in Khmer. */ 504bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 505eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod { 506eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod switch ((hb_tag_t) plan->props.script) 507eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod { 508eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod case HB_SCRIPT_KHMER: 5099ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL); 510eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod break; 511eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod } 512eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod } 5136b389ddc3623d042ded4731f4d62dc354002fdd0Behdad Esfahbod 514ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); 515d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod} 516d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod 517867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 51885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodstruct would_substitute_feature_t 519a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 520b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) 521a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 522b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod zero_context = zero_context_; 523a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_stage_lookups (0/*GSUB*/, 524a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_feature_stage (0/*GSUB*/, feature_tag), 525a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod &lookups, &count); 526a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 527a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 5288144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod inline bool would_substitute (const hb_codepoint_t *glyphs, 5298144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod unsigned int glyphs_count, 5308144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod hb_face_t *face) const 531a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 532a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 533362a990b2246f5448ecb9d600761f710aea7d42dBehdad Esfahbod if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) 534a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return true; 535a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return false; 536a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 537a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 538a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod private: 539a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const hb_ot_map_t::lookup_map_t *lookups; 540a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int count; 541b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod bool zero_context; 542a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 543a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 544a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstruct indic_shape_plan_t 545a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 54685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod ASSERT_POD (); 547914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 548914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const 549914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 550914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod hb_codepoint_t glyph = virama_glyph; 551914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (unlikely (virama_glyph == (hb_codepoint_t) -1)) 552914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 55311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!config->virama || !font->get_glyph (config->virama, 0, &glyph)) 554914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod glyph = 0; 555914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Technically speaking, the spec says we should apply 'locl' to virama too. 556914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * Maybe one day... */ 557914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 558914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Our get_glyph() function needs a font, so we can't get the virama glyph 559914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */ 560914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph; 561914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 562914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 563914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod *pglyph = glyph; 564914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod return glyph != 0; 565914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 56685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 56711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod const indic_config_t *config; 56885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 56985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod bool is_old_spec; 57085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_codepoint_t virama_glyph; 57185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 572f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod would_substitute_feature_t rphf; 57385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pref; 57485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t blwf; 57585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pstf; 57685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 57785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_mask_t mask_array[INDIC_NUM_FEATURES]; 578a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 579a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 580a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void * 581a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_create_indic (const hb_ot_shape_plan_t *plan) 582a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 58385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t)); 58485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (unlikely (!indic_plan)) 585a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return NULL; 586a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 58711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[0]; 58811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++) 58911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (plan->props.script == indic_configs[i].script) { 59011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[i]; 59111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 59285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 59311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 594851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2'); 59511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->virama_glyph = (hb_codepoint_t) -1; 59685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 597b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod /* Use zero-context would_substitute() matching for new-spec of the main 598828e109c7aac3389cc3b89ea1f13388aefb63804Behdad Esfahbod * Indic scripts, and scripts with one spec only, but not for old-specs. */ 599828e109c7aac3389cc3b89ea1f13388aefb63804Behdad Esfahbod bool zero_context = !indic_plan->is_old_spec; 600b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context); 601b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context); 602b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context); 603b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context); 60485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 60585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) 606ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ? 607ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod 0 : plan->map.get_1_mask (indic_features[i].tag); 608a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 60985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod return indic_plan; 610a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 611a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 612a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void 613a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_destroy_indic (void *data) 614a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 615a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod free (data); 616a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 617a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 618a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic indic_position_t 619a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodconsonant_position_from_face (const indic_shape_plan_t *indic_plan, 620684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod const hb_codepoint_t consonant, 621684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod const hb_codepoint_t virama, 6228144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod hb_face_t *face) 623a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 6248144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod /* For old-spec, the order of glyphs is Consonant,Virama, 6258144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * whereas for new-spec, it's Virama,Consonant. However, 6268144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * some broken fonts (like Free Sans) simply copied lookups 6278144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * from old-spec to new-spec without modification. 6288144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * And oddly enough, Uniscribe seems to respect those lookups. 6298144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds 6308144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * base at 0. The font however, only has lookups matching 6318144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * 930,94D in 'blwf', not the expected 94D,930 (with new-spec 6328144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * table). As such, we simply match both sequences. Seems 6338144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * to work. */ 634684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod hb_codepoint_t glyphs[3] = {virama, consonant, virama}; 635b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod if (indic_plan->blwf.would_substitute (glyphs , 2, face) || 636684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod indic_plan->blwf.would_substitute (glyphs+1, 2, face)) 6378144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod return POS_BELOW_C; 638b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod if (indic_plan->pstf.would_substitute (glyphs , 2, face) || 639684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod indic_plan->pstf.would_substitute (glyphs+1, 2, face)) 6408144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod return POS_POST_C; 64174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod unsigned int pref_len = indic_plan->config->pref_len; 64274f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod if ((pref_len == PREF_LEN_2 && 64374f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod (indic_plan->pref.would_substitute (glyphs , 2, face) || 64474f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod indic_plan->pref.would_substitute (glyphs+1, 2, face))) 64574f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod || (pref_len == PREF_LEN_1 && 64674f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod indic_plan->pref.would_substitute (glyphs+1, 1, face))) 647ae9a5834df477006686421d494b55a1569789327Behdad Esfahbod return POS_POST_C; 648a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return POS_BASE_C; 649a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 650a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 651a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 652166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodenum syllable_type_t { 653166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod consonant_syllable, 654166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod vowel_syllable, 655166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod standalone_cluster, 6569f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod symbol_cluster, 657166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod broken_cluster, 658166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod non_indic_cluster, 659166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod}; 660166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 661166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod#include "hb-ot-shape-complex-indic-machine.hh" 662166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 663166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 664693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 66516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodsetup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, 66616c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_buffer_t *buffer, 66716c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_font_t *font HB_UNUSED) 66824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 66924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); 67024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); 67124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 67224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod /* We cannot setup masks here. We save information about characters 67324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod * and setup masks later on in a pause-callback. */ 67424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 67524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod unsigned int count = buffer->len; 67624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 67724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod set_indic_properties (buffer->info[i]); 67824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 67924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 680166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 681166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, 682166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font HB_UNUSED, 683166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer) 684166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod{ 685166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod find_syllables (buffer); 686166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod} 687166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 68824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic int 68924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodcompare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 69024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 69124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int a = pa->indic_position(); 69224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int b = pb->indic_position(); 69324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 69424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod return a < b ? -1 : a == b ? 0 : +1; 69524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 69624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 69724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 69824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 69924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic void 7008bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodupdate_consonant_positions (const hb_ot_shape_plan_t *plan, 70185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 70285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer) 7038ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod{ 704a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 7058ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 706c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod if (indic_plan->config->base_pos != BASE_POS_LAST) 707c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod return; 708c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod 709684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod hb_codepoint_t virama; 710684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod if (indic_plan->get_virama_glyph (font, &virama)) 7118ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod { 7128ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_face_t *face = font->face; 7138ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod unsigned int count = buffer->len; 7148ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 7158ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod if (buffer->info[i].indic_position() == POS_BASE_C) { 716684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod hb_codepoint_t consonant = buffer->info[i].codepoint; 717684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face); 7188ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 7198ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 7208ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod} 7218ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 722867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 7237ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod/* Rules from: 7247ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ 7257ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod 726743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 727f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbodinitial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, 728f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 729f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_buffer_t *buffer, 730ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 731743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 732914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 733ee58f3bc75d2d071a71b94063bf12205a5871acbBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 734743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 735617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod 736743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 1. Find base consonant: 737743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 738743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The shaping engine finds the base consonant of the syllable, using the 739743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following algorithm: starting from the end of the syllable, move backwards 740743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * until a consonant is found that does not have a below-base or post-base 741743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * form (post-base forms have to follow below-base forms), or that is not a 742743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * pre-base reordering Ra, or arrive at the first consonant. The consonant 743743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * stopped at will be the base. 744743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 745743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o If the syllable starts with Ra + Halant (in a script that has Reph) 746743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 747743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * base consonants. 748743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 749743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 7505e72071062c015237b79fbd0521341a63166a204Behdad Esfahbod unsigned int base = end; 75176b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod bool has_reph = false; 752743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 75376b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod { 754617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 755617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 756617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * base consonants. */ 757617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod unsigned int limit = start; 758f175aa33c5e94397c60648ac0697c80f5fe0dcb7Behdad Esfahbod if (indic_plan->config->reph_pos != REPH_POS_DONT_CARE && 759efed40b975110d78c9c505441e7e17a8c13e85c8Behdad Esfahbod indic_plan->mask_array[RPHF] && 760617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod start + 3 <= end && 7618b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod ( 76211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || 76311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ) 7643285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod )) 765617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod { 766f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod /* See if it matches the 'rphf' feature. */ 76729531128f2f4342d537817746863705df80efe4bBehdad Esfahbod hb_codepoint_t glyphs[3] = {info[start].codepoint, 76829531128f2f4342d537817746863705df80efe4bBehdad Esfahbod info[start + 1].codepoint, 76929531128f2f4342d537817746863705df80efe4bBehdad Esfahbod indic_plan->config->reph_mode == REPH_MODE_EXPLICIT ? 77029531128f2f4342d537817746863705df80efe4bBehdad Esfahbod info[start + 2].codepoint : 0}; 77129531128f2f4342d537817746863705df80efe4bBehdad Esfahbod if (indic_plan->rphf.would_substitute (glyphs, 2, face) || 77229531128f2f4342d537817746863705df80efe4bBehdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && 77329531128f2f4342d537817746863705df80efe4bBehdad Esfahbod indic_plan->rphf.would_substitute (glyphs, 3, face))) 774f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod { 775f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit += 2; 776f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 777f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit++; 778f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod base = start; 779f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod has_reph = true; 780f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod } 7818b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha) 7828b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod { 7838b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod limit += 1; 7848b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 7858b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod limit++; 7868b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod base = start; 7878b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod has_reph = true; 7888b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod } 78976b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod 79023b0e9d7dc801e11640979af3c2b00649a519bb1Behdad Esfahbod switch (indic_plan->config->base_pos) 7915d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 792d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod default: 793d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod assert (false); 794d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod /* fallthrough */ 795d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod 79611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_LAST: 79711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 79811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> starting from the end of the syllable, move backwards */ 79911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int i = end; 80011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool seen_below = false; 80111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod do { 80211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod i--; 80311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> until a consonant is found */ 80411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i])) 8055d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 80611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> that does not have a below-base or post-base form 80711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * (post-base forms have to follow below-base forms), */ 80811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() != POS_BELOW_C && 80911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (info[i].indic_position() != POS_POST_C || seen_below)) 81011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 81111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 81211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 81311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 81411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() == POS_BELOW_C) 81511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod seen_below = true; 81611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 81711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or that is not a pre-base reordering Ra, 81811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 81911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * IMPLEMENTATION NOTES: 82011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 821fb7c182bf92142540bff1ad7fb82de0d115fb2b5Behdad Esfahbod * Our pre-base reordering Ra's are marked POS_POST_C, so will be skipped 82211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * by the logic above already. 82311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 82411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 82511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or arrive at the first consonant. The consonant stopped at will 82611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * be the base. */ 8275d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod base = i; 8285d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 82911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 83011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 83111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* A ZWJ after a Halant stops the base search, and requests an explicit 83211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * half form. 83311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * A ZWJ before a Halant, requests a subjoined form instead, and hence 83411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * search continues. This is particularly important for Bengali 835c4be9917438c45b972ec76dc68409014110f0837Behdad Esfahbod * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */ 83611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (start < i && 83711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_category() == OT_ZWJ && 83811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i - 1].indic_category() == OT_H) 83911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 84011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 84111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } while (i > limit); 84211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 84311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 8445d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 845e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod case BASE_POS_LAST_SINHALA: 84611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 847c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod /* Sinhala base positioning is slightly different from main Indic, in that: 848b082ef373cefb35dd98b5f2f0b677ccc7806f51eBehdad Esfahbod * 1. Its ZWJ behavior is different, 849c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod * 2. We don't need to look into the font for consonant positions. 850c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod */ 8515d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 85211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!has_reph) 85311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = limit; 85434c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 85511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Find the last base consonant that is not blocked by ZWJ. If there is 85611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * a ZWJ right before a base consonant, that would request a subjoined form. */ 85711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = limit; i < end; i++) 858c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod if (is_consonant (info[i])) 85911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 86011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (limit < i && info[i - 1].indic_category() == OT_ZWJ) 86111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 86211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 86311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 86411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 86534c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 86611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Mark all subsequent consonants as below. */ 86711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 868c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod if (is_consonant (info[i])) 86911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_position() = POS_BELOW_C; 87011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 87111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 872e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod 873e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod case BASE_POS_FIRST: 874e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod { 875e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod /* The first consonant is always the base. */ 876e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod 877e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod assert (indic_plan->config->reph_mode == REPH_MODE_VIS_REPHA); 878efed40b975110d78c9c505441e7e17a8c13e85c8Behdad Esfahbod assert (!has_reph); 879e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod 880e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod base = start; 881e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod 882e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod /* Mark all subsequent consonants as below. */ 883e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 884c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod if (is_consonant (info[i])) 885e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod info[i].indic_position() = POS_BELOW_C; 886e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod } 887e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod break; 8885d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 889743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 890617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 891617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 8922278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * base consonants. 8932278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * 8942278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ 8959621e0ba294c9cc6d458bbf632e63e92fda71e10Behdad Esfahbod if (has_reph && base == start && limit - base <= 2) { 896617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* Have no other consonant, so Reph is not formed and Ra becomes base. */ 897617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = false; 898617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod } 8995e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod } 9002278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod 9013d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 902743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 2. Decompose and reorder Matras: 903743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 904743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Each matra and any syllable modifier sign in the cluster are moved to the 905743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * appropriate position relative to the consonant(s) in the cluster. The 906743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * shaping engine decomposes two- or three-part matras into their constituent 907743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * parts before any repositioning. Matra characters are classified by which 908743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * consonant in a conjunct they have affinity for and are reordered to the 909743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following positions: 910743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 911743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o Before first half form in the syllable 912743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After subjoined consonants 913743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After post-form consonant 914743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After main consonant (for above marks) 915743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 916743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 917743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 918743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The normalize() routine has already decomposed matras for us, so we don't 919743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * need to worry about that. 920743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 921743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 922743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 923743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 3. Reorder marks to canonical order: 924743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 925743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Adjacent nukta and halant or nukta and vedic sign are always repositioned 926743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * if necessary, so that the nukta is first. 927743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 928743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 929743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 930743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * We don't need to do this: the normalize() routine already did this for us. 931743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 932743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 933743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 93445d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod /* Reorder characters */ 93545d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 9363c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 937900cf3d449bf36d4f8b1474590cae925fef48fc8Behdad Esfahbod info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position()); 93855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 939075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 940075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].indic_position() = POS_BASE_C; 94145d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 94255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod /* Mark final consonants. A final consonant is one appearing after a matra, 94355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod * like in Khmer. */ 94455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 94555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (info[i].indic_category() == OT_M) { 94655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int j = i + 1; j < end; j++) 94755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (is_consonant (info[j])) { 94855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod info[j].indic_position() = POS_FINAL_C; 94955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 95055f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 95155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 95255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 95355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 954fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod /* Handle beginning Ra */ 9555e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod if (has_reph) 956dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() = POS_RA_TO_BECOME_REPH; 957fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod 958f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* For old-style Indic script tags, move the first post-base Halant after 959ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod * last consonant. Only do this if there is *not* a Halant after last 960ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod * consonant. Otherwise it becomes messy. */ 961914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->is_old_spec) { 9623c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 963f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (info[i].indic_category() == OT_H) { 964f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod unsigned int j; 965f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod for (j = end - 1; j > i; j--) 966ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod if (is_consonant (info[j]) || info[j].indic_category() == OT_H) 967f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 968ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod if (info[j].indic_category() != OT_H && j > i) { 969f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* Move Halant to after last consonant. */ 970f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod hb_glyph_info_t t = info[i]; 971f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); 972f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod info[j] = t; 973f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 974f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 975f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 976f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 977f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod 97881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* Attach misc marks to previous char to move with them. */ 979ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 98081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod indic_position_t last_pos = POS_START; 98181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod for (unsigned int i = start; i < end; i++) 98281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 983c16012e9019ec59c2200a3cc29b8a37ea70eda70Behdad Esfahbod if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS))) 98481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 98581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() = last_pos; 986dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod if (unlikely (info[i].indic_category() == OT_H && 98781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() == POS_PRE_M)) 98881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 98981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* 99081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * Uniscribe doesn't move the Halant with Left Matra. 99181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * TEST: U+092B,U+093F,U+094DE 992dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We follow. This is important for the Sinhala 993dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA 994dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * where U+0DD9 is a left matra and U+0DCA is the virama. 995dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We don't want to move the virama with the left matra. 996dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * TEST: U+0D9A,U+0DDA 99781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod */ 998ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod for (unsigned int j = i; j > start; j--) 9996a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[j - 1].indic_position() != POS_PRE_M) { 1000ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod info[i].indic_position() = info[j - 1].indic_position(); 1001ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod break; 1002ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 100381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 100481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } else if (info[i].indic_position() != POS_SMVD) { 100581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod last_pos = (indic_position_t) info[i].indic_position(); 1006ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 100781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 1008ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 1009ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod /* For post-base consonants let them own anything before them 1010ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod * since the last consonant or matra. */ 101174ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod { 1012ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod unsigned int last = base; 101374ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 1014ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod if (is_consonant (info[i])) 1015ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod { 1016ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod for (unsigned int j = last + 1; j < i; j++) 1017ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod if (info[j].indic_position() < POS_SMVD) 101881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[j].indic_position() = info[i].indic_position(); 1019ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod last = i; 1020ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod } else if (info[i].indic_category() == OT_M) 1021ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod last = i; 102274ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 102345d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 102428d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod 1025a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod { 102628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod /* Use syllable() for sort accounting temporarily. */ 102728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod unsigned int syllable = info[start].syllable(); 102828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod for (unsigned int i = start; i < end; i++) 102928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod info[i].syllable() = i - start; 103028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod 1031a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Sit tight, rock 'n roll! */ 1032d3637edb248162970e202e9d0671540274192844Behdad Esfahbod hb_bubble_sort (info + start, end - start, compare_indic_order); 1033a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Find base again */ 1034a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = end; 10353c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < end; i++) 103628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod if (info[i].indic_position() == POS_BASE_C) 103728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod { 103828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod base = i; 1039a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod break; 1040a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 104128d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod /* Things are out-of-control for post base positions, they may shuffle 104228d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod * around like crazy. In old-spec mode, we move halants around, so in 104328d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod * that case merge all clusters after base. Otherwise, check the sort 104428d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod * order and merge as needed. 104528d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod * For pre-base stuff, we handle cluster issues in final reordering. */ 104628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod if (indic_plan->is_old_spec || end - base > 127) 104728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod buffer->merge_clusters (base, end); 104828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod else 104928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod { 105028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod /* Note! syllable() is a one-byte field. */ 105128d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod for (unsigned int i = base; i < end; i++) 105228d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod if (info[i].syllable() != 255) 105328d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod { 105428d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod unsigned int max = i; 105528d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod unsigned int j = start + info[i].syllable(); 105628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod while (j != i) 105728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod { 105828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod max = MAX (max, j); 105928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod unsigned int next = start + info[j].syllable(); 106028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod info[j].syllable() = 255; /* So we don't process j later again. */ 106128d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod j = next; 106228d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod } 106328d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod if (i != max) 106428d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod buffer->merge_clusters (i, max + 1); 106528d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod } 106628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod } 106728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod 106828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod /* Put syllable back in. */ 106928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod for (unsigned int i = start; i < end; i++) 107028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod info[i].syllable() = syllable; 1071a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 107245d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 1073743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Setup masks now */ 1074743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1075281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod { 1076281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod hb_mask_t mask; 1077281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod 1078dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* Reph */ 1079668c6046c1b3af3bd316bda0cc8636f2a5e8df42Behdad Esfahbod for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) 108085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[RPHF]; 1081dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1082281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Pre-base */ 108385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[HALF]; 1084c7dacac02cfe8526eaf131ce6c5e7b6df7ca2ccdBehdad Esfahbod if (!indic_plan->is_old_spec && 1085c7dacac02cfe8526eaf131ce6c5e7b6df7ca2ccdBehdad Esfahbod indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST) 10868acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod mask |= indic_plan->mask_array[BLWF]; 10873c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 1088281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 1089281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Base */ 109020b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = 0; 1091075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 1092075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].mask |= mask; 1093281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Post-base */ 109485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF]; 10953c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 1096281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 1097281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod } 10989da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 109985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod if (indic_plan->is_old_spec && 110085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod buffer->props.script == HB_SCRIPT_DEVANAGARI) 110185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod { 110285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod /* Old-spec eye-lash Ra needs special handling. From the 110385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * spec: 110485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 110585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * "The feature 'below-base form' is applied to consonants 110685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * having below-base forms and following the base consonant. 110785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * The exception is vattu, which may appear below half forms 110885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * as well as below the base glyph. The feature 'below-base 110985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * form' will be applied to all such occurrences of Ra as well." 111085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 111185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * Test case: U+0924,U+094D,U+0930,U+094d,U+0915 111285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * with Sanskrit 2003 font. 111385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 111485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * However, note that Ra,Halant,ZWJ is the correct way to 111585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * request eyelash form of Ra, so we wouldbn't inhibit it 111685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * in that sequence. 111785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 111885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915 111985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod */ 112085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod for (unsigned int i = start; i + 1 < base; i++) 112185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod if (info[i ].indic_category() == OT_Ra && 112285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+1].indic_category() == OT_H && 112385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod (i + 2 == base || 112485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+2].indic_category() != OT_ZWJ)) 112585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod { 112685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i ].mask |= indic_plan->mask_array[BLWF]; 112785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+1].mask |= indic_plan->mask_array[BLWF]; 112885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod } 112985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod } 113085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod 113174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod unsigned int pref_len = indic_plan->config->pref_len; 113274f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + pref_len < end) 113317d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod { 113474f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod assert (1 <= pref_len && pref_len <= 2); 1135771a8f50289e8fa458cfc3cd84f73a380ce98077Behdad Esfahbod /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ 113674f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) { 113774f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod hb_codepoint_t glyphs[2]; 113874f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod for (unsigned int j = 0; j < pref_len; j++) 113974f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod glyphs[j] = info[i + j].codepoint; 114074f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, pref_len, face)) 11418e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 114274f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod for (unsigned int j = 0; j < pref_len; j++) 114374f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 11440201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 11450201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod /* Mark the subsequent stuff with 'cfar'. Used in Khmer. 11460201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * Read the feature spec. 11470201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * This allows distinguishing the following cases with MS Khmer fonts: 11480201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+179A,U+17D2,U+1782 11490201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+1782,U+17D2,U+179A 11500201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod */ 115174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod if (indic_plan->mask_array[CFAR]) 115274f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod for (; i < end; i++) 115374f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod info[i].mask |= indic_plan->mask_array[CFAR]; 11540201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 11558e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 11568e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 115756be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod } 115817d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod } 115917d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod 11609da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod /* Apply ZWJ/ZWNJ effects */ 11613c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start + 1; i < end; i++) 11629da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod if (is_joiner (info[i])) { 11639da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod bool non_joiner = info[i].indic_category() == OT_ZWNJ; 11646b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod unsigned int j = i; 11659da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 11669da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod do { 11679da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod j--; 11686b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 1169cfc507c5432e6327e8484b07b9e091212653bc92Behdad Esfahbod /* ZWJ/ZWNJ should disable CJCT. They do that by simply 1170cfc507c5432e6327e8484b07b9e091212653bc92Behdad Esfahbod * being there, since we don't skip them for the CJCT 1171a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod * feature (ie. F_MANUAL_ZWJ) */ 117220b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod 117320b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWNJ disables HALF. */ 11746b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod if (non_joiner) 117585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[j].mask &= ~indic_plan->mask_array[HALF]; 11766b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 11779da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } while (j > start && !is_consonant (info[j])); 11789da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } 1179743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1180743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1181743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1182743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 11838bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan, 1184f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 11859f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 1186ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1187743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 1188c5306b6861cfaa50af40e8ceb058791fa06d7981Behdad Esfahbod /* We made the vowels look like consonants. So let's call the consonant logic! */ 1189f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1190743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1191743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1192743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 11938bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, 1194f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 11959f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 1196ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1197743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 119818c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain. 119918c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Only if not in compatibility mode that is... */ 120018c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 1201bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 120218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod { 120318c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* For dotted-circle, this is what Uniscribe does: 120418c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * If dotted-circle is the last glyph, it just does nothing. 120518c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Ie. It doesn't form Reph. */ 120618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) 120718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod return; 120818c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod } 120918c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 1210f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1211743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1212743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1213743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 1214b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodinitial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan, 1215f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 1216b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer, 1217b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int start, unsigned int end) 1218b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1219b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod /* We already inserted dotted-circles, so just call the standalone_cluster. */ 1220f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_standalone_cluster (plan, face, buffer, start, end); 1221b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1222b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1223b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 12249f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbodinitial_reordering_symbol_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 12259f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod hb_face_t *face HB_UNUSED, 12269f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 12279f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 12283c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod{ 12293c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 12303c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 12313c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod} 12323c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod 12333c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbodstatic void 1234327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 1235f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face HB_UNUSED, 1236327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 1237327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 1238743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 1239743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 1240743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 1241743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1242743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1243327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1244743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 1245327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_syllable (const hb_ot_shape_plan_t *plan, 1246f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 1247327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer, 1248327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start, unsigned int end) 1249327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod{ 1250327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); 1251327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod switch (syllable_type) { 1252f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; 1253f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return; 1254f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return; 12559f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod case symbol_cluster: initial_reordering_symbol_cluster (plan, face, buffer, start, end); return; 1256f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; 1257f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return; 1258327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 1259327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod} 1260327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1261166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic inline void 12620beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbodinsert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, 1263b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_font_t *font, 1264b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer) 1265b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1266166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Note: This loop is extra overhead, but should not be measurable. */ 1267166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod bool has_broken_syllables = false; 1268166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod unsigned int count = buffer->len; 1269166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod for (unsigned int i = 0; i < count; i++) 1270166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) { 1271166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod has_broken_syllables = true; 1272166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod break; 1273166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod } 1274166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if (likely (!has_broken_syllables)) 1275166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod return; 1276166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 1277166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 1278b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_codepoint_t dottedcircle_glyph; 1279b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) 1280b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return; 1281b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1282f41dc2d35b23220d59d38990bb66f1cbd66a55b3Behdad Esfahbod hb_glyph_info_t dottedcircle = {0}; 1283b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = 0x25CC; 1284b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod set_indic_properties (dottedcircle); 1285b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = dottedcircle_glyph; 1286b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1287b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->clear_output (); 1288b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1289b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->idx = 0; 1290b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int last_syllable = 0; 1291b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod while (buffer->idx < buffer->len) 1292b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 1293b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int syllable = buffer->cur().syllable(); 1294b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); 1295b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) 1296b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 1297596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod last_syllable = syllable; 1298596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1299b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_glyph_info_t info = dottedcircle; 1300b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.cluster = buffer->cur().cluster; 1301b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.mask = buffer->cur().mask; 1302b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.syllable() = buffer->cur().syllable(); 1303596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1304596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod /* Insert dottedcircle after possible Repha. */ 1305596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod while (buffer->idx < buffer->len && 1306596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod last_syllable == buffer->cur().syllable() && 1307596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->cur().indic_category() == OT_Repha) 1308596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->next_glyph (); 1309596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1310b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->output_info (info); 1311b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 1312596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod else 1313596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->next_glyph (); 1314b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 1315b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1316b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->swap_buffers (); 1317b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1318b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1319b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 13208bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 132124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod hb_font_t *font, 13223e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1323743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 132485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod update_consonant_positions (plan, font, buffer); 1325166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod insert_dotted_circles (plan, font, buffer); 1326327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1327327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1328b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int count = buffer->len; 1329b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (!count)) return; 1330327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last = 0; 1331327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1332327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1333327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (last_syllable != info[i].syllable()) { 1334f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, i); 1335327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last = i; 1336327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last_syllable = info[last].syllable(); 1337327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 1338f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, count); 1339b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 1340b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 1341743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 134285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodfinal_reordering_syllable (const hb_ot_shape_plan_t *plan, 134385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer, 1344ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1345743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 134685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 13474ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 13484ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 1349e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod /* 4. Final reordering: 1350e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1351e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * After the localized forms and basic shaping forms GSUB features have been 1352e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * applied (see below), the shaping engine performs some final glyph 1353e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * reordering before applying all the remaining font features to the entire 1354e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * cluster. 13554ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 13564ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 13574ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* Find base again */ 13585f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod unsigned int base; 13595f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod for (base = start; base < end; base++) 13605f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (info[base].indic_position() >= POS_BASE_C) { 13615f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (start < base && info[base].indic_position() > POS_BASE_C) 13625f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod base--; 13635f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod break; 13645f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod } 1365a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod if (base == end && start < base && 1366a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod info[base - 1].indic_category() != OT_ZWJ) 1367a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod base--; 1368a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod while (start < base && 1369a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod (info[base].indic_category() == OT_H || 1370a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod info[base].indic_category() == OT_N)) 1371a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod base--; 13724ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 13734705a7026900e51f6430f03a73c87f2df035df92Behdad Esfahbod 13744ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder matras: 1375e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1376e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base matra character had been reordered before applying basic 1377e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * features, the glyph can be moved closer to the main consonant based on 1378e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * whether half-forms had been formed. Actual position for the matra is 1379e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * defined as “after last standalone halant glyph, after initial matra 1380e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * position and before the main consonant”. If ZWJ or ZWNJ follow this 1381e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * halant, position is moved after it. 13824ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 13834ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 138465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ 13859d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 138665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we lost track of base, alas, position before last thingy. */ 138765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod unsigned int new_pos = base == end ? base - 2 : base - 1; 138865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 138927bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 139027bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 139127bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * We want to position matra after them. 139265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod */ 139327bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1394e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod { 139565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod while (new_pos > start && 139665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng))))) 139765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos--; 139865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 139965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we found no Halant we are done. 140065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * Otherwise only proceed if the Halant does 140165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * not belong to the Matra itself! */ 140265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (is_halant_or_coeng (info[new_pos]) && 140365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod info[new_pos].indic_position() != POS_PRE_M) 140465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 140565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 140665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) 140765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos++; 140865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 140965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod else 141065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos = start; /* No move. */ 141165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 14129d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod 141327bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M) 141465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 14159d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* Now go see if there's actually any matras... */ 1416921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod for (unsigned int i = new_pos; i > start; i--) 14176a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[i - 1].indic_position () == POS_PRE_M) 14189d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 14191a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod unsigned int old_pos = i - 1; 14201a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 14211a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0])); 14221a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod info[new_pos] = tmp; 1423f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */ 1424f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod base--; 14259cb59d460e80d769087045535a8d54ec9ed7985cBehdad Esfahbod buffer->merge_clusters (new_pos, MIN (end, base + 1)); 1426921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod new_pos--; 14279d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 1428abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } else { 1429e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod for (unsigned int i = start; i < base; i++) 1430abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod if (info[i].indic_position () == POS_PRE_M) { 14312cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (i, MIN (end, base + 1)); 1432abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod break; 1433abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } 14349d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 14354ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod } 14364ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 14374ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 14384ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder reph: 1439e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1440e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Reph’s original position is always at the beginning of the syllable, 1441e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * (i.e. it is not reordered at the character reordering stage). However, 1442e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * it will be reordered according to the basic-forms shaping results. 1443e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Possible positions for reph, depending on the script, are; after main, 1444e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * before post-base consonant forms, and after post-base consonant forms. 1445dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 1446dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 144765a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod /* Two cases: 144865a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * 144965a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * - If repha is encoded as a sequence of characters (Ra,H or Ra,H,ZWJ), then 145065a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * we should only move it if the sequence ligated to the repha form. 145165a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * 145265a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * - If repha is encoded separately and in the logical position, we should only 145365a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * move it if it did NOT ligate. If it ligated, it's probably the font trying 145465a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * to make it work without the reordering. 145565a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod */ 1456f5299eff5c0065d6329cd536c0ac339abea085b0Behdad Esfahbod if (start + 1 < end && 1457f5299eff5c0065d6329cd536c0ac339abea085b0Behdad Esfahbod info[start].indic_position() == POS_RA_TO_BECOME_REPH && 14583ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod ((info[start].indic_category() == OT_Repha) ^ 1459a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod _hb_glyph_info_ligated (&info[start]))) 1460dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod { 146111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int new_reph_pos; 146211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos = indic_plan->config->reph_pos; 146311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 1464f175aa33c5e94397c60648ac0697c80f5fe0dcb7Behdad Esfahbod assert (reph_pos != REPH_POS_DONT_CARE); 146502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1466dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* 1. If reph should be positioned after post-base consonant forms, 1467dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to step 5. 146802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 146911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_POST) 147002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 14719d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_step_5; 147202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 147302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 147402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 2. If the reph repositioning class is not after post-base: target 1475dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is after the first explicit halant glyph between the 1476dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-reph consonant and last main consonant. If ZWJ or ZWNJ 1477dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * are following this halant, position is moved after it. If such 1478dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is found, this is the target position. Otherwise, 1479dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to the next step. 1480dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * 1481dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Note: in old-implementation fonts, where classifications were 1482dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * fixed in shaping engine, there was no case where reph position 1483dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * will be found on this step. 148402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 148502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 148602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = start + 1; 1487deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 148802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 148902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 14901f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) 14911f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod { 149202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 149302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 149402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 149502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 149602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 149702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 149802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 149902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 3. If reph should be repositioned after the main consonant: find the 1500dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first consonant not ligated with main, or find the first 1501dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant that is not a potential pre-base reordering Ra. 150202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 150311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_MAIN) 150402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1505b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos = base; 150634ae336f3fae93ef9372881d545c817bce383041Behdad Esfahbod while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN) 1507b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos++; 1508b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod if (new_reph_pos < end) 1509b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod goto reph_move; 151002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 151102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 151202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 4. If reph should be positioned before post-base consonant, find 1513dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-base classified consonant not ligated with main. If no 1514dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant is found, the target position should be before the 1515dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first matra, syllable modifier sign or vedic sign. 151602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 15179d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* This is our take on what step 4 is trying to say (and failing, BADLY). */ 151811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_SUB) 151902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 15209d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos = base; 15219d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod while (new_reph_pos < end && 1522be8b9f5f715f6fb36b98bd33c3303f79cc068f8aBehdad Esfahbod !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD)))) 15239d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos++; 15249d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (new_reph_pos < end) 15259d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_move; 152602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 152702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 152802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 5. If no consonant is found in steps 3 or 4, move reph to a position 1529dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * immediately before the first post-base matra, syllable modifier 1530dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * sign or vedic sign that has a reordering class after the intended 1531dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * reph position. For example, if the reordering position for reph 1532dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * is post-main, it will skip above-base matras that also have a 1533dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * post-main position. 1534dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 153502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_step_5: 153602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1537d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* Copied from step 2. */ 1538d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos = start + 1; 1539d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 1540d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1541d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod 15421f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) 15431f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod { 1544d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 1545d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 1546d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1547d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod goto reph_move; 1548d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod } 154902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1550dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 155102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 6. Otherwise, reorder reph to the end of the syllable. 155202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 155302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 155402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = end - 1; 155502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD) 155602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 155702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1558892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod /* 1559892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * If the Reph is to be ending up after a Matra,Halant sequence, 1560892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * position it before that Halant so it can interact with the Matra. 1561892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * However, if it's a plain Consonant,Halant we shouldn't do that. 1562892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * Uniscribe doesn't do this. 1563892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * TEST: U+0930,U+094D,U+0915,U+094B,U+094D 1564892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod */ 1565bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (!hb_options ().uniscribe_bug_compatible && 1566deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod unlikely (is_halant_or_coeng (info[new_reph_pos]))) { 156702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod for (unsigned int i = base + 1; i < new_reph_pos; i++) 156802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (info[i].indic_category() == OT_M) { 156902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Ok, got it. */ 157002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 157102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 157202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 157302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 15748df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod } 15758df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod 157602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_move: 157702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 15786b2abdcd203204131f3017ca85c91de9d43959cdBehdad Esfahbod buffer->merge_clusters (start, new_reph_pos + 1); 1579e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod 158002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Move */ 158102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod hb_glyph_info_t reph = info[start]; 158202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0])); 158302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod info[new_reph_pos] = reph; 1584f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod if (start < base && base <= new_reph_pos) 1585f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod base--; 158602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1587dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod } 1588dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1589dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1590dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* o Reorder pre-base reordering consonants: 1591e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1592e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base reordering consonant is found, reorder it according to 1593e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * the following rules: 1594e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod */ 1595e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 159685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ 159746e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod { 159846a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod unsigned int pref_len = indic_plan->config->pref_len; 15998e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 160085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) 160178818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod { 16028e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 1. Only reorder a glyph produced by substitution during application 16038e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * of the <pref> feature. (Note that a font may shape a Ra consonant with 16048e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * the feature generally but block it in certain contexts.) 16058e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 16069a49351cc2625de16a73e0e153d3097ef6c7cc0fBehdad Esfahbod /* Note: We just check that something got substituted. We don't check that 160746a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod * the <pref> feature actually did it... 160846a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod * 160946a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod * If pref len is longer than one, then only reorder if it ligated. If 161046a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod * pref len is one, only reorder if it didn't ligate with other things. */ 161146a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod if (_hb_glyph_info_substituted (&info[i]) && 161246a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod ((pref_len == 1) ^ _hb_glyph_info_ligated (&info[i]))) 16138e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 16148e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 16158e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 2. Try to find a target position the same way as for pre-base matra. 16168e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * If it is found, reorder pre-base consonant glyph. 16178e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 16188e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 3. If position is not found, reorder immediately before main 16198e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * consonant. 16208e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 16218e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 16228e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int new_pos = base; 162388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 162488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 162588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * We want to position matra after them. 162688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod */ 162788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1628d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 162988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod while (new_pos > start && 163088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS))) 163188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 163288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod 16339a49351cc2625de16a73e0e153d3097ef6c7cc0fBehdad Esfahbod /* In Khmer coeng model, a H,Ra can go *after* matras. If it goes after a 163488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * split matra, it should be reordered to *before* the left part of such matra. */ 163588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) 163688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 163788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod unsigned int old_pos = i; 163888d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod for (unsigned int i = base + 1; i < old_pos; i++) 163988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (info[i].indic_category() == OT_M) 164088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 164188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 164288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod break; 164388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 164488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 1645d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1646d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod 1647deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) 16481f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod { 16498e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 16508e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if (new_pos < end && is_joiner (info[new_pos])) 16518e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos++; 16521f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod } 16538e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 16548e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 16558e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int old_pos = i; 1656e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (new_pos, old_pos + 1); 16578e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 16588e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0])); 16598e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[new_pos] = tmp; 1660f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod if (new_pos <= base && base < old_pos) 1661f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod base++; 16628e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 16638e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 16648e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 16658e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 166678818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod } 166746e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod } 1668eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1669eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1670a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod /* Apply 'init' to the Left Matra if it's a word start. */ 16716a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[start].indic_position () == POS_PRE_M && 1672a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod (!start || 1673eace47b173807d94b29a6490d0bc3c9f8f6168d1Behdad Esfahbod !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & 16742c372b80f6befad69e216e3f218b38640b8cc044Behdad Esfahbod FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))) 167585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[start].mask |= indic_plan->mask_array[INIT]; 1676a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod 1677eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 16788ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod /* 16798ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod * Finish off the clusters and go home! 16808ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod */ 16819ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 1682ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 16839ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod switch ((hb_tag_t) plan->props.script) 16849ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod { 16859ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod case HB_SCRIPT_TAMIL: 16869ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod case HB_SCRIPT_SINHALA: 16879ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod break; 16889ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod 16899ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod default: 16909ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod /* Uniscribe merges the entire cluster... Except for Tamil & Sinhala. 16919ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod * This means, half forms are submerged into the main consonants cluster. 16929ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod * This is unnecessary, and makes cursor positioning harder, but that's what 16939ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod * Uniscribe does. */ 16949ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod buffer->merge_clusters (start, end); 16959ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod break; 16969ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod } 169721d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod } 1698ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod} 1699e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1700e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1701ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbodstatic void 17028bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 17030beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod hb_font_t *font HB_UNUSED, 17043e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1705ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod{ 1706ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int count = buffer->len; 1707327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (unlikely (!count)) return; 1708ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod 1709ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1710ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int last = 0; 1711cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1712ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1713cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod if (last_syllable != info[i].syllable()) { 171485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, i); 1715ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod last = i; 1716cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod last_syllable = info[last].syllable(); 1717ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod } 171885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, count); 1719e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1720743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); 1721743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); 1722743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1723743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1724743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 172530145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbodstatic void 172630145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbodclear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, 172730145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_font_t *font HB_UNUSED, 172830145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_buffer_t *buffer) 172930145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod{ 173030145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 173130145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod unsigned int count = buffer->len; 173230145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 173330145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod info[i].syllable() = 0; 173430145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod} 173530145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod 173630145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod 1737eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1738eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahboddecompose_indic (const hb_ot_shape_normalize_context_t *c, 17390736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t ab, 17400736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *a, 17410736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *b) 17420736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 17430736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod switch (ab) 17440736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 17450736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Don't decompose these. */ 17460736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0931 : return false; 17470736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0B94 : return false; 17480736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 17490736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 17500736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* 17510736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod * Decompose split matras that don't have Unicode decompositions. 17520736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod */ 17530736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 17540736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true; 17550736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true; 17560736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true; 17570736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true; 17580736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true; 17590736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true; 17600736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true; 17610736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1925 : *a = 0x1920; *b= 0x1923; return true; 17620736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1926 : *a = 0x1920; *b= 0x1924; return true; 17630736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true; 17640736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1112E : *a = 0x11127; *b= 0x11131; return true; 17650736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1112F : *a = 0x11127; *b= 0x11132; return true; 17660736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#if 0 17670736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* This one has no decomposition in Unicode, but needs no decomposition either. */ 17680736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* case 0x0AC9 : return false; */ 17690736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0B57 : *a = no decomp, -> RIGHT; return true; 17700736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1C29 : *a = no decomp, -> LEFT; return true; 17710736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0xA9C0 : *a = no decomp, -> RIGHT; return true; 17720736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x111BF : *a = no decomp, -> ABOVE; return true; 17730736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#endif 17740736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 17750736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 177643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod if ((ab == 0x0DDA || hb_in_range<hb_codepoint_t> (ab, 0x0DDC, 0x0DDE))) 17770736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 177843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* 177943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Sinhala split matras... Let the fun begin. 178043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 178143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * These four characters have Unicode decompositions. However, Uniscribe 178243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * decomposes them "Khmer-style", that is, it uses the character itself to 178343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * get the second half. The first half of all four decompositions is always 178443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * U+0DD9. 178543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 178643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are 178743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * broken with Uniscribe. But we need to support them. As such, we only 178843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * do the Uniscribe-style decomposition if the character is transformed into 178943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * its "sec.half" form by the 'pstf' feature. Otherwise, we fall back to 179043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Unicode decomposition. 179143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 179243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Note that we can't unconditionally use Unicode decomposition. That would 179343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * break some other fonts, that are designed to work with Uniscribe, and 179443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * don't have positioning features for the Unicode-style decomposition. 179543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 179643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Argh... 1797b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * 1798b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * The Uniscribe behavior is now documented in the newly published Sinhala 1799b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * spec in 2012: 1800b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * 1801b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shaping 180243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod */ 180343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 180443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data; 180543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 180643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod hb_codepoint_t glyph; 180743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 1808bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible || 180943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod (c->font->get_glyph (ab, 0, &glyph) && 1810b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->pstf.would_substitute (&glyph, 1, c->font->face))) 181143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod { 181243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* Ok, safe to use Uniscribe-style decomposition. */ 181343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *a = 0x0DD9; 181443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *b = ab; 181543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod return true; 181643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod } 18170736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 18180736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1819eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->decompose (ab, a, b); 18200736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 18210736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1822eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1823eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodcompose_indic (const hb_ot_shape_normalize_context_t *c, 18240736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t a, 18250736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t b, 18260736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *ab) 18270736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 18280736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Avoid recomposing split matras. */ 1829eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a))) 18300736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod return false; 18310736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 18320736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Composition-exclusion exceptions that we want to recompose. */ 18330736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; } 18340736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1835eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->compose (a, b, ab); 18360736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 18370736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 18380736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1839693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = 1840693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{ 1841693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod "indic", 1842693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod collect_features_indic, 1843693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod override_features_indic, 1844a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_create_indic, 1845a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_destroy_indic, 18469f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod NULL, /* preprocess_text */ 18473d6ca0d32e5c6597acfcf59301cb1905586ddb52Behdad Esfahbod HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, 18480736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod decompose_indic, 18490736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod compose_indic, 1850693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod setup_masks_indic, 185171b4c999a511bf018acaf48a45e070470c0daf12Behdad Esfahbod HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, 1852865745b5b87236651f5663cae3461db9cb505eedBehdad Esfahbod false, /* fallback_position */ 1853693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod}; 1854