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 407627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IN_HALF_BLOCK(u, Base) (((u) & ~0x7Fu) == (Base)) 413a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 427627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900u)) 437627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980u)) 447627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00u)) 457627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80u)) 467627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00u)) 477627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80u)) 487627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00u)) 497627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80u)) 507627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00u)) 517627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80u)) 527627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_KHMR(u) (IN_HALF_BLOCK (u, 0x1780u)) 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 : \ 637627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod IS_TELU(u) ? (u <= 0x0C42u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \ 647627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod IS_KNDA(u) ? (u < 0x0CC3u || u > 0xCD6u ? 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[] = { 1157627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x0930u, /* Devanagari */ 1167627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x09B0u, /* Bengali */ 1177627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x09F0u, /* Bengali */ 1187627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x0A30u, /* Gurmukhi */ /* No Reph */ 1197627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x0AB0u, /* Gujarati */ 1207627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x0B30u, /* Oriya */ 1217627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x0BB0u, /* Tamil */ /* No Reph */ 1227627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x0C30u, /* Telugu */ /* Reph formed only with ZWJ */ 1237627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x0CB0u, /* Kannada */ 1247627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x0D30u, /* Malayalam */ /* No Reph, Logical Repha */ 1257627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 1267627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x0DBBu, /* Sinhala */ /* Reph formed only with ZWJ */ 1277627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 1287627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x179Au, /* 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 Esfahbodstatic inline bool 1493a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_joiner (const hb_glyph_info_t &info) 1503a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1513a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return is_one_of (info, JOINER_FLAGS); 1523a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1533a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1543a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1553a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_consonant (const hb_glyph_info_t &info) 1563a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1573a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return is_one_of (info, CONSONANT_FLAGS); 1583a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1593a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1603a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1613a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_halant_or_coeng (const hb_glyph_info_t &info) 1623a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1633a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return is_one_of (info, HALANT_OR_COENG_FLAGS); 1643a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1653a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1663a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline void 1673a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodset_indic_properties (hb_glyph_info_t &info) 1683a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1693a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod hb_codepoint_t u = info.codepoint; 1703a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod unsigned int type = hb_indic_get_categories (u); 1717627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod indic_category_t cat = (indic_category_t) (type & 0x7Fu); 1723a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod indic_position_t pos = (indic_position_t) (type >> 8); 1733a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1743a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1753a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* 1763a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Re-assign category 1773a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 1783a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1793a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1803a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe 181c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod * treats a whole bunch of characters similarly. 182c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod * TESTS: For example, for U+0951: 1833a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * U+092E,U+0947,U+0952 1843a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * U+092E,U+0952,U+0947 1853a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * U+092E,U+0947,U+0951 1863a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * U+092E,U+0951,U+0947 187c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod * U+092E,U+0951,U+0952 188c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod * U+092E,U+0952,U+0951 1893756efaf4e14ec3b5b1def700a1b5985f162372bBehdad Esfahbod */ 1907627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if (unlikely (hb_in_ranges (u, 0x0951u, 0x0952u, 1917627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x1CD0u, 0x1CD2u, 1927627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x1CD4u, 0x1CE1u) || 1937627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod u == 0x1CF4u)) 19426c836e53d55a2e2d4c17fd9ea1884eec33ce015Behdad Esfahbod cat = OT_A; 195c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod /* The following act more like the Bindus. */ 1967627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (hb_in_range (u, 0x0953u, 0x0954u))) 197c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod cat = OT_SM; 198131e17ff9ae792cafa7a500043acb373802ee872Behdad Esfahbod /* The following act like consonants. */ 1997627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (hb_in_ranges (u, 0x0A72u, 0x0A73u, 2007627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x1CF5u, 0x1CF6u))) 201131e17ff9ae792cafa7a500043acb373802ee872Behdad Esfahbod cat = OT_C; 202ecb98babbaa065940b40ca8954a454f0e2cdcff0Behdad Esfahbod /* TODO: The following should only be allowed after a Visarga. 203ecb98babbaa065940b40ca8954a454f0e2cdcff0Behdad Esfahbod * For now, just treat them like regular tone marks. */ 2047627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (hb_in_range (u, 0x1CE2u, 0x1CE8u))) 205ecb98babbaa065940b40ca8954a454f0e2cdcff0Behdad Esfahbod cat = OT_A; 206e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod /* TODO: The following should only be allowed after some of 207e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod * the nasalization marks, maybe only for U+1CE9..U+1CF1. 208e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod * For now, just treat them like tone marks. */ 2097627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (u == 0x1CEDu)) 210e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod cat = OT_A; 211d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod /* The following take marks in standalone clusters, similar to Avagraha. */ 2127627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (hb_in_ranges (u, 0xA8F2u, 0xA8F7u, 2137627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x1CE9u, 0x1CECu, 2147627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod 0x1CEEu, 0x1CF1u))) 215d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod { 216d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod cat = OT_Symbol; 217d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol); 218d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod } 2197627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (hb_in_range (u, 0x17CDu, 0x17D1u) || 2207627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */ 2213a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2223a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* These are like Top Matras. */ 2233a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_M; 2243a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = POS_ABOVE_C; 2253a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2267627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */ 2277627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (u == 0x17D2u)) cat = OT_Coeng; /* Khmer coeng */ 2287627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u))) 2297627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod cat = OT_PLACEHOLDER; 2307627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE; 2317627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (u == 0xA982u)) cat = OT_SM; /* Javanese repha. */ 2327627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (u == 0xA9BEu)) cat = OT_CM2; /* Javanese medial ya. */ 2337627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod else if (unlikely (u == 0xA9BDu)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */ 2343a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2353a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2363a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* 2373a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Re-assign position. 2383a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 2393a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2403a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if ((FLAG (cat) & CONSONANT_FLAGS)) 2413a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 242c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod pos = POS_BASE_C; 2433a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (is_ra (u)) 2443a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_Ra; 2453a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2463a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (cat == OT_M) 2473a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2483a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = matra_position (u, pos); 2493a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2509f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol)))) 2513a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2523a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = POS_SMVD; 2533a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2543a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2557627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if (unlikely (u == 0x0B01u)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */ 2563a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2573a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2583a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2593a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod info.indic_category() = cat; 2603a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod info.indic_position() = pos; 2613a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 2623a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2633a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod/* 2643a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Things above this line should ideally be moved to the Indic table itself. 2653a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 2663a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2671d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 26811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 26911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic configurations. Note that we do not want to keep every single script-specific 27011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * behavior in these tables necessarily. This should mainly be used for per-script 27111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * properties that are cheaper keeping here, than in the code. Ie. if, say, one and 27211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * only one script has an exception, that one script can be if'ed directly in the code, 27311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * instead of adding a new flag in these structs. 27411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 27511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 27611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum base_position_t { 27711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_FIRST, 278e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod BASE_POS_LAST_SINHALA, 27911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_LAST 28011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 28111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_position_t { 28211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_MAIN = POS_AFTER_MAIN, 28311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_SUB = POS_BEFORE_SUB, 28411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_SUB = POS_AFTER_SUB, 28511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_POST = POS_BEFORE_POST, 28674f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod REPH_POS_AFTER_POST = POS_AFTER_POST, 28774f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod REPH_POS_DONT_CARE = POS_RA_TO_BECOME_REPH 28811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 28911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_mode_t { 29011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_IMPLICIT, /* Reph formed out of initial Ra,H sequence. */ 29111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_EXPLICIT, /* Reph formed out of initial Ra,H,ZWJ sequence. */ 29211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */ 29311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_LOG_REPHA /* Encoded Repha character, needs reordering. */ 29411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 2958acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbodenum blwf_mode_t { 2968acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod BLWF_MODE_PRE_AND_POST, /* Below-forms feature applied to pre-base and post-base. */ 2978acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod BLWF_MODE_POST_ONLY /* Below-forms feature applied to post-base only. */ 2988acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod}; 29974f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbodenum pref_len_t { 30074f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod PREF_LEN_1 = 1, 30174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod PREF_LEN_2 = 2, 30274f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod PREF_LEN_DONT_CARE = PREF_LEN_2 30374f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod}; 30411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstruct indic_config_t 30511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 30611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_script_t script; 30711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool has_old_spec; 30811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_codepoint_t virama; 30911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base_position_t base_pos; 31011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos; 31111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_mode_t reph_mode; 3128acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod blwf_mode_t blwf_mode; 31374f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod pref_len_t pref_len; 31411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 31511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 31611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstatic const indic_config_t indic_configs[] = 31711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 31811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Default. Should be first. */ 3197627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1}, 3207627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_DEVANAGARI,true, 0x094Du,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 3217627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_BENGALI, true, 0x09CDu,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 3227627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_GURMUKHI, true, 0x0A4Du,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 3237627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_GUJARATI, true, 0x0ACDu,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 3247627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_ORIYA, true, 0x0B4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 3257627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_TAMIL, true, 0x0BCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, 3267627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_TELUGU, true, 0x0C4Du,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2}, 3277627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_KANNADA, true, 0x0CCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2}, 3287627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_MALAYALAM, true, 0x0D4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, 3297627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_SINHALA, false,0x0DCAu,BASE_POS_LAST_SINHALA, 3307627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 3317627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_KHMER, false,0x17D2u,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, 3327627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {HB_SCRIPT_JAVANESE, false,0xA9C0u,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1}, 33311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 33411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 33511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 33611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 33711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 33811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic shaper. 33911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 3409ccc6382ba43760167c134c18c1c4ada4b8c3f22Behdad Esfahbod 341eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstruct feature_list_t { 342c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_tag_t tag; 343ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod hb_ot_map_feature_flags_t flags; 344eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod}; 345eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 346eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstatic const feature_list_t 34785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodindic_features[] = 348b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 34985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 35085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Basic features. 35185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied in order, one at a time, after initial_reordering. 35285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 353a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('n','u','k','t'), F_GLOBAL}, 354a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('a','k','h','n'), F_GLOBAL}, 355a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('r','p','h','f'), F_NONE}, 356a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('r','k','r','f'), F_GLOBAL}, 357a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('p','r','e','f'), F_NONE}, 358a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('b','l','w','f'), F_NONE}, 359a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('a','b','v','f'), F_NONE}, 360a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod {HB_TAG('h','a','l','f'), F_NONE}, 361a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('p','s','t','f'), F_NONE}, 362a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('v','a','t','u'), F_GLOBAL}, 363a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('c','j','c','t'), F_GLOBAL}, 364a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod {HB_TAG('c','f','a','r'), F_NONE}, 36585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 36685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Other features. 36785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied all at once, after final_reordering. 368a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod * Default Bengali font in Windows for example has intermixed 369a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod * lookups for init,pres,abvs,blws features. 37085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 371ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('i','n','i','t'), F_NONE}, 372ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('p','r','e','s'), F_GLOBAL}, 373ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('a','b','v','s'), F_GLOBAL}, 374ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('b','l','w','s'), F_GLOBAL}, 375ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('p','s','t','s'), F_GLOBAL}, 376ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('h','a','l','n'), F_GLOBAL}, 37785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* Positioning features, though we don't care about the types. */ 378ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('d','i','s','t'), F_GLOBAL}, 379ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('a','b','v','m'), F_GLOBAL}, 380ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('b','l','w','m'), F_GLOBAL}, 381c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod}; 382c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod 38385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod/* 38485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Must be in the same order as the indic_features array. 38585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 386c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbodenum { 387c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod _NUKT, 388e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod _AKHN, 389c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod RPHF, 390df6d45c693c417bf311e6fa49f18a8558542e525Behdad Esfahbod _RKRF, 391c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PREF, 392167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod BLWF, 39329f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod ABVF, 394a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod HALF, 395c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PSTF, 39685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _VATU, 39770d656571194d2bd32671244530edbe159722cecBehdad Esfahbod _CJCT, 398a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod CFAR, 39985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 40085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INIT, 40185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PRES, 40285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVS, 40385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWS, 40485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PSTS, 40585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _HALN, 40685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _DIST, 40785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVM, 40885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWM, 40985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 41085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_NUM_FEATURES, 41185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */ 412b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod}; 413b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 414743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 415166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan, 416166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font, 417166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer); 418166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 4198bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 420afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 4213e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 422f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbodstatic void 4238bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 424afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 4253e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 42630145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbodstatic void 42730145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbodclear_syllables (const hb_ot_shape_plan_t *plan, 42830145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_font_t *font, 42930145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_buffer_t *buffer); 430b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 431693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 43216c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodcollect_features_indic (hb_ot_shape_planner_t *plan) 433b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 43416c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_ot_map_builder_t *map = &plan->map; 43516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod 436166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Do this before any lookups have been applied. */ 437166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod map->add_gsub_pause (setup_syllables); 438166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 439e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod map->add_global_bool_feature (HB_TAG('l','o','c','l')); 440a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod /* The Indic specs do not require ccmp, but we apply it here since if 441a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod * there is a use of it, it's typically at the beginning. */ 442e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod map->add_global_bool_feature (HB_TAG('c','c','m','p')); 443f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 444f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 44585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod unsigned int i = 0; 44685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_gsub_pause (initial_reordering); 44785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_BASIC_FEATURES; i++) { 448a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ); 4493e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (NULL); 450412b91889d9a1ae477e8b6907d0b9a76e78a6c91Behdad Esfahbod } 4513e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (final_reordering); 45285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_NUM_FEATURES; i++) { 453a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ); 45485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 45542d0f55cbc68285e22d713df7062e520af708c82Behdad Esfahbod 45642d0f55cbc68285e22d713df7062e520af708c82Behdad Esfahbod map->add_global_bool_feature (HB_TAG('c','a','l','t')); 45742d0f55cbc68285e22d713df7062e520af708c82Behdad Esfahbod map->add_global_bool_feature (HB_TAG('c','l','i','g')); 45842d0f55cbc68285e22d713df7062e520af708c82Behdad Esfahbod 45930145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod map->add_gsub_pause (clear_syllables); 460b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 461b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 462693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 46316c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodoverride_features_indic (hb_ot_shape_planner_t *plan) 464d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod{ 465eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod /* Uniscribe does not apply 'kern' in Khmer. */ 466bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 467eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod { 468eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod switch ((hb_tag_t) plan->props.script) 469eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod { 470eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod case HB_SCRIPT_KHMER: 4719ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL); 472eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod break; 473eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod } 474eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod } 4756b389ddc3623d042ded4731f4d62dc354002fdd0Behdad Esfahbod 476ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); 477d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod} 478d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod 479867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 48085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodstruct would_substitute_feature_t 481a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 482b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) 483a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 484b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod zero_context = zero_context_; 485a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_stage_lookups (0/*GSUB*/, 486a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_feature_stage (0/*GSUB*/, feature_tag), 487a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod &lookups, &count); 488a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 489a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 4908144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod inline bool would_substitute (const hb_codepoint_t *glyphs, 4918144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod unsigned int glyphs_count, 4928144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod hb_face_t *face) const 493a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 494a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 495362a990b2246f5448ecb9d600761f710aea7d42dBehdad Esfahbod if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) 496a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return true; 497a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return false; 498a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 499a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 500a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod private: 501a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const hb_ot_map_t::lookup_map_t *lookups; 502a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int count; 503b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod bool zero_context; 504a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 505a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 506a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstruct indic_shape_plan_t 507a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 50885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod ASSERT_POD (); 509914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 510914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const 511914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 512914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod hb_codepoint_t glyph = virama_glyph; 513914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (unlikely (virama_glyph == (hb_codepoint_t) -1)) 514914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 51511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!config->virama || !font->get_glyph (config->virama, 0, &glyph)) 516914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod glyph = 0; 517914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Technically speaking, the spec says we should apply 'locl' to virama too. 518914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * Maybe one day... */ 519914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 520914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Our get_glyph() function needs a font, so we can't get the virama glyph 521914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */ 522914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph; 523914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 524914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 525914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod *pglyph = glyph; 526914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod return glyph != 0; 527914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 52885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 52911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod const indic_config_t *config; 53085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 53185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod bool is_old_spec; 53285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_codepoint_t virama_glyph; 53385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 534f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod would_substitute_feature_t rphf; 53585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pref; 53685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t blwf; 53785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pstf; 53885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 53985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_mask_t mask_array[INDIC_NUM_FEATURES]; 540a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 541a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 542a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void * 543a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_create_indic (const hb_ot_shape_plan_t *plan) 544a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 54585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t)); 54685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (unlikely (!indic_plan)) 547a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return NULL; 548a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 54911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[0]; 55011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++) 55111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (plan->props.script == indic_configs[i].script) { 55211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[i]; 55311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 55485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 55511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 5567627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2'); 55711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->virama_glyph = (hb_codepoint_t) -1; 55885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 559b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod /* Use zero-context would_substitute() matching for new-spec of the main 560828e109c7aac3389cc3b89ea1f13388aefb63804Behdad Esfahbod * Indic scripts, and scripts with one spec only, but not for old-specs. */ 561828e109c7aac3389cc3b89ea1f13388aefb63804Behdad Esfahbod bool zero_context = !indic_plan->is_old_spec; 562b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context); 563b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context); 564b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context); 565b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context); 56685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 56785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) 568ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ? 569ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod 0 : plan->map.get_1_mask (indic_features[i].tag); 570a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 57185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod return indic_plan; 572a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 573a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 574a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void 575a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_destroy_indic (void *data) 576a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 577a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod free (data); 578a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 579a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 580a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic indic_position_t 581a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodconsonant_position_from_face (const indic_shape_plan_t *indic_plan, 582684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod const hb_codepoint_t consonant, 583684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod const hb_codepoint_t virama, 5848144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod hb_face_t *face) 585a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 5868144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod /* For old-spec, the order of glyphs is Consonant,Virama, 5878144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * whereas for new-spec, it's Virama,Consonant. However, 5888144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * some broken fonts (like Free Sans) simply copied lookups 5898144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * from old-spec to new-spec without modification. 5908144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * And oddly enough, Uniscribe seems to respect those lookups. 5918144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds 5928144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * base at 0. The font however, only has lookups matching 5938144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * 930,94D in 'blwf', not the expected 94D,930 (with new-spec 5948144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * table). As such, we simply match both sequences. Seems 5958144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * to work. */ 596684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod hb_codepoint_t glyphs[3] = {virama, consonant, virama}; 597b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod if (indic_plan->blwf.would_substitute (glyphs , 2, face) || 598684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod indic_plan->blwf.would_substitute (glyphs+1, 2, face)) 5998144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod return POS_BELOW_C; 600b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod if (indic_plan->pstf.would_substitute (glyphs , 2, face) || 601684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod indic_plan->pstf.would_substitute (glyphs+1, 2, face)) 6028144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod return POS_POST_C; 60374f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod unsigned int pref_len = indic_plan->config->pref_len; 60474f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod if ((pref_len == PREF_LEN_2 && 60574f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod (indic_plan->pref.would_substitute (glyphs , 2, face) || 60674f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod indic_plan->pref.would_substitute (glyphs+1, 2, face))) 60774f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod || (pref_len == PREF_LEN_1 && 60874f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod indic_plan->pref.would_substitute (glyphs+1, 1, face))) 609ae9a5834df477006686421d494b55a1569789327Behdad Esfahbod return POS_POST_C; 610a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return POS_BASE_C; 611a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 612a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 613a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 614166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodenum syllable_type_t { 615166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod consonant_syllable, 616166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod vowel_syllable, 617166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod standalone_cluster, 6189f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod symbol_cluster, 619166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod broken_cluster, 620166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod non_indic_cluster, 621166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod}; 622166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 623166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod#include "hb-ot-shape-complex-indic-machine.hh" 624166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 625166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 626693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 62716c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodsetup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, 62816c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_buffer_t *buffer, 62916c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_font_t *font HB_UNUSED) 63024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 63124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); 63224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); 63324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 63424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod /* We cannot setup masks here. We save information about characters 63524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod * and setup masks later on in a pause-callback. */ 63624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 63724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod unsigned int count = buffer->len; 6387cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 63924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 6407cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod set_indic_properties (info[i]); 64124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 64224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 643166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 644166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, 645166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font HB_UNUSED, 646166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer) 647166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod{ 648166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod find_syllables (buffer); 649166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod} 650166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 65124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic int 65224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodcompare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 65324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 65424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int a = pa->indic_position(); 65524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int b = pb->indic_position(); 65624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 65724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod return a < b ? -1 : a == b ? 0 : +1; 65824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 65924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 66024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 66124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 66224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic void 6638bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodupdate_consonant_positions (const hb_ot_shape_plan_t *plan, 66485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 66585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer) 6668ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod{ 667a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 6688ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 669c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod if (indic_plan->config->base_pos != BASE_POS_LAST) 670c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod return; 671c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod 672684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod hb_codepoint_t virama; 673684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod if (indic_plan->get_virama_glyph (font, &virama)) 6748ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod { 6758ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_face_t *face = font->face; 6768ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod unsigned int count = buffer->len; 6777cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 6788ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 6797cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod if (info[i].indic_position() == POS_BASE_C) 6807cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod { 6817cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod hb_codepoint_t consonant = info[i].codepoint; 6827cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face); 6838ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 6848ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 6858ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod} 6868ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 687867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 6887ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod/* Rules from: 6897ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ 6907ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod 691743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 692f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbodinitial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, 693f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 694f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_buffer_t *buffer, 695ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 696743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 697914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 698ee58f3bc75d2d071a71b94063bf12205a5871acbBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 699743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 700617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod 701743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 1. Find base consonant: 702743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 703743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The shaping engine finds the base consonant of the syllable, using the 704743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following algorithm: starting from the end of the syllable, move backwards 705743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * until a consonant is found that does not have a below-base or post-base 706743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * form (post-base forms have to follow below-base forms), or that is not a 707743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * pre-base reordering Ra, or arrive at the first consonant. The consonant 708743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * stopped at will be the base. 709743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 710743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o If the syllable starts with Ra + Halant (in a script that has Reph) 711743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 712743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * base consonants. 713743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 714743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 7155e72071062c015237b79fbd0521341a63166a204Behdad Esfahbod unsigned int base = end; 71676b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod bool has_reph = false; 717743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 71876b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod { 719617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 720617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 721617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * base consonants. */ 722617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod unsigned int limit = start; 723f175aa33c5e94397c60648ac0697c80f5fe0dcb7Behdad Esfahbod if (indic_plan->config->reph_pos != REPH_POS_DONT_CARE && 724efed40b975110d78c9c505441e7e17a8c13e85c8Behdad Esfahbod indic_plan->mask_array[RPHF] && 725617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod start + 3 <= end && 7268b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod ( 72711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || 72811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ) 7293285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod )) 730617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod { 731f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod /* See if it matches the 'rphf' feature. */ 73229531128f2f4342d537817746863705df80efe4bBehdad Esfahbod hb_codepoint_t glyphs[3] = {info[start].codepoint, 73329531128f2f4342d537817746863705df80efe4bBehdad Esfahbod info[start + 1].codepoint, 73429531128f2f4342d537817746863705df80efe4bBehdad Esfahbod indic_plan->config->reph_mode == REPH_MODE_EXPLICIT ? 73529531128f2f4342d537817746863705df80efe4bBehdad Esfahbod info[start + 2].codepoint : 0}; 73629531128f2f4342d537817746863705df80efe4bBehdad Esfahbod if (indic_plan->rphf.would_substitute (glyphs, 2, face) || 73729531128f2f4342d537817746863705df80efe4bBehdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && 73829531128f2f4342d537817746863705df80efe4bBehdad Esfahbod indic_plan->rphf.would_substitute (glyphs, 3, face))) 739f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod { 740f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit += 2; 741f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 742f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit++; 743f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod base = start; 744f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod has_reph = true; 745f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod } 7468b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha) 7478b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod { 7488b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod limit += 1; 7498b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 7508b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod limit++; 7518b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod base = start; 7528b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod has_reph = true; 7538b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod } 75476b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod 75523b0e9d7dc801e11640979af3c2b00649a519bb1Behdad Esfahbod switch (indic_plan->config->base_pos) 7565d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 757d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod default: 758d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod assert (false); 759d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod /* fallthrough */ 760d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod 76111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_LAST: 76211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 76311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> starting from the end of the syllable, move backwards */ 76411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int i = end; 76511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool seen_below = false; 76611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod do { 76711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod i--; 76811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> until a consonant is found */ 76911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i])) 7705d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 77111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> that does not have a below-base or post-base form 77211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * (post-base forms have to follow below-base forms), */ 77311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() != POS_BELOW_C && 77411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (info[i].indic_position() != POS_POST_C || seen_below)) 77511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 77611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 77711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 77811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 77911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() == POS_BELOW_C) 78011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod seen_below = true; 78111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 78211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or that is not a pre-base reordering Ra, 78311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 78411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * IMPLEMENTATION NOTES: 78511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 786fb7c182bf92142540bff1ad7fb82de0d115fb2b5Behdad Esfahbod * Our pre-base reordering Ra's are marked POS_POST_C, so will be skipped 78711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * by the logic above already. 78811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 78911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 79011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or arrive at the first consonant. The consonant stopped at will 79111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * be the base. */ 7925d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod base = i; 7935d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 79411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 79511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 79611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* A ZWJ after a Halant stops the base search, and requests an explicit 79711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * half form. 79811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * A ZWJ before a Halant, requests a subjoined form instead, and hence 79911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * search continues. This is particularly important for Bengali 800c4be9917438c45b972ec76dc68409014110f0837Behdad Esfahbod * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */ 80111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (start < i && 80211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_category() == OT_ZWJ && 80311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i - 1].indic_category() == OT_H) 80411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 80511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 80611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } while (i > limit); 80711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 80811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 8095d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 810e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod case BASE_POS_LAST_SINHALA: 81111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 812c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod /* Sinhala base positioning is slightly different from main Indic, in that: 813b082ef373cefb35dd98b5f2f0b677ccc7806f51eBehdad Esfahbod * 1. Its ZWJ behavior is different, 814c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod * 2. We don't need to look into the font for consonant positions. 815c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod */ 8165d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 81711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!has_reph) 81811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = limit; 81934c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 82011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Find the last base consonant that is not blocked by ZWJ. If there is 82111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * a ZWJ right before a base consonant, that would request a subjoined form. */ 82211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = limit; i < end; i++) 823c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod if (is_consonant (info[i])) 82411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 82511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (limit < i && info[i - 1].indic_category() == OT_ZWJ) 82611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 82711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 82811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 82911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 83034c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 83111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Mark all subsequent consonants as below. */ 83211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 833c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod if (is_consonant (info[i])) 83411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_position() = POS_BELOW_C; 83511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 83611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 837e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod 838e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod case BASE_POS_FIRST: 839e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod { 840e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod /* The first consonant is always the base. */ 841e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod 842e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod assert (indic_plan->config->reph_mode == REPH_MODE_VIS_REPHA); 843efed40b975110d78c9c505441e7e17a8c13e85c8Behdad Esfahbod assert (!has_reph); 844e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod 845e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod base = start; 846e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod 847e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod /* Mark all subsequent consonants as below. */ 848e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 849c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod if (is_consonant (info[i])) 850e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod info[i].indic_position() = POS_BELOW_C; 851e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod } 852e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod break; 8535d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 854743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 855617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 856617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 8572278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * base consonants. 8582278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * 8592278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ 8609621e0ba294c9cc6d458bbf632e63e92fda71e10Behdad Esfahbod if (has_reph && base == start && limit - base <= 2) { 861617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* Have no other consonant, so Reph is not formed and Ra becomes base. */ 862617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = false; 863617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod } 8645e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod } 8652278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod 8663d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 867743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 2. Decompose and reorder Matras: 868743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 869743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Each matra and any syllable modifier sign in the cluster are moved to the 870743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * appropriate position relative to the consonant(s) in the cluster. The 871743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * shaping engine decomposes two- or three-part matras into their constituent 872743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * parts before any repositioning. Matra characters are classified by which 873743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * consonant in a conjunct they have affinity for and are reordered to the 874743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following positions: 875743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 876743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o Before first half form in the syllable 877743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After subjoined consonants 878743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After post-form consonant 879743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After main consonant (for above marks) 880743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 881743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 882743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 883743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The normalize() routine has already decomposed matras for us, so we don't 884743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * need to worry about that. 885743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 886743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 887743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 888743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 3. Reorder marks to canonical order: 889743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 890743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Adjacent nukta and halant or nukta and vedic sign are always repositioned 891743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * if necessary, so that the nukta is first. 892743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 893743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 894743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 895743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * We don't need to do this: the normalize() routine already did this for us. 896743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 897743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 898743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 89945d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod /* Reorder characters */ 90045d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 9013c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 902900cf3d449bf36d4f8b1474590cae925fef48fc8Behdad Esfahbod info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position()); 90355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 904075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 905075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].indic_position() = POS_BASE_C; 90645d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 90755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod /* Mark final consonants. A final consonant is one appearing after a matra, 90855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod * like in Khmer. */ 90955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 91055f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (info[i].indic_category() == OT_M) { 91155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int j = i + 1; j < end; j++) 91255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (is_consonant (info[j])) { 91355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod info[j].indic_position() = POS_FINAL_C; 91455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 91555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 91655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 91755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 91855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 919fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod /* Handle beginning Ra */ 9205e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod if (has_reph) 921dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() = POS_RA_TO_BECOME_REPH; 922fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod 923f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* For old-style Indic script tags, move the first post-base Halant after 924fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * last consonant. 925fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * 926fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * Reports suggest that in some scripts Uniscribe does this only if there 927fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * is *not* a Halant after last consonant already (eg. Kannada), while it 928fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * does it unconditionally in other scripts (eg. Malayalam). We don't 929fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * currently know about other scripts, so we single out Malayalam for now. 930fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * 931fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * Kannada test case: 932fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * U+0C9A,U+0CCD,U+0C9A,U+0CCD 933fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * With some versions of Lohit Kannada. 934fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * https://bugs.freedesktop.org/show_bug.cgi?id=59118 935fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * 936fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * Malayalam test case: 937fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D 938fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod * With lohit-ttf-20121122/Lohit-Malayalam.ttf 939fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod */ 940fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod if (indic_plan->is_old_spec) 941fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod { 942fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM; 9433c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 944fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod if (info[i].indic_category() == OT_H) 945fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod { 946f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod unsigned int j; 947f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod for (j = end - 1; j > i; j--) 948fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod if (is_consonant (info[j]) || 949fc0daafab0336b847ac14682e581a8838f36a0bfBehdad Esfahbod (disallow_double_halants && info[j].indic_category() == OT_H)) 950f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 951ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod if (info[j].indic_category() != OT_H && j > i) { 952f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* Move Halant to after last consonant. */ 953f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod hb_glyph_info_t t = info[i]; 954f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); 955f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod info[j] = t; 956f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 957f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 958f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 959f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 960f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod 96181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* Attach misc marks to previous char to move with them. */ 962ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 96381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod indic_position_t last_pos = POS_START; 96481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod for (unsigned int i = start; i < end; i++) 96581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 966c16012e9019ec59c2200a3cc29b8a37ea70eda70Behdad Esfahbod if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS))) 96781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 96881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() = last_pos; 969dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod if (unlikely (info[i].indic_category() == OT_H && 97081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() == POS_PRE_M)) 97181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 97281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* 97381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * Uniscribe doesn't move the Halant with Left Matra. 97481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * TEST: U+092B,U+093F,U+094DE 975dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We follow. This is important for the Sinhala 976dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA 977dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * where U+0DD9 is a left matra and U+0DCA is the virama. 978dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We don't want to move the virama with the left matra. 979dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * TEST: U+0D9A,U+0DDA 98081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod */ 981ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod for (unsigned int j = i; j > start; j--) 9826a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[j - 1].indic_position() != POS_PRE_M) { 983ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod info[i].indic_position() = info[j - 1].indic_position(); 984ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod break; 985ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 98681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 98781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } else if (info[i].indic_position() != POS_SMVD) { 98881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod last_pos = (indic_position_t) info[i].indic_position(); 989ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 99081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 991ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 992ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod /* For post-base consonants let them own anything before them 993ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod * since the last consonant or matra. */ 99474ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod { 995ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod unsigned int last = base; 99674ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 997ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod if (is_consonant (info[i])) 998ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod { 999ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod for (unsigned int j = last + 1; j < i; j++) 1000ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod if (info[j].indic_position() < POS_SMVD) 100181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[j].indic_position() = info[i].indic_position(); 1002ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod last = i; 1003ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod } else if (info[i].indic_category() == OT_M) 1004ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod last = i; 100574ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 100645d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 100728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod 1008a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod { 100928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod /* Use syllable() for sort accounting temporarily. */ 101028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod unsigned int syllable = info[start].syllable(); 101128d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod for (unsigned int i = start; i < end; i++) 101228d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod info[i].syllable() = i - start; 101328d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod 1014a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Sit tight, rock 'n roll! */ 1015d3637edb248162970e202e9d0671540274192844Behdad Esfahbod hb_bubble_sort (info + start, end - start, compare_indic_order); 1016a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Find base again */ 1017a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = end; 10183c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < end; i++) 101928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod if (info[i].indic_position() == POS_BASE_C) 102028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod { 102128d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod base = i; 1022a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod break; 1023a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 102428d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod /* Things are out-of-control for post base positions, they may shuffle 102528d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod * around like crazy. In old-spec mode, we move halants around, so in 102628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod * that case merge all clusters after base. Otherwise, check the sort 102728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod * order and merge as needed. 102828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod * For pre-base stuff, we handle cluster issues in final reordering. */ 102928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod if (indic_plan->is_old_spec || end - base > 127) 103028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod buffer->merge_clusters (base, end); 103128d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod else 103228d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod { 103328d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod /* Note! syllable() is a one-byte field. */ 103428d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod for (unsigned int i = base; i < end; i++) 103528d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod if (info[i].syllable() != 255) 103628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod { 103728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod unsigned int max = i; 103828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod unsigned int j = start + info[i].syllable(); 103928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod while (j != i) 104028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod { 104128d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod max = MAX (max, j); 104228d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod unsigned int next = start + info[j].syllable(); 104328d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod info[j].syllable() = 255; /* So we don't process j later again. */ 104428d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod j = next; 104528d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod } 104628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod if (i != max) 104728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod buffer->merge_clusters (i, max + 1); 104828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod } 104928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod } 105028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod 105128d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod /* Put syllable back in. */ 105228d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod for (unsigned int i = start; i < end; i++) 105328d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod info[i].syllable() = syllable; 1054a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 105545d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 1056743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Setup masks now */ 1057743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1058281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod { 1059281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod hb_mask_t mask; 1060281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod 1061dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* Reph */ 1062668c6046c1b3af3bd316bda0cc8636f2a5e8df42Behdad Esfahbod for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) 106385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[RPHF]; 1064dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1065281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Pre-base */ 106685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[HALF]; 1067c7dacac02cfe8526eaf131ce6c5e7b6df7ca2ccdBehdad Esfahbod if (!indic_plan->is_old_spec && 1068c7dacac02cfe8526eaf131ce6c5e7b6df7ca2ccdBehdad Esfahbod indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST) 10698acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod mask |= indic_plan->mask_array[BLWF]; 10703c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 1071281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 1072281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Base */ 107320b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = 0; 1074075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 1075075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].mask |= mask; 1076281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Post-base */ 107785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF]; 10783c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 1079281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 1080281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod } 10819da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 108285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod if (indic_plan->is_old_spec && 108385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod buffer->props.script == HB_SCRIPT_DEVANAGARI) 108485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod { 108585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod /* Old-spec eye-lash Ra needs special handling. From the 108685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * spec: 108785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 108885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * "The feature 'below-base form' is applied to consonants 108985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * having below-base forms and following the base consonant. 109085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * The exception is vattu, which may appear below half forms 109185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * as well as below the base glyph. The feature 'below-base 109285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * form' will be applied to all such occurrences of Ra as well." 109385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 109485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * Test case: U+0924,U+094D,U+0930,U+094d,U+0915 109585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * with Sanskrit 2003 font. 109685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 109785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * However, note that Ra,Halant,ZWJ is the correct way to 109885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * request eyelash form of Ra, so we wouldbn't inhibit it 109985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * in that sequence. 110085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 110185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915 110285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod */ 110385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod for (unsigned int i = start; i + 1 < base; i++) 110485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod if (info[i ].indic_category() == OT_Ra && 110585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+1].indic_category() == OT_H && 110685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod (i + 2 == base || 110785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+2].indic_category() != OT_ZWJ)) 110885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod { 110985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i ].mask |= indic_plan->mask_array[BLWF]; 111085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+1].mask |= indic_plan->mask_array[BLWF]; 111185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod } 111285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod } 111385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod 111474f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod unsigned int pref_len = indic_plan->config->pref_len; 111574f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + pref_len < end) 111617d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod { 111774f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod assert (1 <= pref_len && pref_len <= 2); 1118771a8f50289e8fa458cfc3cd84f73a380ce98077Behdad Esfahbod /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ 111974f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) { 112074f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod hb_codepoint_t glyphs[2]; 112174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod for (unsigned int j = 0; j < pref_len; j++) 112274f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod glyphs[j] = info[i + j].codepoint; 112374f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, pref_len, face)) 11248e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 112574f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod for (unsigned int j = 0; j < pref_len; j++) 112674f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 11270201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 11280201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod /* Mark the subsequent stuff with 'cfar'. Used in Khmer. 11290201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * Read the feature spec. 11300201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * This allows distinguishing the following cases with MS Khmer fonts: 11310201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+179A,U+17D2,U+1782 11320201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+1782,U+17D2,U+179A 11330201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod */ 113474f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod if (indic_plan->mask_array[CFAR]) 113574f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod for (; i < end; i++) 113674f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod info[i].mask |= indic_plan->mask_array[CFAR]; 11370201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 11388e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 11398e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 114056be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod } 114117d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod } 114217d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod 11439da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod /* Apply ZWJ/ZWNJ effects */ 11443c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start + 1; i < end; i++) 11459da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod if (is_joiner (info[i])) { 11469da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod bool non_joiner = info[i].indic_category() == OT_ZWNJ; 11476b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod unsigned int j = i; 11489da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 11499da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod do { 11509da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod j--; 11516b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 1152cfc507c5432e6327e8484b07b9e091212653bc92Behdad Esfahbod /* ZWJ/ZWNJ should disable CJCT. They do that by simply 1153cfc507c5432e6327e8484b07b9e091212653bc92Behdad Esfahbod * being there, since we don't skip them for the CJCT 1154a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod * feature (ie. F_MANUAL_ZWJ) */ 115520b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod 115620b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWNJ disables HALF. */ 11576b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod if (non_joiner) 115885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[j].mask &= ~indic_plan->mask_array[HALF]; 11596b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 11609da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } while (j > start && !is_consonant (info[j])); 11619da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } 1162743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1163743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1164743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1165743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 11668bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan, 1167f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 11689f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 1169ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1170743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 1171c5306b6861cfaa50af40e8ceb058791fa06d7981Behdad Esfahbod /* We made the vowels look like consonants. So let's call the consonant logic! */ 1172f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1173743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1174743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1175743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 11768bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, 1177f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 11789f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 1179ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1180743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 1181cf78dd483cbe1759a8ecb731879e041a53ba9bb3Behdad Esfahbod /* We treat placeholder/dotted-circle as if they are consonants, so we 1182cf78dd483cbe1759a8ecb731879e041a53ba9bb3Behdad Esfahbod * should just chain. Only if not in compatibility mode that is... */ 118318c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 1184bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 118518c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod { 118618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* For dotted-circle, this is what Uniscribe does: 118718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * If dotted-circle is the last glyph, it just does nothing. 118818c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Ie. It doesn't form Reph. */ 118918c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) 119018c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod return; 119118c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod } 119218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 1193f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1194743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1195743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1196743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 1197b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodinitial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan, 1198f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 1199b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer, 1200b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int start, unsigned int end) 1201b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1202b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod /* We already inserted dotted-circles, so just call the standalone_cluster. */ 1203f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_standalone_cluster (plan, face, buffer, start, end); 1204b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1205b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1206b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 12079f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbodinitial_reordering_symbol_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 12089f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod hb_face_t *face HB_UNUSED, 12099f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 12109f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 12113c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod{ 12123c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 12133c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 12143c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod} 12153c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod 12163c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbodstatic void 1217327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 1218f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face HB_UNUSED, 1219327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 1220327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 1221743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 1222743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 1223743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 1224743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1225743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1226327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1227743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 1228327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_syllable (const hb_ot_shape_plan_t *plan, 1229f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 1230327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer, 1231327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start, unsigned int end) 1232327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod{ 1233327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); 1234327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod switch (syllable_type) { 1235f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; 1236f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return; 1237f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return; 12389f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod case symbol_cluster: initial_reordering_symbol_cluster (plan, face, buffer, start, end); return; 1239f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; 1240f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return; 1241327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 1242327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod} 1243327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1244166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic inline void 12450beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbodinsert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, 1246b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_font_t *font, 1247b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer) 1248b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1249166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Note: This loop is extra overhead, but should not be measurable. */ 1250166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod bool has_broken_syllables = false; 1251166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod unsigned int count = buffer->len; 12527cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 1253166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod for (unsigned int i = 0; i < count; i++) 12547cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod if ((info[i].syllable() & 0x0F) == broken_cluster) 12557cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod { 1256166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod has_broken_syllables = true; 1257166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod break; 1258166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod } 1259166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if (likely (!has_broken_syllables)) 1260166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod return; 1261166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 1262166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 1263b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_codepoint_t dottedcircle_glyph; 12647627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph)) 1265b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return; 1266b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1267f41dc2d35b23220d59d38990bb66f1cbd66a55b3Behdad Esfahbod hb_glyph_info_t dottedcircle = {0}; 12687627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod dottedcircle.codepoint = 0x25CCu; 1269b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod set_indic_properties (dottedcircle); 1270b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = dottedcircle_glyph; 1271b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1272b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->clear_output (); 1273b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1274b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->idx = 0; 1275b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int last_syllable = 0; 1276b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod while (buffer->idx < buffer->len) 1277b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 1278b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int syllable = buffer->cur().syllable(); 1279b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); 1280b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) 1281b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 1282596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod last_syllable = syllable; 1283596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1284b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_glyph_info_t info = dottedcircle; 1285b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.cluster = buffer->cur().cluster; 1286b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.mask = buffer->cur().mask; 1287b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.syllable() = buffer->cur().syllable(); 1288596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1289596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod /* Insert dottedcircle after possible Repha. */ 1290596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod while (buffer->idx < buffer->len && 1291596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod last_syllable == buffer->cur().syllable() && 1292596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->cur().indic_category() == OT_Repha) 1293596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->next_glyph (); 1294596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1295b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->output_info (info); 1296b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 1297596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod else 1298596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->next_glyph (); 1299b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 1300b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1301b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->swap_buffers (); 1302b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1303b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1304b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 13058bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 130624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod hb_font_t *font, 13073e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1308743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 130985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod update_consonant_positions (plan, font, buffer); 1310166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod insert_dotted_circles (plan, font, buffer); 1311327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1312327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1313b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int count = buffer->len; 1314b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (!count)) return; 1315327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last = 0; 1316327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1317327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1318327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (last_syllable != info[i].syllable()) { 1319f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, i); 1320327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last = i; 1321327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last_syllable = info[last].syllable(); 1322327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 1323f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, count); 1324b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 1325b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 1326743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 132785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodfinal_reordering_syllable (const hb_ot_shape_plan_t *plan, 132885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer, 1329ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1330743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 133185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 13324ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 13334ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 133404dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod 133504dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod /* This function relies heavily on halant glyphs. Lots of ligation 133604dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod * and possibly multiplication substitutions happened prior to this 133704dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod * phase, and that might have messed up our properties. Recover 133804dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod * from a particular case of that where we're fairly sure that a 133904dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod * class of OT_H is desired but has been lost. */ 134004dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod if (indic_plan->virama_glyph) 134104dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod { 134204dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod unsigned int virama_glyph = indic_plan->virama_glyph; 134304dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod for (unsigned int i = start; i < end; i++) 134404dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod if (info[i].codepoint == virama_glyph && 134504dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod _hb_glyph_info_ligated (&info[i]) && 134604dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod _hb_glyph_info_multiplied (&info[i])) 134704dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod { 134804dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod /* This will make sure that this glyph passes is_halant_or_coeng() test. */ 134904dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod info[i].indic_category() = OT_H; 135004dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod _hb_glyph_info_clear_ligated_and_multiplied (&info[i]); 135104dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod } 135204dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod } 135304dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod 135404dc52fa15f5b7f9eb5f448ea43e7ef1b2269e88Behdad Esfahbod 1355e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod /* 4. Final reordering: 1356e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1357e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * After the localized forms and basic shaping forms GSUB features have been 1358e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * applied (see below), the shaping engine performs some final glyph 1359e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * reordering before applying all the remaining font features to the entire 1360e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * cluster. 13614ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 13624ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 13631d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod bool try_pref = !!indic_plan->mask_array[PREF]; 13641d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod 13654ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* Find base again */ 13665f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod unsigned int base; 13675f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod for (base = start; base < end; base++) 13681d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod if (info[base].indic_position() >= POS_BASE_C) 13691d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod { 13701d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod if (try_pref && base + 1 < end && indic_plan->config->pref_len == 2) 13711d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod { 13721d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 13731d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) 13741d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod { 13751d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod if (!(_hb_glyph_info_substituted (&info[i]) && 13761d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod _hb_glyph_info_ligated_and_didnt_multiply (&info[i]))) 13771d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod { 13781d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod /* Ok, this was a 'pref' candidate but didn't form any. 13791d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod * Base is around here... */ 13801d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod base = i; 13811d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod while (base < end && is_halant_or_coeng (info[base])) 13821d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod base++; 13831d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod info[base].indic_position() = POS_BASE_C; 13841d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod 13851d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod try_pref = false; 13861d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod } 13871d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod break; 13881d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod } 13891d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod } 13901d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod 13915f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (start < base && info[base].indic_position() > POS_BASE_C) 13925f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod base--; 13935f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod break; 13945f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod } 1395a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod if (base == end && start < base && 139639c8201f8e361e8c0f23f07bf20124ccadc6086cBehdad Esfahbod is_one_of (info[base - 1], FLAG (OT_ZWJ))) 1397a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod base--; 1398e7ce50d9eb6e3678f731b10dfeb308ffc478af8dBehdad Esfahbod if (base < end) 1399e7ce50d9eb6e3678f731b10dfeb308ffc478af8dBehdad Esfahbod while (start < base && 1400e7ce50d9eb6e3678f731b10dfeb308ffc478af8dBehdad Esfahbod is_one_of (info[base], (FLAG (OT_N) | HALANT_OR_COENG_FLAGS))) 1401e7ce50d9eb6e3678f731b10dfeb308ffc478af8dBehdad Esfahbod base--; 14024ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 14034705a7026900e51f6430f03a73c87f2df035df92Behdad Esfahbod 14044ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder matras: 1405e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1406e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base matra character had been reordered before applying basic 1407e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * features, the glyph can be moved closer to the main consonant based on 1408e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * whether half-forms had been formed. Actual position for the matra is 1409e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * defined as “after last standalone halant glyph, after initial matra 1410e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * position and before the main consonant”. If ZWJ or ZWNJ follow this 1411e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * halant, position is moved after it. 14124ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 14134ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 141465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ 14159d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 141665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we lost track of base, alas, position before last thingy. */ 141765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod unsigned int new_pos = base == end ? base - 2 : base - 1; 141865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 141927bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 142027bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 142127bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * We want to position matra after them. 142265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod */ 142327bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1424e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod { 142565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod while (new_pos > start && 1426c04d5f0dd24d0ed9560fb9aebb5561ce946743c3Behdad Esfahbod !(is_one_of (info[new_pos], (FLAG (OT_M) | HALANT_OR_COENG_FLAGS)))) 142765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos--; 142865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 142965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we found no Halant we are done. 143065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * Otherwise only proceed if the Halant does 143165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * not belong to the Matra itself! */ 143265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (is_halant_or_coeng (info[new_pos]) && 143365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod info[new_pos].indic_position() != POS_PRE_M) 143465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 143565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 143665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) 143765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos++; 143865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 143965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod else 144065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos = start; /* No move. */ 144165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 14429d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod 144327bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M) 144465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 14459d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* Now go see if there's actually any matras... */ 1446921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod for (unsigned int i = new_pos; i > start; i--) 14476a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[i - 1].indic_position () == POS_PRE_M) 14489d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 14491a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod unsigned int old_pos = i - 1; 14501a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 14511a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0])); 14521a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod info[new_pos] = tmp; 1453f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */ 1454f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod base--; 14559cb59d460e80d769087045535a8d54ec9ed7985cBehdad Esfahbod buffer->merge_clusters (new_pos, MIN (end, base + 1)); 1456921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod new_pos--; 14579d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 1458abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } else { 1459e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod for (unsigned int i = start; i < base; i++) 1460abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod if (info[i].indic_position () == POS_PRE_M) { 14612cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (i, MIN (end, base + 1)); 1462abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod break; 1463abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } 14649d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 14654ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod } 14664ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 14674ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 14684ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder reph: 1469e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1470e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Reph’s original position is always at the beginning of the syllable, 1471e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * (i.e. it is not reordered at the character reordering stage). However, 1472e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * it will be reordered according to the basic-forms shaping results. 1473e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Possible positions for reph, depending on the script, are; after main, 1474e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * before post-base consonant forms, and after post-base consonant forms. 1475dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 1476dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 147765a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod /* Two cases: 147865a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * 147965a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * - If repha is encoded as a sequence of characters (Ra,H or Ra,H,ZWJ), then 148065a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * we should only move it if the sequence ligated to the repha form. 148165a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * 148265a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * - If repha is encoded separately and in the logical position, we should only 148365a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * move it if it did NOT ligate. If it ligated, it's probably the font trying 148465a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * to make it work without the reordering. 148565a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod */ 1486f5299eff5c0065d6329cd536c0ac339abea085b0Behdad Esfahbod if (start + 1 < end && 1487f5299eff5c0065d6329cd536c0ac339abea085b0Behdad Esfahbod info[start].indic_position() == POS_RA_TO_BECOME_REPH && 14883ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod ((info[start].indic_category() == OT_Repha) ^ 1489832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod _hb_glyph_info_ligated_and_didnt_multiply (&info[start]))) 1490dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod { 149111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int new_reph_pos; 149211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos = indic_plan->config->reph_pos; 149311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 1494f175aa33c5e94397c60648ac0697c80f5fe0dcb7Behdad Esfahbod assert (reph_pos != REPH_POS_DONT_CARE); 149502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1496dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* 1. If reph should be positioned after post-base consonant forms, 1497dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to step 5. 149802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 149911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_POST) 150002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 15019d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_step_5; 150202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 150302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 150402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 2. If the reph repositioning class is not after post-base: target 1505dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is after the first explicit halant glyph between the 1506dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-reph consonant and last main consonant. If ZWJ or ZWNJ 1507dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * are following this halant, position is moved after it. If such 1508dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is found, this is the target position. Otherwise, 1509dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to the next step. 1510dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * 1511dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Note: in old-implementation fonts, where classifications were 1512dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * fixed in shaping engine, there was no case where reph position 1513dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * will be found on this step. 151402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 151502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 151602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = start + 1; 1517deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 151802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 151902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 15201f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) 15211f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod { 152202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 152302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 152402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 152502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 152602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 152702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 152802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 152902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 3. If reph should be repositioned after the main consonant: find the 1530dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first consonant not ligated with main, or find the first 1531dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant that is not a potential pre-base reordering Ra. 153202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 153311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_MAIN) 153402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1535b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos = base; 153634ae336f3fae93ef9372881d545c817bce383041Behdad Esfahbod while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN) 1537b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos++; 1538b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod if (new_reph_pos < end) 1539b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod goto reph_move; 154002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 154102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 154202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 4. If reph should be positioned before post-base consonant, find 1543dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-base classified consonant not ligated with main. If no 1544dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant is found, the target position should be before the 1545dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first matra, syllable modifier sign or vedic sign. 154602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 15479d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* This is our take on what step 4 is trying to say (and failing, BADLY). */ 154811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_SUB) 154902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 15509d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos = base; 15519d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod while (new_reph_pos < end && 1552be8b9f5f715f6fb36b98bd33c3303f79cc068f8aBehdad Esfahbod !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD)))) 15539d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos++; 15549d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (new_reph_pos < end) 15559d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_move; 155602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 155702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 155802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 5. If no consonant is found in steps 3 or 4, move reph to a position 1559dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * immediately before the first post-base matra, syllable modifier 1560dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * sign or vedic sign that has a reordering class after the intended 1561dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * reph position. For example, if the reordering position for reph 1562dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * is post-main, it will skip above-base matras that also have a 1563dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * post-main position. 1564dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 156502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_step_5: 156602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1567d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* Copied from step 2. */ 1568d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos = start + 1; 1569d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 1570d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1571d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod 15721f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) 15731f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod { 1574d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 1575d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 1576d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1577d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod goto reph_move; 1578d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod } 157902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1580dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 158102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 6. Otherwise, reorder reph to the end of the syllable. 158202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 158302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 158402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = end - 1; 158502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD) 158602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 158702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1588892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod /* 1589892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * If the Reph is to be ending up after a Matra,Halant sequence, 1590892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * position it before that Halant so it can interact with the Matra. 1591892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * However, if it's a plain Consonant,Halant we shouldn't do that. 1592892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * Uniscribe doesn't do this. 1593892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * TEST: U+0930,U+094D,U+0915,U+094B,U+094D 1594892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod */ 1595bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (!hb_options ().uniscribe_bug_compatible && 1596deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod unlikely (is_halant_or_coeng (info[new_reph_pos]))) { 159702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod for (unsigned int i = base + 1; i < new_reph_pos; i++) 159802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (info[i].indic_category() == OT_M) { 159902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Ok, got it. */ 160002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 160102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 160202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 160302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 16048df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod } 16058df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod 160602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_move: 160702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 16086b2abdcd203204131f3017ca85c91de9d43959cdBehdad Esfahbod buffer->merge_clusters (start, new_reph_pos + 1); 1609e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod 161002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Move */ 161102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod hb_glyph_info_t reph = info[start]; 161202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0])); 161302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod info[new_reph_pos] = reph; 1614f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod if (start < base && base <= new_reph_pos) 1615f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod base--; 161602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1617dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod } 1618dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1619dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1620dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* o Reorder pre-base reordering consonants: 1621e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1622e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base reordering consonant is found, reorder it according to 1623e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * the following rules: 1624e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod */ 1625e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 16261d634cbb4b0338e1c2841127a72c5fac3a2a5ca1Behdad Esfahbod if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ 162746e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod { 162846a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod unsigned int pref_len = indic_plan->config->pref_len; 16298e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 163085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) 163178818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod { 16328e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 1. Only reorder a glyph produced by substitution during application 16338e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * of the <pref> feature. (Note that a font may shape a Ra consonant with 16348e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * the feature generally but block it in certain contexts.) 16358e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 16369a49351cc2625de16a73e0e153d3097ef6c7cc0fBehdad Esfahbod /* Note: We just check that something got substituted. We don't check that 163746a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod * the <pref> feature actually did it... 163846a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod * 163946a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod * If pref len is longer than one, then only reorder if it ligated. If 164046a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod * pref len is one, only reorder if it didn't ligate with other things. */ 164146a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod if (_hb_glyph_info_substituted (&info[i]) && 1642832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod ((pref_len == 1) ^ _hb_glyph_info_ligated_and_didnt_multiply (&info[i]))) 16438e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 16448e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 16458e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 2. Try to find a target position the same way as for pre-base matra. 16468e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * If it is found, reorder pre-base consonant glyph. 16478e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 16488e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 3. If position is not found, reorder immediately before main 16498e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * consonant. 16508e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 16518e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 16528e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int new_pos = base; 165388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 165488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 165588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * We want to position matra after them. 165688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod */ 165788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1658d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 165988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod while (new_pos > start && 166088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS))) 166188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 166288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod 16639a49351cc2625de16a73e0e153d3097ef6c7cc0fBehdad Esfahbod /* In Khmer coeng model, a H,Ra can go *after* matras. If it goes after a 166488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * split matra, it should be reordered to *before* the left part of such matra. */ 166588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) 166688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 166788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod unsigned int old_pos = i; 166888d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod for (unsigned int i = base + 1; i < old_pos; i++) 166988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (info[i].indic_category() == OT_M) 167088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 167188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 167288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod break; 167388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 167488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 1675d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1676d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod 1677deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) 16781f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod { 16798e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 16808e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if (new_pos < end && is_joiner (info[new_pos])) 16818e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos++; 16821f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod } 16838e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 16848e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 16858e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int old_pos = i; 1686e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (new_pos, old_pos + 1); 16878e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 16888e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0])); 16898e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[new_pos] = tmp; 1690f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod if (new_pos <= base && base < old_pos) 1691f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod base++; 16928e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 16938e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 16948e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 16958e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 169678818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod } 169746e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod } 1698eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1699eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1700a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod /* Apply 'init' to the Left Matra if it's a word start. */ 17016a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[start].indic_position () == POS_PRE_M && 1702a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod (!start || 1703eace47b173807d94b29a6490d0bc3c9f8f6168d1Behdad Esfahbod !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & 17042c372b80f6befad69e216e3f218b38640b8cc044Behdad Esfahbod FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))) 170585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[start].mask |= indic_plan->mask_array[INIT]; 1706a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod 1707eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 17088ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod /* 17098ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod * Finish off the clusters and go home! 17108ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod */ 17119ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 1712ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 17139ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod switch ((hb_tag_t) plan->props.script) 17149ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod { 17159ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod case HB_SCRIPT_TAMIL: 17169ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod case HB_SCRIPT_SINHALA: 17179ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod break; 17189ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod 17199ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod default: 17209ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod /* Uniscribe merges the entire cluster... Except for Tamil & Sinhala. 17219ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod * This means, half forms are submerged into the main consonants cluster. 17229ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod * This is unnecessary, and makes cursor positioning harder, but that's what 17239ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod * Uniscribe does. */ 17249ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod buffer->merge_clusters (start, end); 17259ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod break; 17269ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod } 172721d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod } 1728ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod} 1729e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1730e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1731ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbodstatic void 17328bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 17330beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod hb_font_t *font HB_UNUSED, 17343e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1735ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod{ 1736ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int count = buffer->len; 1737327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (unlikely (!count)) return; 1738ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod 1739ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1740ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int last = 0; 1741cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1742ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1743cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod if (last_syllable != info[i].syllable()) { 174485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, i); 1745ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod last = i; 1746cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod last_syllable = info[last].syllable(); 1747ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod } 174885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, count); 1749e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1750743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); 1751743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); 1752743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1753743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1754743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 175530145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbodstatic void 175630145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbodclear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, 175730145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_font_t *font HB_UNUSED, 175830145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_buffer_t *buffer) 175930145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod{ 176030145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 176130145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod unsigned int count = buffer->len; 176230145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 176330145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod info[i].syllable() = 0; 176430145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod} 176530145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod 176630145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod 1767eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1768eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahboddecompose_indic (const hb_ot_shape_normalize_context_t *c, 17690736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t ab, 17700736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *a, 17710736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *b) 17720736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 17730736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod switch (ab) 17740736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 17750736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Don't decompose these. */ 17767627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x0931u : return false; 17777627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x0B94u : return false; 17780736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 17790736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 17800736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* 17810736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod * Decompose split matras that don't have Unicode decompositions. 17820736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod */ 17830736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 17847627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x0F77u : *a = 0x0FB2u; *b= 0x0F81u; return true; 17857627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x0F79u : *a = 0x0FB3u; *b= 0x0F81u; return true; 17867627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x17BEu : *a = 0x17C1u; *b= 0x17BEu; return true; 17877627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x17BFu : *a = 0x17C1u; *b= 0x17BFu; return true; 17887627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x17C0u : *a = 0x17C1u; *b= 0x17C0u; return true; 17897627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x17C4u : *a = 0x17C1u; *b= 0x17C4u; return true; 17907627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x17C5u : *a = 0x17C1u; *b= 0x17C5u; return true; 17917627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x1925u : *a = 0x1920u; *b= 0x1923u; return true; 17927627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x1926u : *a = 0x1920u; *b= 0x1924u; return true; 17937627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x1B3Cu : *a = 0x1B42u; *b= 0x1B3Cu; return true; 17947627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x1112Eu : *a = 0x11127u; *b= 0x11131u; return true; 17957627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x1112Fu : *a = 0x11127u; *b= 0x11132u; return true; 17960736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#if 0 17970736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* This one has no decomposition in Unicode, but needs no decomposition either. */ 17987627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod /* case 0x0AC9u : return false; */ 17997627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x0B57u : *a = no decomp, -> RIGHT; return true; 18007627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x1C29u : *a = no decomp, -> LEFT; return true; 18017627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0xA9C0u : *a = no decomp, -> RIGHT; return true; 18027627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod case 0x111BuF : *a = no decomp, -> ABOVE; return true; 18030736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#endif 18040736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 18050736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 18067627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if ((ab == 0x0DDAu || hb_in_range (ab, 0x0DDCu, 0x0DDEu))) 18070736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 180843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* 180943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Sinhala split matras... Let the fun begin. 181043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 181143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * These four characters have Unicode decompositions. However, Uniscribe 181243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * decomposes them "Khmer-style", that is, it uses the character itself to 181343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * get the second half. The first half of all four decompositions is always 181443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * U+0DD9. 181543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 181643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are 181743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * broken with Uniscribe. But we need to support them. As such, we only 181843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * do the Uniscribe-style decomposition if the character is transformed into 181943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * its "sec.half" form by the 'pstf' feature. Otherwise, we fall back to 182043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Unicode decomposition. 182143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 182243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Note that we can't unconditionally use Unicode decomposition. That would 182343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * break some other fonts, that are designed to work with Uniscribe, and 182443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * don't have positioning features for the Unicode-style decomposition. 182543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 182643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Argh... 1827b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * 1828b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * The Uniscribe behavior is now documented in the newly published Sinhala 1829b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * spec in 2012: 1830b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * 1831b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shaping 183243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod */ 183343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 183443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data; 183543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 183643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod hb_codepoint_t glyph; 183743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 1838bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible || 183943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod (c->font->get_glyph (ab, 0, &glyph) && 1840b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->pstf.would_substitute (&glyph, 1, c->font->face))) 184143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod { 184243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* Ok, safe to use Uniscribe-style decomposition. */ 18437627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod *a = 0x0DD9u; 184443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *b = ab; 184543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod return true; 184643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod } 18470736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 18480736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1849eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->decompose (ab, a, b); 18500736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 18510736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1852eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1853eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodcompose_indic (const hb_ot_shape_normalize_context_t *c, 18540736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t a, 18550736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t b, 18560736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *ab) 18570736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 18580736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Avoid recomposing split matras. */ 1859eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a))) 18600736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod return false; 18610736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 18620736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Composition-exclusion exceptions that we want to recompose. */ 18637627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if (a == 0x09AFu && b == 0x09BCu) { *ab = 0x09DFu; return true; } 18640736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1865eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->compose (a, b, ab); 18660736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 18670736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 18680736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1869693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = 1870693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{ 1871693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod "indic", 1872693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod collect_features_indic, 1873693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod override_features_indic, 1874a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_create_indic, 1875a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_destroy_indic, 18769f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod NULL, /* preprocess_text */ 18773d6ca0d32e5c6597acfcf59301cb1905586ddb52Behdad Esfahbod HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, 18780736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod decompose_indic, 18790736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod compose_indic, 1880693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod setup_masks_indic, 188171b4c999a511bf018acaf48a45e070470c0daf12Behdad Esfahbod HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, 1882865745b5b87236651f5663cae3461db9cb505eedBehdad Esfahbod false, /* fallback_position */ 1883693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod}; 1884