hb-ot-shape-complex-indic.cc revision 17c3b809f42aec34d83dba2e6229ad85804bebae
1b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod/* 227aba594c90b4444c35273a38f5fedc8e09d9a88Behdad Esfahbod * Copyright © 2011,2012 Google, Inc. 3b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 4b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * This is part of HarfBuzz, a text shaping library. 5b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 6b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * Permission is hereby granted, without written agreement and without 7b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this 8b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * software and its documentation for any purpose, provided that the 9b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * above copyright notice and the following two paragraphs appear in 10b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * all copies of this software. 11b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 12b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * DAMAGE. 17b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 18b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 24b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * Google Author(s): Behdad Esfahbod 25b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod */ 26b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 273ed4634ec349fa9e943ad23718c04be4dd4bba62Behdad Esfahbod#include "hb-ot-shape-complex-indic-private.hh" 2849c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod#include "hb-ot-layout-private.hh" 29352372ae5ea0998e40cf9fe43c22b6b610a5764eBehdad Esfahbod 303a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod/* buffer var allocations */ 313a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define indic_category() complex_var_u8_0() /* indic_category_t */ 323a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define indic_position() complex_var_u8_1() /* indic_position_t */ 333a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 343a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 353a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod/* 363a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Indic shaper. 373a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 383a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 393a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 403a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IN_HALF_BLOCK(u, Base) (((u) & ~0x7F) == (Base)) 413a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 423a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900)) 433a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980)) 443a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00)) 453a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80)) 463a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00)) 473a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80)) 483a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00)) 493a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80)) 503a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00)) 513a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80)) 523a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define IS_KHMR(u) (IN_HALF_BLOCK (u, 0x1780)) 533a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 543a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 553a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define MATRA_POS_LEFT(u) POS_PRE_M 563a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define MATRA_POS_RIGHT(u) ( \ 573a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_DEVA(u) ? POS_AFTER_SUB : \ 583a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_BENG(u) ? POS_AFTER_POST : \ 593a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_GURU(u) ? POS_AFTER_POST : \ 603a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_GUJR(u) ? POS_AFTER_POST : \ 613a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_ORYA(u) ? POS_AFTER_POST : \ 623a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_TAML(u) ? POS_AFTER_POST : \ 633a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_TELU(u) ? (u <= 0x0C42 ? POS_BEFORE_SUB : POS_AFTER_SUB) : \ 643a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_KNDA(u) ? (u < 0x0CC3 || u > 0xCD6 ? POS_BEFORE_SUB : POS_AFTER_SUB) : \ 653a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_MLYM(u) ? POS_AFTER_POST : \ 663a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_SINH(u) ? POS_AFTER_SUB : \ 673a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_KHMR(u) ? POS_AFTER_POST : \ 683a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /*default*/ POS_AFTER_SUB \ 693a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod ) 703a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define MATRA_POS_TOP(u) ( /* BENG and MLYM don't have top matras. */ \ 713a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_DEVA(u) ? POS_AFTER_SUB : \ 723a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_GURU(u) ? POS_AFTER_POST : /* Deviate from spec */ \ 733a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_GUJR(u) ? POS_AFTER_SUB : \ 743a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_ORYA(u) ? POS_AFTER_MAIN : \ 753a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_TAML(u) ? POS_AFTER_SUB : \ 763a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_TELU(u) ? POS_BEFORE_SUB : \ 773a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_KNDA(u) ? POS_BEFORE_SUB : \ 783a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_SINH(u) ? POS_AFTER_SUB : \ 793a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_KHMR(u) ? POS_AFTER_POST : \ 803a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /*default*/ POS_AFTER_SUB \ 813a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod ) 823a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define MATRA_POS_BOTTOM(u) ( \ 833a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_DEVA(u) ? POS_AFTER_SUB : \ 843a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_BENG(u) ? POS_AFTER_SUB : \ 853a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_GURU(u) ? POS_AFTER_POST : \ 863a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_GUJR(u) ? POS_AFTER_POST : \ 873a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_ORYA(u) ? POS_AFTER_SUB : \ 883a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_TAML(u) ? POS_AFTER_POST : \ 893a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_TELU(u) ? POS_BEFORE_SUB : \ 903a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_KNDA(u) ? POS_BEFORE_SUB : \ 913a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_MLYM(u) ? POS_AFTER_POST : \ 923a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_SINH(u) ? POS_AFTER_SUB : \ 933a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod IS_KHMR(u) ? POS_AFTER_POST : \ 943a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /*default*/ POS_AFTER_SUB \ 953a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod ) 963a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 973a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline indic_position_t 983a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodmatra_position (hb_codepoint_t u, indic_position_t side) 993a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1003a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod switch ((int) side) 1013a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 1023a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod case POS_PRE_C: return MATRA_POS_LEFT (u); 1033a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod case POS_POST_C: return MATRA_POS_RIGHT (u); 1043a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod case POS_ABOVE_C: return MATRA_POS_TOP (u); 1053a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod case POS_BELOW_C: return MATRA_POS_BOTTOM (u); 1063a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod }; 1073a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return side; 1083a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1093a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1103a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod/* XXX 1113a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * This is a hack for now. We should move this data into the main Indic table. 1123a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Or completely remove it and just check in the tables. 1133a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 1143a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic const hb_codepoint_t ra_chars[] = { 1153a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0930, /* Devanagari */ 1163a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x09B0, /* Bengali */ 1173a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x09F0, /* Bengali */ 1183a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0A30, /* Gurmukhi */ /* No Reph */ 1193a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0AB0, /* Gujarati */ 1203a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0B30, /* Oriya */ 1213a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0BB0, /* Tamil */ /* No Reph */ 1223a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0C30, /* Telugu */ /* Reph formed only with ZWJ */ 1233a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0CB0, /* Kannada */ 1243a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0D30, /* Malayalam */ /* No Reph, Logical Repha */ 1253a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1263a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x0DBB, /* Sinhala */ /* Reph formed only with ZWJ */ 1273a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1283a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 0x179A, /* Khmer */ /* No Reph, Visual Repha */ 1293a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod}; 1303a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1313a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1323a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_ra (hb_codepoint_t u) 1333a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1343a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++) 1353a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (u == ra_chars[i]) 1363a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return true; 1373a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return false; 1383a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1393a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1403a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1413a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_one_of (const hb_glyph_info_t &info, unsigned int flags) 1423a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1433a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* If it ligated, all bets are off. */ 144a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod if (_hb_glyph_info_ligated (&info)) return false; 1453a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return !!(FLAG (info.indic_category()) & flags); 1463a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1473a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1483a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad 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); 1713a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod indic_category_t cat = (indic_category_t) (type & 0x7F); 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 */ 190c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0x0951, 0x0952, 191e848bfae7c975a6fae434daf8e3db4d69914df9fBehdad Esfahbod 0x1CD0, 0x1CD2, 19272ead0cc72dac4d1c985ead065bb820f93f14a1dBehdad Esfahbod 0x1CD4, 0x1CE1) || 19337bf2c9224e32fdc99c20158c6dc0a4602ec1292Behdad Esfahbod u == 0x1CF4)) 19426c836e53d55a2e2d4c17fd9ea1884eec33ce015Behdad Esfahbod cat = OT_A; 195c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod /* The following act more like the Bindus. */ 196c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0953, 0x0954))) 197c11fc6833980fce6d70c5ae0c6623de97a3eb30aBehdad Esfahbod cat = OT_SM; 198e848bfae7c975a6fae434daf8e3db4d69914df9fBehdad Esfahbod /* Cantillation marks. */ 199e848bfae7c975a6fae434daf8e3db4d69914df9fBehdad Esfahbod else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xA8E0, 0xA8F1))) 20017c3b809f42aec34d83dba2e6229ad85804bebaeBehdad Esfahbod cat = OT_A; 201131e17ff9ae792cafa7a500043acb373802ee872Behdad Esfahbod /* The following act like consonants. */ 2022307268e01d27a999b56a2f573dfcee8b2a7949bBehdad Esfahbod else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0x0A72, 0x0A73, 2032307268e01d27a999b56a2f573dfcee8b2a7949bBehdad Esfahbod 0x1CF5, 0x1CF6))) 204131e17ff9ae792cafa7a500043acb373802ee872Behdad Esfahbod cat = OT_C; 205ecb98babbaa065940b40ca8954a454f0e2cdcff0Behdad Esfahbod /* TODO: The following should only be allowed after a Visarga. 206ecb98babbaa065940b40ca8954a454f0e2cdcff0Behdad Esfahbod * For now, just treat them like regular tone marks. */ 207ecb98babbaa065940b40ca8954a454f0e2cdcff0Behdad Esfahbod else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1CE2, 0x1CE8))) 208ecb98babbaa065940b40ca8954a454f0e2cdcff0Behdad Esfahbod cat = OT_A; 209e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod /* TODO: The following should only be allowed after some of 210e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod * the nasalization marks, maybe only for U+1CE9..U+1CF1. 211e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod * For now, just treat them like tone marks. */ 212e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod else if (unlikely (u == 0x1CED)) 213e9b2a4cfe593bdbe9288571635ba26ac42ede987Behdad Esfahbod cat = OT_A; 214a498565cedf0441ae723c5e5969f637d792a15e7Behdad Esfahbod /* The following are Visarga variants. */ 215a498565cedf0441ae723c5e5969f637d792a15e7Behdad Esfahbod else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1CF2, 0x1CF3))) 216a498565cedf0441ae723c5e5969f637d792a15e7Behdad Esfahbod { 217a498565cedf0441ae723c5e5969f637d792a15e7Behdad Esfahbod cat = OT_SM; 218a498565cedf0441ae723c5e5969f637d792a15e7Behdad Esfahbod ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_VISARGA == OT_SM); 219a498565cedf0441ae723c5e5969f637d792a15e7Behdad Esfahbod } 220d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod /* The following take marks in standalone clusters, similar to Avagraha. */ 221d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0xA8F2, 0xA8F7, 222d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod 0x1CE9, 0x1CEC, 223d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod 0x1CEE, 0x1CF1))) 224d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod { 225d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod cat = OT_Symbol; 226d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol); 227d19f8e85702a1e473efe2f02027984dcc127602aBehdad Esfahbod } 22852b562a6a058131c0103aaa5404d053e6465bb23Behdad Esfahbod else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CD, 0x17D1) || 22952b562a6a058131c0103aaa5404d053e6465bb23Behdad Esfahbod u == 0x17CB || u == 0x17D3 || u == 0x17DD)) /* Khmer Various signs */ 2303a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2313a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* These are like Top Matras. */ 2323a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_M; 2333a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = POS_ABOVE_C; 2343a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 23552b562a6a058131c0103aaa5404d053e6465bb23Behdad Esfahbod else if (unlikely (u == 0x17C6)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */ 23652b562a6a058131c0103aaa5404d053e6465bb23Behdad Esfahbod else if (unlikely (u == 0x17D2)) cat = OT_Coeng; /* Khmer coeng */ 2373a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (unlikely (u == 0x200C)) cat = OT_ZWNJ; 2383a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (unlikely (u == 0x200D)) cat = OT_ZWJ; 2393bf652b90783e8244c153739585d95dc4162efb4Behdad Esfahbod else if (unlikely (u == 0x002D || u == 0x00D7 || 2403bf652b90783e8244c153739585d95dc4162efb4Behdad Esfahbod hb_in_range<hb_codepoint_t> (u, 0x2010, 0x2014))) 2413bf652b90783e8244c153739585d95dc4162efb4Behdad Esfahbod cat = OT_PLACEHOLDER; 2423a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (unlikely (u == 0x25CC)) cat = OT_DOTTEDCIRCLE; 2433756efaf4e14ec3b5b1def700a1b5985f162372bBehdad Esfahbod else if (unlikely (u == 0x0A71)) cat = OT_SM; /* GURMUKHI ADDAK. Move it to the end. */ 244c16012e9019ec59c2200a3cc29b8a37ea70eda70Behdad Esfahbod else if (unlikely (u == 0xA982)) cat = OT_SM; /* Javanese repha. */ 245c16012e9019ec59c2200a3cc29b8a37ea70eda70Behdad Esfahbod else if (unlikely (u == 0xA9BE)) cat = OT_CM2; /* Javanese medial ya. */ 246c16012e9019ec59c2200a3cc29b8a37ea70eda70Behdad Esfahbod else if (unlikely (u == 0xA9BD)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */ 24752b562a6a058131c0103aaa5404d053e6465bb23Behdad Esfahbod else if (cat == OT_Repha) { 2483a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* There are two kinds of characters marked as Repha: 2493a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * - The ones that are GenCat=Mn are already positioned visually, ie. after base. (eg. Khmer) 2503a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * - The ones that are GenCat=Lo is encoded logically, ie. beginning of syllable. (eg. Malayalam) 2513a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * 2523a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * We recategorize the first kind to look like a Nukta and attached to the base directly. 2533a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 2543a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (_hb_glyph_info_get_general_category (&info) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 2553a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_N; 2563a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2577977ca17aac34b9ab10622928bed8afa2177f16aBehdad Esfahbod /* Decimal and Brahmi numbers. */ 2587977ca17aac34b9ab10622928bed8afa2177f16aBehdad Esfahbod else if (unlikely (_hb_glyph_info_get_general_category (&info) == 2597977ca17aac34b9ab10622928bed8afa2177f16aBehdad Esfahbod HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER || 2607977ca17aac34b9ab10622928bed8afa2177f16aBehdad Esfahbod hb_in_range<hb_codepoint_t> (u, 0x11052, 0x11065))) cat = OT_PLACEHOLDER; 2613a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2623a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2633a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2643a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* 2653a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Re-assign position. 2663a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 2673a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2683a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if ((FLAG (cat) & CONSONANT_FLAGS)) 2693a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 270c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod pos = POS_BASE_C; 2713a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (is_ra (u)) 2723a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_Ra; 2733a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2743a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (cat == OT_M) 2753a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2763a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = matra_position (u, pos); 2773a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2789f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol)))) 2793a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2803a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = POS_SMVD; 2813a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2823a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2833a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (unlikely (u == 0x0B01)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */ 2843a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2853a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2863a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2873a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod info.indic_category() = cat; 2883a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod info.indic_position() = pos; 2893a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 2903a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2913a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod/* 2923a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Things above this line should ideally be moved to the Indic table itself. 2933a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 2943a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2951d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 29611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 29711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic configurations. Note that we do not want to keep every single script-specific 29811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * behavior in these tables necessarily. This should mainly be used for per-script 29911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * properties that are cheaper keeping here, than in the code. Ie. if, say, one and 30011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * only one script has an exception, that one script can be if'ed directly in the code, 30111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * instead of adding a new flag in these structs. 30211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 30311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 30411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum base_position_t { 30511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_FIRST, 306e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod BASE_POS_LAST_SINHALA, 30711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_LAST 30811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 30911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_position_t { 31011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_MAIN = POS_AFTER_MAIN, 31111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_SUB = POS_BEFORE_SUB, 31211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_SUB = POS_AFTER_SUB, 31311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_POST = POS_BEFORE_POST, 31474f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod REPH_POS_AFTER_POST = POS_AFTER_POST, 31574f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod REPH_POS_DONT_CARE = POS_RA_TO_BECOME_REPH 31611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 31711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_mode_t { 31811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_IMPLICIT, /* Reph formed out of initial Ra,H sequence. */ 31911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_EXPLICIT, /* Reph formed out of initial Ra,H,ZWJ sequence. */ 32011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */ 32111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_LOG_REPHA /* Encoded Repha character, needs reordering. */ 32211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 3238acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbodenum blwf_mode_t { 3248acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod BLWF_MODE_PRE_AND_POST, /* Below-forms feature applied to pre-base and post-base. */ 3258acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod BLWF_MODE_POST_ONLY /* Below-forms feature applied to post-base only. */ 3268acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod}; 32774f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbodenum pref_len_t { 32874f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod PREF_LEN_1 = 1, 32974f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod PREF_LEN_2 = 2, 33074f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod PREF_LEN_DONT_CARE = PREF_LEN_2 33174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod}; 33211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstruct indic_config_t 33311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 33411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_script_t script; 33511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool has_old_spec; 33611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_codepoint_t virama; 33711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base_position_t base_pos; 33811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos; 33911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_mode_t reph_mode; 3408acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod blwf_mode_t blwf_mode; 34174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod pref_len_t pref_len; 34211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 34311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 34411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstatic const indic_config_t indic_configs[] = 34511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 34611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Default. Should be first. */ 34774f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1}, 34874f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 34974f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_BENGALI, true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 35074f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_GURMUKHI, true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 35174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_GUJARATI, true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 35274f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_ORIYA, true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 35374f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_TAMIL, true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, 35474f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_TELUGU, true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2}, 35574f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_KANNADA, true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2}, 35674f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, 357e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod {HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_LAST_SINHALA, 35874f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, 35974f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod {HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, 3608f9ec92dfce5c469fb85ad301296b5dde1b2ab0aBehdad Esfahbod {HB_SCRIPT_JAVANESE, false,0xA9C0,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1}, 36111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 36211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 36311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 36411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 36511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 36611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic shaper. 36711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 3689ccc6382ba43760167c134c18c1c4ada4b8c3f22Behdad Esfahbod 369eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstruct feature_list_t { 370c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_tag_t tag; 371ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod hb_ot_map_feature_flags_t flags; 372eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod}; 373eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 374eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstatic const feature_list_t 37585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodindic_features[] = 376b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 37785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 37885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Basic features. 37985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied in order, one at a time, after initial_reordering. 38085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 381a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('n','u','k','t'), F_GLOBAL}, 382a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('a','k','h','n'), F_GLOBAL}, 383a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('r','p','h','f'), F_NONE}, 384a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('r','k','r','f'), F_GLOBAL}, 385a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('p','r','e','f'), F_NONE}, 386a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('b','l','w','f'), F_NONE}, 387a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('a','b','v','f'), F_NONE}, 388a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod {HB_TAG('h','a','l','f'), F_NONE}, 389a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('p','s','t','f'), F_NONE}, 390a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('v','a','t','u'), F_GLOBAL}, 391a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('c','j','c','t'), F_GLOBAL}, 392a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod {HB_TAG('c','f','a','r'), F_NONE}, 39385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 39485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Other features. 39585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied all at once, after final_reordering. 396a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod * Default Bengali font in Windows for example has intermixed 397a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod * lookups for init,pres,abvs,blws features. 39885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 399ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('i','n','i','t'), F_NONE}, 400ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('p','r','e','s'), F_GLOBAL}, 401ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('a','b','v','s'), F_GLOBAL}, 402ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('b','l','w','s'), F_GLOBAL}, 403ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('p','s','t','s'), F_GLOBAL}, 404ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('h','a','l','n'), F_GLOBAL}, 40585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* Positioning features, though we don't care about the types. */ 406ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('d','i','s','t'), F_GLOBAL}, 407ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('a','b','v','m'), F_GLOBAL}, 408ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('b','l','w','m'), F_GLOBAL}, 409c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod}; 410c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod 41185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod/* 41285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Must be in the same order as the indic_features array. 41385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 414c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbodenum { 415c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod _NUKT, 416e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod _AKHN, 417c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod RPHF, 418df6d45c693c417bf311e6fa49f18a8558542e525Behdad Esfahbod _RKRF, 419c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PREF, 420167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod BLWF, 42129f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod ABVF, 422a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod HALF, 423c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PSTF, 42485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _VATU, 42570d656571194d2bd32671244530edbe159722cecBehdad Esfahbod _CJCT, 426a01cbf6cbe0021722302cfb58fb638a0a2427b26Behdad Esfahbod CFAR, 42785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 42885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INIT, 42985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PRES, 43085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVS, 43185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWS, 43285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PSTS, 43385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _HALN, 43485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _DIST, 43585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVM, 43685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWM, 43785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 43885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_NUM_FEATURES, 43985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */ 440b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod}; 441b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 442743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 443166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan, 444166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font, 445166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer); 446166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 4478bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 448afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 4493e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 450f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbodstatic void 4518bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 452afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 4533e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 45430145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbodstatic void 45530145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbodclear_syllables (const hb_ot_shape_plan_t *plan, 45630145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_font_t *font, 45730145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_buffer_t *buffer); 458b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 459693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 46016c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodcollect_features_indic (hb_ot_shape_planner_t *plan) 461b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 46216c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_ot_map_builder_t *map = &plan->map; 46316c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod 464166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Do this before any lookups have been applied. */ 465166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod map->add_gsub_pause (setup_syllables); 466166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 467e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod map->add_global_bool_feature (HB_TAG('l','o','c','l')); 468a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod /* The Indic specs do not require ccmp, but we apply it here since if 469a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod * there is a use of it, it's typically at the beginning. */ 470e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod map->add_global_bool_feature (HB_TAG('c','c','m','p')); 471f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 472f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 47385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod unsigned int i = 0; 47485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_gsub_pause (initial_reordering); 47585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_BASIC_FEATURES; i++) { 476a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ); 4773e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (NULL); 478412b91889d9a1ae477e8b6907d0b9a76e78a6c91Behdad Esfahbod } 4793e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (final_reordering); 48085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_NUM_FEATURES; i++) { 481a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ); 48285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 48342d0f55cbc68285e22d713df7062e520af708c82Behdad Esfahbod 48442d0f55cbc68285e22d713df7062e520af708c82Behdad Esfahbod map->add_global_bool_feature (HB_TAG('c','a','l','t')); 48542d0f55cbc68285e22d713df7062e520af708c82Behdad Esfahbod map->add_global_bool_feature (HB_TAG('c','l','i','g')); 48642d0f55cbc68285e22d713df7062e520af708c82Behdad Esfahbod 48730145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod map->add_gsub_pause (clear_syllables); 488b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 489b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 490693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 49116c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodoverride_features_indic (hb_ot_shape_planner_t *plan) 492d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod{ 493eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod /* Uniscribe does not apply 'kern' in Khmer. */ 494bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 495eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod { 496eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod switch ((hb_tag_t) plan->props.script) 497eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod { 498eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod case HB_SCRIPT_KHMER: 4999ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL); 500eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod break; 501eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod } 502eb10233b267909dee0245f126000e117f3b21c35Behdad Esfahbod } 5036b389ddc3623d042ded4731f4d62dc354002fdd0Behdad Esfahbod 504ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); 505d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod} 506d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod 507867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 50885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodstruct would_substitute_feature_t 509a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 510b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) 511a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 512b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod zero_context = zero_context_; 513a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_stage_lookups (0/*GSUB*/, 514a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_feature_stage (0/*GSUB*/, feature_tag), 515a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod &lookups, &count); 516a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 517a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 5188144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod inline bool would_substitute (const hb_codepoint_t *glyphs, 5198144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod unsigned int glyphs_count, 5208144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod hb_face_t *face) const 521a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 522a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 523362a990b2246f5448ecb9d600761f710aea7d42dBehdad Esfahbod if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) 524a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return true; 525a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return false; 526a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 527a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 528a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod private: 529a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const hb_ot_map_t::lookup_map_t *lookups; 530a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int count; 531b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod bool zero_context; 532a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 533a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 534a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstruct indic_shape_plan_t 535a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 53685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod ASSERT_POD (); 537914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 538914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const 539914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 540914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod hb_codepoint_t glyph = virama_glyph; 541914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (unlikely (virama_glyph == (hb_codepoint_t) -1)) 542914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 54311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!config->virama || !font->get_glyph (config->virama, 0, &glyph)) 544914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod glyph = 0; 545914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Technically speaking, the spec says we should apply 'locl' to virama too. 546914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * Maybe one day... */ 547914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 548914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Our get_glyph() function needs a font, so we can't get the virama glyph 549914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */ 550914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph; 551914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 552914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 553914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod *pglyph = glyph; 554914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod return glyph != 0; 555914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 55685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 55711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod const indic_config_t *config; 55885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 55985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod bool is_old_spec; 56085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_codepoint_t virama_glyph; 56185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 562f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod would_substitute_feature_t rphf; 56385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pref; 56485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t blwf; 56585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pstf; 56685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 56785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_mask_t mask_array[INDIC_NUM_FEATURES]; 568a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 569a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 570a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void * 571a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_create_indic (const hb_ot_shape_plan_t *plan) 572a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 57385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t)); 57485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (unlikely (!indic_plan)) 575a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return NULL; 576a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 57711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[0]; 57811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++) 57911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (plan->props.script == indic_configs[i].script) { 58011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[i]; 58111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 58285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 58311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 584851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2'); 58511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->virama_glyph = (hb_codepoint_t) -1; 58685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 587b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod /* Use zero-context would_substitute() matching for new-spec of the main 588828e109c7aac3389cc3b89ea1f13388aefb63804Behdad Esfahbod * Indic scripts, and scripts with one spec only, but not for old-specs. */ 589828e109c7aac3389cc3b89ea1f13388aefb63804Behdad Esfahbod bool zero_context = !indic_plan->is_old_spec; 590b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context); 591b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context); 592b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context); 593b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context); 59485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 59585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) 596ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ? 597ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod 0 : plan->map.get_1_mask (indic_features[i].tag); 598a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 59985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod return indic_plan; 600a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 601a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 602a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void 603a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_destroy_indic (void *data) 604a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 605a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod free (data); 606a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 607a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 608a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic indic_position_t 609a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodconsonant_position_from_face (const indic_shape_plan_t *indic_plan, 610684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod const hb_codepoint_t consonant, 611684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod const hb_codepoint_t virama, 6128144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod hb_face_t *face) 613a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 6148144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod /* For old-spec, the order of glyphs is Consonant,Virama, 6158144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * whereas for new-spec, it's Virama,Consonant. However, 6168144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * some broken fonts (like Free Sans) simply copied lookups 6178144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * from old-spec to new-spec without modification. 6188144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * And oddly enough, Uniscribe seems to respect those lookups. 6198144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds 6208144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * base at 0. The font however, only has lookups matching 6218144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * 930,94D in 'blwf', not the expected 94D,930 (with new-spec 6228144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * table). As such, we simply match both sequences. Seems 6238144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * to work. */ 624684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod hb_codepoint_t glyphs[3] = {virama, consonant, virama}; 625b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod if (indic_plan->blwf.would_substitute (glyphs , 2, face) || 626684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod indic_plan->blwf.would_substitute (glyphs+1, 2, face)) 6278144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod return POS_BELOW_C; 628b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod if (indic_plan->pstf.would_substitute (glyphs , 2, face) || 629684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod indic_plan->pstf.would_substitute (glyphs+1, 2, face)) 6308144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod return POS_POST_C; 63174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod unsigned int pref_len = indic_plan->config->pref_len; 63274f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod if ((pref_len == PREF_LEN_2 && 63374f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod (indic_plan->pref.would_substitute (glyphs , 2, face) || 63474f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod indic_plan->pref.would_substitute (glyphs+1, 2, face))) 63574f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod || (pref_len == PREF_LEN_1 && 63674f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod indic_plan->pref.would_substitute (glyphs+1, 1, face))) 637ae9a5834df477006686421d494b55a1569789327Behdad Esfahbod return POS_POST_C; 638a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return POS_BASE_C; 639a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 640a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 641a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 642166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodenum syllable_type_t { 643166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod consonant_syllable, 644166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod vowel_syllable, 645166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod standalone_cluster, 6469f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod symbol_cluster, 647166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod broken_cluster, 648166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod non_indic_cluster, 649166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod}; 650166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 651166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod#include "hb-ot-shape-complex-indic-machine.hh" 652166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 653166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 654693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 65516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodsetup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, 65616c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_buffer_t *buffer, 65716c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_font_t *font HB_UNUSED) 65824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 65924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); 66024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); 66124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 66224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod /* We cannot setup masks here. We save information about characters 66324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod * and setup masks later on in a pause-callback. */ 66424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 66524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod unsigned int count = buffer->len; 66624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 66724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod set_indic_properties (buffer->info[i]); 66824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 66924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 670166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 671166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, 672166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font HB_UNUSED, 673166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer) 674166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod{ 675166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod find_syllables (buffer); 676166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod} 677166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 67824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic int 67924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodcompare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 68024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 68124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int a = pa->indic_position(); 68224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int b = pb->indic_position(); 68324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 68424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod return a < b ? -1 : a == b ? 0 : +1; 68524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 68624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 68724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 68824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 68924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic void 6908bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodupdate_consonant_positions (const hb_ot_shape_plan_t *plan, 69185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 69285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer) 6938ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod{ 694a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 6958ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 696c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod if (indic_plan->config->base_pos != BASE_POS_LAST) 697c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod return; 698c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod 699684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod hb_codepoint_t virama; 700684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod if (indic_plan->get_virama_glyph (font, &virama)) 7018ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod { 7028ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_face_t *face = font->face; 7038ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod unsigned int count = buffer->len; 7048ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 7058ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod if (buffer->info[i].indic_position() == POS_BASE_C) { 706684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod hb_codepoint_t consonant = buffer->info[i].codepoint; 707684fe59ff858a0ecba71b3ed80378afb0b8bbb48Behdad Esfahbod buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face); 7088ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 7098ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 7108ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod} 7118ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 712867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 7137ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod/* Rules from: 7147ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ 7157ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod 716743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 717f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbodinitial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, 718f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 719f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_buffer_t *buffer, 720ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 721743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 722914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 723ee58f3bc75d2d071a71b94063bf12205a5871acbBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 724743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 725617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod 726743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 1. Find base consonant: 727743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 728743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The shaping engine finds the base consonant of the syllable, using the 729743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following algorithm: starting from the end of the syllable, move backwards 730743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * until a consonant is found that does not have a below-base or post-base 731743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * form (post-base forms have to follow below-base forms), or that is not a 732743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * pre-base reordering Ra, or arrive at the first consonant. The consonant 733743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * stopped at will be the base. 734743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 735743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o If the syllable starts with Ra + Halant (in a script that has Reph) 736743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 737743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * base consonants. 738743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 739743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 7405e72071062c015237b79fbd0521341a63166a204Behdad Esfahbod unsigned int base = end; 74176b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod bool has_reph = false; 742743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 74376b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod { 744617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 745617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 746617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * base consonants. */ 747617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod unsigned int limit = start; 748f175aa33c5e94397c60648ac0697c80f5fe0dcb7Behdad Esfahbod if (indic_plan->config->reph_pos != REPH_POS_DONT_CARE && 749efed40b975110d78c9c505441e7e17a8c13e85c8Behdad Esfahbod indic_plan->mask_array[RPHF] && 750617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod start + 3 <= end && 7518b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod ( 75211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || 75311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ) 7543285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod )) 755617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod { 756f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod /* See if it matches the 'rphf' feature. */ 75729531128f2f4342d537817746863705df80efe4bBehdad Esfahbod hb_codepoint_t glyphs[3] = {info[start].codepoint, 75829531128f2f4342d537817746863705df80efe4bBehdad Esfahbod info[start + 1].codepoint, 75929531128f2f4342d537817746863705df80efe4bBehdad Esfahbod indic_plan->config->reph_mode == REPH_MODE_EXPLICIT ? 76029531128f2f4342d537817746863705df80efe4bBehdad Esfahbod info[start + 2].codepoint : 0}; 76129531128f2f4342d537817746863705df80efe4bBehdad Esfahbod if (indic_plan->rphf.would_substitute (glyphs, 2, face) || 76229531128f2f4342d537817746863705df80efe4bBehdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && 76329531128f2f4342d537817746863705df80efe4bBehdad Esfahbod indic_plan->rphf.would_substitute (glyphs, 3, face))) 764f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod { 765f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit += 2; 766f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 767f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit++; 768f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod base = start; 769f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod has_reph = true; 770f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod } 7718b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha) 7728b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod { 7738b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod limit += 1; 7748b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 7758b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod limit++; 7768b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod base = start; 7778b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod has_reph = true; 7788b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod } 77976b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod 78023b0e9d7dc801e11640979af3c2b00649a519bb1Behdad Esfahbod switch (indic_plan->config->base_pos) 7815d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 782d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod default: 783d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod assert (false); 784d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod /* fallthrough */ 785d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod 78611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_LAST: 78711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 78811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> starting from the end of the syllable, move backwards */ 78911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int i = end; 79011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool seen_below = false; 79111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod do { 79211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod i--; 79311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> until a consonant is found */ 79411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i])) 7955d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 79611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> that does not have a below-base or post-base form 79711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * (post-base forms have to follow below-base forms), */ 79811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() != POS_BELOW_C && 79911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (info[i].indic_position() != POS_POST_C || seen_below)) 80011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 80111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 80211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 80311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 80411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() == POS_BELOW_C) 80511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod seen_below = true; 80611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 80711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or that is not a pre-base reordering Ra, 80811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 80911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * IMPLEMENTATION NOTES: 81011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 811fb7c182bf92142540bff1ad7fb82de0d115fb2b5Behdad Esfahbod * Our pre-base reordering Ra's are marked POS_POST_C, so will be skipped 81211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * by the logic above already. 81311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 81411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 81511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or arrive at the first consonant. The consonant stopped at will 81611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * be the base. */ 8175d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod base = i; 8185d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 81911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 82011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 82111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* A ZWJ after a Halant stops the base search, and requests an explicit 82211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * half form. 82311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * A ZWJ before a Halant, requests a subjoined form instead, and hence 82411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * search continues. This is particularly important for Bengali 825c4be9917438c45b972ec76dc68409014110f0837Behdad Esfahbod * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */ 82611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (start < i && 82711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_category() == OT_ZWJ && 82811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i - 1].indic_category() == OT_H) 82911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 83011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 83111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } while (i > limit); 83211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 83311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 8345d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 835e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod case BASE_POS_LAST_SINHALA: 83611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 837c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod /* Sinhala base positioning is slightly different from main Indic, in that: 838b082ef373cefb35dd98b5f2f0b677ccc7806f51eBehdad Esfahbod * 1. Its ZWJ behavior is different, 839c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod * 2. We don't need to look into the font for consonant positions. 840c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod */ 8415d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 84211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!has_reph) 84311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = limit; 84434c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 84511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Find the last base consonant that is not blocked by ZWJ. If there is 84611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * a ZWJ right before a base consonant, that would request a subjoined form. */ 84711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = limit; i < end; i++) 848c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod if (is_consonant (info[i])) 84911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 85011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (limit < i && info[i - 1].indic_category() == OT_ZWJ) 85111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 85211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 85311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 85411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 85534c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 85611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Mark all subsequent consonants as below. */ 85711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 858c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod if (is_consonant (info[i])) 85911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_position() = POS_BELOW_C; 86011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 86111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 862e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod 863e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod case BASE_POS_FIRST: 864e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod { 865e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod /* The first consonant is always the base. */ 866e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod 867e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod assert (indic_plan->config->reph_mode == REPH_MODE_VIS_REPHA); 868efed40b975110d78c9c505441e7e17a8c13e85c8Behdad Esfahbod assert (!has_reph); 869e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod 870e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod base = start; 871e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod 872e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod /* Mark all subsequent consonants as below. */ 873e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 874c4e71ff36d1f86a6ea56539728a964d97217e2b6Behdad Esfahbod if (is_consonant (info[i])) 875e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod info[i].indic_position() = POS_BELOW_C; 876e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod } 877e10453e6fb2544724ccd7ddfdbb9de90ef9274ceBehdad Esfahbod break; 8785d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 879743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 880617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 881617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 8822278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * base consonants. 8832278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * 8842278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ 8859621e0ba294c9cc6d458bbf632e63e92fda71e10Behdad Esfahbod if (has_reph && base == start && limit - base <= 2) { 886617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* Have no other consonant, so Reph is not formed and Ra becomes base. */ 887617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = false; 888617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod } 8895e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod } 8902278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod 8913d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 892743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 2. Decompose and reorder Matras: 893743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 894743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Each matra and any syllable modifier sign in the cluster are moved to the 895743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * appropriate position relative to the consonant(s) in the cluster. The 896743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * shaping engine decomposes two- or three-part matras into their constituent 897743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * parts before any repositioning. Matra characters are classified by which 898743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * consonant in a conjunct they have affinity for and are reordered to the 899743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following positions: 900743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 901743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o Before first half form in the syllable 902743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After subjoined consonants 903743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After post-form consonant 904743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After main consonant (for above marks) 905743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 906743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 907743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 908743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The normalize() routine has already decomposed matras for us, so we don't 909743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * need to worry about that. 910743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 911743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 912743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 913743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 3. Reorder marks to canonical order: 914743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 915743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Adjacent nukta and halant or nukta and vedic sign are always repositioned 916743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * if necessary, so that the nukta is first. 917743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 918743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 919743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 920743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * We don't need to do this: the normalize() routine already did this for us. 921743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 922743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 923743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 92445d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod /* Reorder characters */ 92545d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 9263c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 927900cf3d449bf36d4f8b1474590cae925fef48fc8Behdad Esfahbod info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position()); 92855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 929075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 930075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].indic_position() = POS_BASE_C; 93145d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 93255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod /* Mark final consonants. A final consonant is one appearing after a matra, 93355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod * like in Khmer. */ 93455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 93555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (info[i].indic_category() == OT_M) { 93655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int j = i + 1; j < end; j++) 93755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (is_consonant (info[j])) { 93855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod info[j].indic_position() = POS_FINAL_C; 93955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 94055f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 94155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 94255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 94355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 944fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod /* Handle beginning Ra */ 9455e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod if (has_reph) 946dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() = POS_RA_TO_BECOME_REPH; 947fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod 948f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* For old-style Indic script tags, move the first post-base Halant after 949ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod * last consonant. Only do this if there is *not* a Halant after last 950ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod * consonant. Otherwise it becomes messy. */ 951914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->is_old_spec) { 9523c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 953f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (info[i].indic_category() == OT_H) { 954f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod unsigned int j; 955f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod for (j = end - 1; j > i; j--) 956ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod if (is_consonant (info[j]) || info[j].indic_category() == OT_H) 957f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 958ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod if (info[j].indic_category() != OT_H && j > i) { 959f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* Move Halant to after last consonant. */ 960f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod hb_glyph_info_t t = info[i]; 961f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); 962f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod info[j] = t; 963f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 964f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 965f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 966f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 967f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod 96881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* Attach misc marks to previous char to move with them. */ 969ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 97081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod indic_position_t last_pos = POS_START; 97181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod for (unsigned int i = start; i < end; i++) 97281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 973c16012e9019ec59c2200a3cc29b8a37ea70eda70Behdad Esfahbod if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS))) 97481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 97581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() = last_pos; 976dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod if (unlikely (info[i].indic_category() == OT_H && 97781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() == POS_PRE_M)) 97881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 97981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* 98081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * Uniscribe doesn't move the Halant with Left Matra. 98181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * TEST: U+092B,U+093F,U+094DE 982dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We follow. This is important for the Sinhala 983dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA 984dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * where U+0DD9 is a left matra and U+0DCA is the virama. 985dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We don't want to move the virama with the left matra. 986dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * TEST: U+0D9A,U+0DDA 98781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod */ 988ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod for (unsigned int j = i; j > start; j--) 9896a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[j - 1].indic_position() != POS_PRE_M) { 990ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod info[i].indic_position() = info[j - 1].indic_position(); 991ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod break; 992ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 99381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 99481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } else if (info[i].indic_position() != POS_SMVD) { 99581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod last_pos = (indic_position_t) info[i].indic_position(); 996ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 99781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 998ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 999ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod /* For post-base consonants let them own anything before them 1000ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod * since the last consonant or matra. */ 100174ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod { 1002ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod unsigned int last = base; 100374ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 1004ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod if (is_consonant (info[i])) 1005ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod { 1006ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod for (unsigned int j = last + 1; j < i; j++) 1007ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod if (info[j].indic_position() < POS_SMVD) 100881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[j].indic_position() = info[i].indic_position(); 1009ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod last = i; 1010ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod } else if (info[i].indic_category() == OT_M) 1011ddce2d8df6fed9c033f1f13e235666680c5beb67Behdad Esfahbod last = i; 101274ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 101345d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 101428d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod 1015a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod { 101628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod /* Use syllable() for sort accounting temporarily. */ 101728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod unsigned int syllable = info[start].syllable(); 101828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod for (unsigned int i = start; i < end; i++) 101928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod info[i].syllable() = i - start; 102028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod 1021a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Sit tight, rock 'n roll! */ 1022d3637edb248162970e202e9d0671540274192844Behdad Esfahbod hb_bubble_sort (info + start, end - start, compare_indic_order); 1023a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Find base again */ 1024a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = end; 10253c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < end; i++) 102628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod if (info[i].indic_position() == POS_BASE_C) 102728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod { 102828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod base = i; 1029a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod break; 1030a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 103128d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod /* Things are out-of-control for post base positions, they may shuffle 103228d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod * around like crazy. In old-spec mode, we move halants around, so in 103328d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod * that case merge all clusters after base. Otherwise, check the sort 103428d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod * order and merge as needed. 103528d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod * For pre-base stuff, we handle cluster issues in final reordering. */ 103628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod if (indic_plan->is_old_spec || end - base > 127) 103728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod buffer->merge_clusters (base, end); 103828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod else 103928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod { 104028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod /* Note! syllable() is a one-byte field. */ 104128d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod for (unsigned int i = base; i < end; i++) 104228d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod if (info[i].syllable() != 255) 104328d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod { 104428d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod unsigned int max = i; 104528d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod unsigned int j = start + info[i].syllable(); 104628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod while (j != i) 104728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod { 104828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod max = MAX (max, j); 104928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod unsigned int next = start + info[j].syllable(); 105028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod info[j].syllable() = 255; /* So we don't process j later again. */ 105128d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod j = next; 105228d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod } 105328d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod if (i != max) 105428d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod buffer->merge_clusters (i, max + 1); 105528d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod } 105628d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod } 105728d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod 105828d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod /* Put syllable back in. */ 105928d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod for (unsigned int i = start; i < end; i++) 106028d5daec948e1a24f13e492ce301aeb9abff37c8Behdad Esfahbod info[i].syllable() = syllable; 1061a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 106245d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 1063743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Setup masks now */ 1064743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1065281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod { 1066281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod hb_mask_t mask; 1067281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod 1068dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* Reph */ 1069668c6046c1b3af3bd316bda0cc8636f2a5e8df42Behdad Esfahbod for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) 107085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[RPHF]; 1071dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1072281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Pre-base */ 107385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[HALF]; 1074c7dacac02cfe8526eaf131ce6c5e7b6df7ca2ccdBehdad Esfahbod if (!indic_plan->is_old_spec && 1075c7dacac02cfe8526eaf131ce6c5e7b6df7ca2ccdBehdad Esfahbod indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST) 10768acbb6be271817c12d2ee0066b355e2fb0f9a934Behdad Esfahbod mask |= indic_plan->mask_array[BLWF]; 10773c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 1078281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 1079281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Base */ 108020b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = 0; 1081075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 1082075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].mask |= mask; 1083281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Post-base */ 108485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF]; 10853c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 1086281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 1087281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod } 10889da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 108985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod if (indic_plan->is_old_spec && 109085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod buffer->props.script == HB_SCRIPT_DEVANAGARI) 109185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod { 109285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod /* Old-spec eye-lash Ra needs special handling. From the 109385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * spec: 109485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 109585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * "The feature 'below-base form' is applied to consonants 109685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * having below-base forms and following the base consonant. 109785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * The exception is vattu, which may appear below half forms 109885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * as well as below the base glyph. The feature 'below-base 109985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * form' will be applied to all such occurrences of Ra as well." 110085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 110185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * Test case: U+0924,U+094D,U+0930,U+094d,U+0915 110285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * with Sanskrit 2003 font. 110385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 110485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * However, note that Ra,Halant,ZWJ is the correct way to 110585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * request eyelash form of Ra, so we wouldbn't inhibit it 110685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * in that sequence. 110785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 110885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915 110985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod */ 111085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod for (unsigned int i = start; i + 1 < base; i++) 111185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod if (info[i ].indic_category() == OT_Ra && 111285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+1].indic_category() == OT_H && 111385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod (i + 2 == base || 111485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+2].indic_category() != OT_ZWJ)) 111585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod { 111685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i ].mask |= indic_plan->mask_array[BLWF]; 111785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+1].mask |= indic_plan->mask_array[BLWF]; 111885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod } 111985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod } 112085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod 112174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod unsigned int pref_len = indic_plan->config->pref_len; 112274f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + pref_len < end) 112317d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod { 112474f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod assert (1 <= pref_len && pref_len <= 2); 1125771a8f50289e8fa458cfc3cd84f73a380ce98077Behdad Esfahbod /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ 112674f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) { 112774f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod hb_codepoint_t glyphs[2]; 112874f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod for (unsigned int j = 0; j < pref_len; j++) 112974f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod glyphs[j] = info[i + j].codepoint; 113074f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, pref_len, face)) 11318e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 113274f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod for (unsigned int j = 0; j < pref_len; j++) 113374f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 11340201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 11350201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod /* Mark the subsequent stuff with 'cfar'. Used in Khmer. 11360201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * Read the feature spec. 11370201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * This allows distinguishing the following cases with MS Khmer fonts: 11380201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+179A,U+17D2,U+1782 11390201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+1782,U+17D2,U+179A 11400201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod */ 114174f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod if (indic_plan->mask_array[CFAR]) 114274f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod for (; i < end; i++) 114374f4bbf0560a5fd2d295e100e96f0c6c7033e852Behdad Esfahbod info[i].mask |= indic_plan->mask_array[CFAR]; 11440201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 11458e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 11468e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 114756be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod } 114817d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod } 114917d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod 11509da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod /* Apply ZWJ/ZWNJ effects */ 11513c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start + 1; i < end; i++) 11529da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod if (is_joiner (info[i])) { 11539da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod bool non_joiner = info[i].indic_category() == OT_ZWNJ; 11546b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod unsigned int j = i; 11559da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 11569da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod do { 11579da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod j--; 11586b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 1159cfc507c5432e6327e8484b07b9e091212653bc92Behdad Esfahbod /* ZWJ/ZWNJ should disable CJCT. They do that by simply 1160cfc507c5432e6327e8484b07b9e091212653bc92Behdad Esfahbod * being there, since we don't skip them for the CJCT 1161a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod * feature (ie. F_MANUAL_ZWJ) */ 116220b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod 116320b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWNJ disables HALF. */ 11646b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod if (non_joiner) 116585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[j].mask &= ~indic_plan->mask_array[HALF]; 11666b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 11679da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } while (j > start && !is_consonant (info[j])); 11689da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } 1169743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1170743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1171743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1172743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 11738bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan, 1174f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 11759f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 1176ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1177743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 1178c5306b6861cfaa50af40e8ceb058791fa06d7981Behdad Esfahbod /* We made the vowels look like consonants. So let's call the consonant logic! */ 1179f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1180743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1181743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1182743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 11838bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, 1184f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 11859f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 1186ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1187743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 1188cf78dd483cbe1759a8ecb731879e041a53ba9bb3Behdad Esfahbod /* We treat placeholder/dotted-circle as if they are consonants, so we 1189cf78dd483cbe1759a8ecb731879e041a53ba9bb3Behdad Esfahbod * should just chain. Only if not in compatibility mode that is... */ 119018c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 1191bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 119218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod { 119318c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* For dotted-circle, this is what Uniscribe does: 119418c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * If dotted-circle is the last glyph, it just does nothing. 119518c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Ie. It doesn't form Reph. */ 119618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) 119718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod return; 119818c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod } 119918c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 1200f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1201743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1202743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1203743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 1204b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodinitial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan, 1205f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 1206b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer, 1207b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int start, unsigned int end) 1208b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1209b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod /* We already inserted dotted-circles, so just call the standalone_cluster. */ 1210f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_standalone_cluster (plan, face, buffer, start, end); 1211b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1212b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1213b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 12149f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbodinitial_reordering_symbol_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 12159f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod hb_face_t *face HB_UNUSED, 12169f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 12179f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 12183c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod{ 12193c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 12203c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 12213c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod} 12223c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbod 12233c7b3641cfb00f2c4dcc0768b9854e4f4410d15fBehdad Esfahbodstatic void 1224327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 1225f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face HB_UNUSED, 1226327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 1227327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 1228743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 1229743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 1230743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 1231743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1232743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1233327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1234743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 1235327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_syllable (const hb_ot_shape_plan_t *plan, 1236f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 1237327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer, 1238327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start, unsigned int end) 1239327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod{ 1240327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); 1241327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod switch (syllable_type) { 1242f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; 1243f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return; 1244f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return; 12459f9bd9bf31161660214b8b39a78cdafbb79db1beBehdad Esfahbod case symbol_cluster: initial_reordering_symbol_cluster (plan, face, buffer, start, end); return; 1246f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; 1247f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return; 1248327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 1249327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod} 1250327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1251166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic inline void 12520beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbodinsert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, 1253b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_font_t *font, 1254b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer) 1255b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1256166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Note: This loop is extra overhead, but should not be measurable. */ 1257166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod bool has_broken_syllables = false; 1258166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod unsigned int count = buffer->len; 1259166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod for (unsigned int i = 0; i < count; i++) 1260166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) { 1261166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod has_broken_syllables = true; 1262166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod break; 1263166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod } 1264166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if (likely (!has_broken_syllables)) 1265166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod return; 1266166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 1267166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 1268b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_codepoint_t dottedcircle_glyph; 1269b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) 1270b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return; 1271b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1272f41dc2d35b23220d59d38990bb66f1cbd66a55b3Behdad Esfahbod hb_glyph_info_t dottedcircle = {0}; 1273b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = 0x25CC; 1274b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod set_indic_properties (dottedcircle); 1275b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = dottedcircle_glyph; 1276b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1277b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->clear_output (); 1278b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1279b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->idx = 0; 1280b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int last_syllable = 0; 1281b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod while (buffer->idx < buffer->len) 1282b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 1283b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int syllable = buffer->cur().syllable(); 1284b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); 1285b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) 1286b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 1287596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod last_syllable = syllable; 1288596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1289b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_glyph_info_t info = dottedcircle; 1290b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.cluster = buffer->cur().cluster; 1291b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.mask = buffer->cur().mask; 1292b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.syllable() = buffer->cur().syllable(); 1293596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1294596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod /* Insert dottedcircle after possible Repha. */ 1295596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod while (buffer->idx < buffer->len && 1296596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod last_syllable == buffer->cur().syllable() && 1297596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->cur().indic_category() == OT_Repha) 1298596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->next_glyph (); 1299596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1300b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->output_info (info); 1301b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 1302596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod else 1303596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->next_glyph (); 1304b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 1305b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1306b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->swap_buffers (); 1307b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1308b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1309b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 13108bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 131124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod hb_font_t *font, 13123e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1313743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 131485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod update_consonant_positions (plan, font, buffer); 1315166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod insert_dotted_circles (plan, font, buffer); 1316327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1317327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1318b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int count = buffer->len; 1319b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (!count)) return; 1320327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last = 0; 1321327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1322327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1323327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (last_syllable != info[i].syllable()) { 1324f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, i); 1325327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last = i; 1326327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last_syllable = info[last].syllable(); 1327327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 1328f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, count); 1329b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 1330b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 1331743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 133285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodfinal_reordering_syllable (const hb_ot_shape_plan_t *plan, 133385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer, 1334ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1335743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 133685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 13374ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 13384ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 1339e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod /* 4. Final reordering: 1340e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1341e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * After the localized forms and basic shaping forms GSUB features have been 1342e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * applied (see below), the shaping engine performs some final glyph 1343e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * reordering before applying all the remaining font features to the entire 1344e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * cluster. 13454ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 13464ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 13474ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* Find base again */ 13485f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod unsigned int base; 13495f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod for (base = start; base < end; base++) 13505f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (info[base].indic_position() >= POS_BASE_C) { 13515f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (start < base && info[base].indic_position() > POS_BASE_C) 13525f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod base--; 13535f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod break; 13545f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod } 1355a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod if (base == end && start < base && 1356a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod info[base - 1].indic_category() != OT_ZWJ) 1357a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod base--; 1358a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod while (start < base && 1359a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod (info[base].indic_category() == OT_H || 1360a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod info[base].indic_category() == OT_N)) 1361a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod base--; 13624ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 13634705a7026900e51f6430f03a73c87f2df035df92Behdad Esfahbod 13644ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder matras: 1365e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1366e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base matra character had been reordered before applying basic 1367e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * features, the glyph can be moved closer to the main consonant based on 1368e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * whether half-forms had been formed. Actual position for the matra is 1369e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * defined as “after last standalone halant glyph, after initial matra 1370e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * position and before the main consonant”. If ZWJ or ZWNJ follow this 1371e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * halant, position is moved after it. 13724ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 13734ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 137465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ 13759d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 137665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we lost track of base, alas, position before last thingy. */ 137765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod unsigned int new_pos = base == end ? base - 2 : base - 1; 137865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 137927bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 138027bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 138127bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * We want to position matra after them. 138265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod */ 138327bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1384e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod { 138565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod while (new_pos > start && 138665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng))))) 138765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos--; 138865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 138965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we found no Halant we are done. 139065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * Otherwise only proceed if the Halant does 139165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * not belong to the Matra itself! */ 139265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (is_halant_or_coeng (info[new_pos]) && 139365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod info[new_pos].indic_position() != POS_PRE_M) 139465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 139565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 139665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) 139765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos++; 139865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 139965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod else 140065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos = start; /* No move. */ 140165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 14029d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod 140327bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M) 140465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 14059d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* Now go see if there's actually any matras... */ 1406921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod for (unsigned int i = new_pos; i > start; i--) 14076a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[i - 1].indic_position () == POS_PRE_M) 14089d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 14091a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod unsigned int old_pos = i - 1; 14101a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 14111a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0])); 14121a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod info[new_pos] = tmp; 1413f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */ 1414f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod base--; 14159cb59d460e80d769087045535a8d54ec9ed7985cBehdad Esfahbod buffer->merge_clusters (new_pos, MIN (end, base + 1)); 1416921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod new_pos--; 14179d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 1418abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } else { 1419e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod for (unsigned int i = start; i < base; i++) 1420abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod if (info[i].indic_position () == POS_PRE_M) { 14212cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (i, MIN (end, base + 1)); 1422abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod break; 1423abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } 14249d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 14254ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod } 14264ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 14274ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 14284ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder reph: 1429e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1430e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Reph’s original position is always at the beginning of the syllable, 1431e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * (i.e. it is not reordered at the character reordering stage). However, 1432e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * it will be reordered according to the basic-forms shaping results. 1433e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Possible positions for reph, depending on the script, are; after main, 1434e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * before post-base consonant forms, and after post-base consonant forms. 1435dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 1436dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 143765a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod /* Two cases: 143865a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * 143965a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * - If repha is encoded as a sequence of characters (Ra,H or Ra,H,ZWJ), then 144065a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * we should only move it if the sequence ligated to the repha form. 144165a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * 144265a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * - If repha is encoded separately and in the logical position, we should only 144365a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * move it if it did NOT ligate. If it ligated, it's probably the font trying 144465a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod * to make it work without the reordering. 144565a929b1c033e91919c931b495a775f76b6dcbb3Behdad Esfahbod */ 1446f5299eff5c0065d6329cd536c0ac339abea085b0Behdad Esfahbod if (start + 1 < end && 1447f5299eff5c0065d6329cd536c0ac339abea085b0Behdad Esfahbod info[start].indic_position() == POS_RA_TO_BECOME_REPH && 14483ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod ((info[start].indic_category() == OT_Repha) ^ 1449a1f7b2856184959e965c9c2b80363f9f46d486a7Behdad Esfahbod _hb_glyph_info_ligated (&info[start]))) 1450dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod { 145111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int new_reph_pos; 145211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos = indic_plan->config->reph_pos; 145311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 1454f175aa33c5e94397c60648ac0697c80f5fe0dcb7Behdad Esfahbod assert (reph_pos != REPH_POS_DONT_CARE); 145502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1456dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* 1. If reph should be positioned after post-base consonant forms, 1457dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to step 5. 145802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 145911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_POST) 146002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 14619d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_step_5; 146202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 146302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 146402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 2. If the reph repositioning class is not after post-base: target 1465dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is after the first explicit halant glyph between the 1466dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-reph consonant and last main consonant. If ZWJ or ZWNJ 1467dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * are following this halant, position is moved after it. If such 1468dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is found, this is the target position. Otherwise, 1469dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to the next step. 1470dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * 1471dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Note: in old-implementation fonts, where classifications were 1472dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * fixed in shaping engine, there was no case where reph position 1473dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * will be found on this step. 147402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 147502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 147602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = start + 1; 1477deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 147802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 147902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 14801f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) 14811f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod { 148202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 148302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 148402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 148502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 148602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 148702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 148802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 148902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 3. If reph should be repositioned after the main consonant: find the 1490dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first consonant not ligated with main, or find the first 1491dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant that is not a potential pre-base reordering Ra. 149202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 149311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_MAIN) 149402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1495b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos = base; 149634ae336f3fae93ef9372881d545c817bce383041Behdad Esfahbod while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN) 1497b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos++; 1498b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod if (new_reph_pos < end) 1499b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod goto reph_move; 150002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 150102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 150202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 4. If reph should be positioned before post-base consonant, find 1503dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-base classified consonant not ligated with main. If no 1504dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant is found, the target position should be before the 1505dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first matra, syllable modifier sign or vedic sign. 150602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 15079d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* This is our take on what step 4 is trying to say (and failing, BADLY). */ 150811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_SUB) 150902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 15109d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos = base; 15119d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod while (new_reph_pos < end && 1512be8b9f5f715f6fb36b98bd33c3303f79cc068f8aBehdad Esfahbod !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD)))) 15139d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos++; 15149d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (new_reph_pos < end) 15159d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_move; 151602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 151702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 151802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 5. If no consonant is found in steps 3 or 4, move reph to a position 1519dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * immediately before the first post-base matra, syllable modifier 1520dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * sign or vedic sign that has a reordering class after the intended 1521dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * reph position. For example, if the reordering position for reph 1522dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * is post-main, it will skip above-base matras that also have a 1523dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * post-main position. 1524dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 152502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_step_5: 152602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1527d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* Copied from step 2. */ 1528d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos = start + 1; 1529d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 1530d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1531d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod 15321f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) 15331f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod { 1534d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 1535d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 1536d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1537d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod goto reph_move; 1538d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod } 153902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1540dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 154102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 6. Otherwise, reorder reph to the end of the syllable. 154202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 154302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 154402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = end - 1; 154502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD) 154602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 154702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1548892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod /* 1549892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * If the Reph is to be ending up after a Matra,Halant sequence, 1550892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * position it before that Halant so it can interact with the Matra. 1551892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * However, if it's a plain Consonant,Halant we shouldn't do that. 1552892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * Uniscribe doesn't do this. 1553892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * TEST: U+0930,U+094D,U+0915,U+094B,U+094D 1554892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod */ 1555bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (!hb_options ().uniscribe_bug_compatible && 1556deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod unlikely (is_halant_or_coeng (info[new_reph_pos]))) { 155702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod for (unsigned int i = base + 1; i < new_reph_pos; i++) 155802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (info[i].indic_category() == OT_M) { 155902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Ok, got it. */ 156002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 156102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 156202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 156302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 15648df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod } 15658df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod 156602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_move: 156702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 15686b2abdcd203204131f3017ca85c91de9d43959cdBehdad Esfahbod buffer->merge_clusters (start, new_reph_pos + 1); 1569e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod 157002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Move */ 157102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod hb_glyph_info_t reph = info[start]; 157202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0])); 157302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod info[new_reph_pos] = reph; 1574f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod if (start < base && base <= new_reph_pos) 1575f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod base--; 157602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1577dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod } 1578dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1579dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1580dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* o Reorder pre-base reordering consonants: 1581e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1582e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base reordering consonant is found, reorder it according to 1583e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * the following rules: 1584e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod */ 1585e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 158685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ 158746e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod { 158846a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod unsigned int pref_len = indic_plan->config->pref_len; 15898e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 159085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) 159178818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod { 15928e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 1. Only reorder a glyph produced by substitution during application 15938e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * of the <pref> feature. (Note that a font may shape a Ra consonant with 15948e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * the feature generally but block it in certain contexts.) 15958e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 15969a49351cc2625de16a73e0e153d3097ef6c7cc0fBehdad Esfahbod /* Note: We just check that something got substituted. We don't check that 159746a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod * the <pref> feature actually did it... 159846a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod * 159946a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod * If pref len is longer than one, then only reorder if it ligated. If 160046a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod * pref len is one, only reorder if it didn't ligate with other things. */ 160146a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod if (_hb_glyph_info_substituted (&info[i]) && 160246a863d91dbcc9a4c796e3715ea3828939f4d941Behdad Esfahbod ((pref_len == 1) ^ _hb_glyph_info_ligated (&info[i]))) 16038e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 16048e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 16058e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 2. Try to find a target position the same way as for pre-base matra. 16068e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * If it is found, reorder pre-base consonant glyph. 16078e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 16088e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 3. If position is not found, reorder immediately before main 16098e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * consonant. 16108e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 16118e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 16128e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int new_pos = base; 161388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 161488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 161588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * We want to position matra after them. 161688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod */ 161788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1618d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 161988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod while (new_pos > start && 162088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS))) 162188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 162288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod 16239a49351cc2625de16a73e0e153d3097ef6c7cc0fBehdad Esfahbod /* In Khmer coeng model, a H,Ra can go *after* matras. If it goes after a 162488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * split matra, it should be reordered to *before* the left part of such matra. */ 162588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) 162688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 162788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod unsigned int old_pos = i; 162888d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod for (unsigned int i = base + 1; i < old_pos; i++) 162988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (info[i].indic_category() == OT_M) 163088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 163188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 163288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod break; 163388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 163488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 1635d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1636d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod 1637deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) 16381f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod { 16398e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 16408e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if (new_pos < end && is_joiner (info[new_pos])) 16418e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos++; 16421f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod } 16438e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 16448e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 16458e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int old_pos = i; 1646e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (new_pos, old_pos + 1); 16478e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 16488e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0])); 16498e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[new_pos] = tmp; 1650f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod if (new_pos <= base && base < old_pos) 1651f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod base++; 16528e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 16538e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 16548e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 16558e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 165678818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod } 165746e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod } 1658eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1659eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1660a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod /* Apply 'init' to the Left Matra if it's a word start. */ 16616a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[start].indic_position () == POS_PRE_M && 1662a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod (!start || 1663eace47b173807d94b29a6490d0bc3c9f8f6168d1Behdad Esfahbod !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & 16642c372b80f6befad69e216e3f218b38640b8cc044Behdad Esfahbod FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))) 166585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[start].mask |= indic_plan->mask_array[INIT]; 1666a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod 1667eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 16688ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod /* 16698ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod * Finish off the clusters and go home! 16708ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod */ 16719ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 1672ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 16739ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod switch ((hb_tag_t) plan->props.script) 16749ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod { 16759ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod case HB_SCRIPT_TAMIL: 16769ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod case HB_SCRIPT_SINHALA: 16779ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod break; 16789ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod 16799ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod default: 16809ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod /* Uniscribe merges the entire cluster... Except for Tamil & Sinhala. 16819ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod * This means, half forms are submerged into the main consonants cluster. 16829ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod * This is unnecessary, and makes cursor positioning harder, but that's what 16839ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod * Uniscribe does. */ 16849ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod buffer->merge_clusters (start, end); 16859ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod break; 16869ac6b01e0cd8e2d66dfc727157f45b615bc77109Behdad Esfahbod } 168721d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod } 1688ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod} 1689e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1690e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1691ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbodstatic void 16928bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 16930beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod hb_font_t *font HB_UNUSED, 16943e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1695ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod{ 1696ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int count = buffer->len; 1697327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (unlikely (!count)) return; 1698ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod 1699ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1700ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int last = 0; 1701cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1702ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1703cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod if (last_syllable != info[i].syllable()) { 170485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, i); 1705ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod last = i; 1706cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod last_syllable = info[last].syllable(); 1707ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod } 170885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, count); 1709e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1710743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); 1711743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); 1712743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1713743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1714743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 171530145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbodstatic void 171630145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbodclear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, 171730145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_font_t *font HB_UNUSED, 171830145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_buffer_t *buffer) 171930145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod{ 172030145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 172130145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod unsigned int count = buffer->len; 172230145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 172330145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod info[i].syllable() = 0; 172430145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod} 172530145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod 172630145272a7d428bc62a903388bd7be43f4da7fc3Behdad Esfahbod 1727eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1728eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahboddecompose_indic (const hb_ot_shape_normalize_context_t *c, 17290736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t ab, 17300736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *a, 17310736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *b) 17320736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 17330736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod switch (ab) 17340736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 17350736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Don't decompose these. */ 17360736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0931 : return false; 17370736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0B94 : return false; 17380736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 17390736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 17400736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* 17410736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod * Decompose split matras that don't have Unicode decompositions. 17420736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod */ 17430736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 17440736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true; 17450736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true; 17460736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true; 17470736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true; 17480736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true; 17490736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true; 17500736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true; 17510736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1925 : *a = 0x1920; *b= 0x1923; return true; 17520736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1926 : *a = 0x1920; *b= 0x1924; return true; 17530736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true; 17540736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1112E : *a = 0x11127; *b= 0x11131; return true; 17550736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1112F : *a = 0x11127; *b= 0x11132; return true; 17560736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#if 0 17570736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* This one has no decomposition in Unicode, but needs no decomposition either. */ 17580736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* case 0x0AC9 : return false; */ 17590736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0B57 : *a = no decomp, -> RIGHT; return true; 17600736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1C29 : *a = no decomp, -> LEFT; return true; 17610736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0xA9C0 : *a = no decomp, -> RIGHT; return true; 17620736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x111BF : *a = no decomp, -> ABOVE; return true; 17630736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#endif 17640736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 17650736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 176643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod if ((ab == 0x0DDA || hb_in_range<hb_codepoint_t> (ab, 0x0DDC, 0x0DDE))) 17670736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 176843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* 176943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Sinhala split matras... Let the fun begin. 177043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 177143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * These four characters have Unicode decompositions. However, Uniscribe 177243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * decomposes them "Khmer-style", that is, it uses the character itself to 177343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * get the second half. The first half of all four decompositions is always 177443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * U+0DD9. 177543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 177643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are 177743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * broken with Uniscribe. But we need to support them. As such, we only 177843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * do the Uniscribe-style decomposition if the character is transformed into 177943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * its "sec.half" form by the 'pstf' feature. Otherwise, we fall back to 178043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Unicode decomposition. 178143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 178243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Note that we can't unconditionally use Unicode decomposition. That would 178343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * break some other fonts, that are designed to work with Uniscribe, and 178443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * don't have positioning features for the Unicode-style decomposition. 178543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 178643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Argh... 1787b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * 1788b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * The Uniscribe behavior is now documented in the newly published Sinhala 1789b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * spec in 2012: 1790b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * 1791b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shaping 179243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod */ 179343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 179443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data; 179543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 179643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod hb_codepoint_t glyph; 179743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 1798bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible || 179943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod (c->font->get_glyph (ab, 0, &glyph) && 1800b5a0f69e47ace468b06e21cf069a18ddcfcf6064Behdad Esfahbod indic_plan->pstf.would_substitute (&glyph, 1, c->font->face))) 180143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod { 180243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* Ok, safe to use Uniscribe-style decomposition. */ 180343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *a = 0x0DD9; 180443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *b = ab; 180543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod return true; 180643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod } 18070736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 18080736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1809eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->decompose (ab, a, b); 18100736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 18110736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1812eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1813eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodcompose_indic (const hb_ot_shape_normalize_context_t *c, 18140736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t a, 18150736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t b, 18160736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *ab) 18170736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 18180736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Avoid recomposing split matras. */ 1819eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a))) 18200736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod return false; 18210736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 18220736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Composition-exclusion exceptions that we want to recompose. */ 18230736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; } 18240736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1825eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->compose (a, b, ab); 18260736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 18270736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 18280736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1829693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = 1830693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{ 1831693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod "indic", 1832693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod collect_features_indic, 1833693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod override_features_indic, 1834a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_create_indic, 1835a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_destroy_indic, 18369f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod NULL, /* preprocess_text */ 18373d6ca0d32e5c6597acfcf59301cb1905586ddb52Behdad Esfahbod HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, 18380736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod decompose_indic, 18390736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod compose_indic, 1840693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod setup_masks_indic, 184171b4c999a511bf018acaf48a45e070470c0daf12Behdad Esfahbod HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, 1842865745b5b87236651f5663cae3461db9cb505eedBehdad Esfahbod false, /* fallback_position */ 1843693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod}; 1844