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 indic_position_t 1323a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodconsonant_position (hb_codepoint_t u) 1333a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1343a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if ((u & ~0x007F) == 0x1780) 1353a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return POS_BELOW_C; /* In Khmer coeng model, post and below forms should not be reordered. */ 1363a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return POS_BASE_C; /* Will recategorize later based on font lookups. */ 1373a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1383a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1393a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1403a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_ra (hb_codepoint_t u) 1413a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1423a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++) 1433a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (u == ra_chars[i]) 1443a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return true; 1453a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return false; 1463a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1473a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1483a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1493a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_one_of (const hb_glyph_info_t &info, unsigned int flags) 1503a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1513a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* If it ligated, all bets are off. */ 1523a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (is_a_ligature (info)) return false; 1533a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return !!(FLAG (info.indic_category()) & flags); 1543a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1553a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1563a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ)) 1573a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1583a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_joiner (const hb_glyph_info_t &info) 1593a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1603a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return is_one_of (info, JOINER_FLAGS); 1613a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1623a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1633a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod/* Note: 1643a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * 1653a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels 1663a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * cannot happen in a consonant syllable. The plus side however is, we can call the 1673a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * consonant syllable logic from the vowel syllable function and get it all right! */ 1683a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CM) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE)) 1693a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1703a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_consonant (const hb_glyph_info_t &info) 1713a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1723a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return is_one_of (info, CONSONANT_FLAGS); 1733a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1743a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1753a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod#define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng)) 1763a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline bool 1773a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodis_halant_or_coeng (const hb_glyph_info_t &info) 1783a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1793a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod return is_one_of (info, HALANT_OR_COENG_FLAGS); 1803a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 1813a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1823a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodstatic inline void 1833a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbodset_indic_properties (hb_glyph_info_t &info) 1843a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod{ 1853a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod hb_codepoint_t u = info.codepoint; 1863a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod unsigned int type = hb_indic_get_categories (u); 1873a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod indic_category_t cat = (indic_category_t) (type & 0x7F); 1883a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod indic_position_t pos = (indic_position_t) (type >> 8); 1893a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1903a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1913a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* 1923a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Re-assign category 1933a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 1943a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1953a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 1963a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe 1973a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * treats U+0951..U+0952 all as OT_VD. 1983a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * TESTS: 1993a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * U+092E,U+0947,U+0952 2003a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * U+092E,U+0952,U+0947 2013a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * U+092E,U+0947,U+0951 2023a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * U+092E,U+0951,U+0947 2033a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * */ 2043a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0951, 0x0954))) 2053a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_VD; 2063a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2073a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (unlikely (u == 0x17D1)) 2083a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_X; 2093a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (cat == OT_X && 2103a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CB, 0x17D3))) /* Khmer Various signs */ 2113a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2123a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* These are like Top Matras. */ 2133a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_M; 2143a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = POS_ABOVE_C; 2153a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2163a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (u == 0x17C6) /* Khmer Bindu doesn't like to be repositioned. */ 2173a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_N; 2183a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2193a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (unlikely (u == 0x17D2)) cat = OT_Coeng; /* Khmer coeng */ 2203a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (unlikely (u == 0x200C)) cat = OT_ZWNJ; 2213a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (unlikely (u == 0x200D)) cat = OT_ZWJ; 2223a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (unlikely (u == 0x25CC)) cat = OT_DOTTEDCIRCLE; 2233a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (unlikely (u == 0x0A71)) cat = OT_SM; /* GURMUKHI ADDAK. More like consonant medial. like 0A75. */ 2243a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2253a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (cat == OT_Repha) { 2263a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* There are two kinds of characters marked as Repha: 2273a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * - The ones that are GenCat=Mn are already positioned visually, ie. after base. (eg. Khmer) 2283a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * - The ones that are GenCat=Lo is encoded logically, ie. beginning of syllable. (eg. Malayalam) 2293a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * 2303a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * We recategorize the first kind to look like a Nukta and attached to the base directly. 2313a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 2323a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (_hb_glyph_info_get_general_category (&info) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 2333a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_N; 2343a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2353a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2363a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2373a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2383a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod /* 2393a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Re-assign position. 2403a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 2413a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2423a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if ((FLAG (cat) & CONSONANT_FLAGS)) 2433a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2443a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = consonant_position (u); 2453a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (is_ra (u)) 2463a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod cat = OT_Ra; 2473a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2483a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (cat == OT_M) 2493a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2503a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = matra_position (u, pos); 2513a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2523a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod else if (cat == OT_SM || cat == OT_VD) 2533a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod { 2543a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod pos = POS_SMVD; 2553a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod } 2563a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2573a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod if (unlikely (u == 0x0B01)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */ 2583a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2593a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2603a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2613a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod info.indic_category() = cat; 2623a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod info.indic_position() = pos; 2633a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod} 2643a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2653a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod/* 2663a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod * Things above this line should ideally be moved to the Indic table itself. 2673a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod */ 2683a83d33ec0b1be6f5992816ff5ebb0f43c8dff00Behdad Esfahbod 2691d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 27011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 27111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic configurations. Note that we do not want to keep every single script-specific 27211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * behavior in these tables necessarily. This should mainly be used for per-script 27311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * properties that are cheaper keeping here, than in the code. Ie. if, say, one and 27411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * only one script has an exception, that one script can be if'ed directly in the code, 27511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * instead of adding a new flag in these structs. 27611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 27711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 27811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum base_position_t { 27911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_FIRST, 28011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_LAST 28111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 28211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_position_t { 28311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_DEFAULT = POS_BEFORE_POST, 28411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 28511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_MAIN = POS_AFTER_MAIN, 28611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_SUB = POS_BEFORE_SUB, 28711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_SUB = POS_AFTER_SUB, 28811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_POST = POS_BEFORE_POST, 28911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_POST = POS_AFTER_POST 29011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 29111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_mode_t { 29211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_IMPLICIT, /* Reph formed out of initial Ra,H sequence. */ 29311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_EXPLICIT, /* Reph formed out of initial Ra,H,ZWJ sequence. */ 29411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */ 29511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_LOG_REPHA /* Encoded Repha character, needs reordering. */ 29611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 29711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstruct indic_config_t 29811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 29911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_script_t script; 30011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool has_old_spec; 30111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_codepoint_t virama; 30211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base_position_t base_pos; 30311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos; 30411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_mode_t reph_mode; 30511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 30611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 30711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstatic const indic_config_t indic_configs[] = 30811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 30911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Default. Should be first. */ 31011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_DEFAULT, REPH_MODE_IMPLICIT}, 31111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT}, 31211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_BENGALI, true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT}, 31311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_GURMUKHI, true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT}, 31411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_GUJARATI, true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT}, 31511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_ORIYA, true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT}, 31611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_TAMIL, true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT}, 31711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_TELUGU, true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT}, 31811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_KANNADA, true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT}, 31911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA}, 32011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT}, 32111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT, REPH_MODE_VIS_REPHA}, 32211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 32311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 32411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 32511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 32611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 32711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic shaper. 32811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 3299ccc6382ba43760167c134c18c1c4ada4b8c3f22Behdad Esfahbod 330eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstruct feature_list_t { 331c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_tag_t tag; 332ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod hb_ot_map_feature_flags_t flags; 333eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod}; 334eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 335eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstatic const feature_list_t 33685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodindic_features[] = 337b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 33885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 33985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Basic features. 34085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied in order, one at a time, after initial_reordering. 34185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 342a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('n','u','k','t'), F_GLOBAL}, 343a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('a','k','h','n'), F_GLOBAL}, 344a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('r','p','h','f'), F_NONE}, 345a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('r','k','r','f'), F_GLOBAL}, 346a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('p','r','e','f'), F_NONE}, 347a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('b','l','w','f'), F_NONE}, 348a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('h','a','l','f'), F_NONE}, 349a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('a','b','v','f'), F_NONE}, 350a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('p','s','t','f'), F_NONE}, 351a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('c','f','a','r'), F_NONE}, 352a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('v','a','t','u'), F_GLOBAL}, 353a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod {HB_TAG('c','j','c','t'), F_GLOBAL}, 35485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 35585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Other features. 35685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied all at once, after final_reordering. 35785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 358ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('i','n','i','t'), F_NONE}, 359ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('p','r','e','s'), F_GLOBAL}, 360ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('a','b','v','s'), F_GLOBAL}, 361ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('b','l','w','s'), F_GLOBAL}, 362ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('p','s','t','s'), F_GLOBAL}, 363ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('h','a','l','n'), F_GLOBAL}, 36485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* Positioning features, though we don't care about the types. */ 365ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('d','i','s','t'), F_GLOBAL}, 366ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('a','b','v','m'), F_GLOBAL}, 367ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod {HB_TAG('b','l','w','m'), F_GLOBAL}, 368c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod}; 369c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod 37085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod/* 37185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Must be in the same order as the indic_features array. 37285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 373c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbodenum { 374c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod _NUKT, 375e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod _AKHN, 376c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod RPHF, 377df6d45c693c417bf311e6fa49f18a8558542e525Behdad Esfahbod _RKRF, 378c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PREF, 379167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod BLWF, 38063e48bc33b68f940c351af623a55a4cf650db102Behdad Esfahbod HALF, 38129f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod ABVF, 382c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PSTF, 3830201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod CFAR, 38485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _VATU, 38570d656571194d2bd32671244530edbe159722cecBehdad Esfahbod _CJCT, 38685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 38785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INIT, 38885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PRES, 38985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVS, 39085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWS, 39185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PSTS, 39285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _HALN, 39385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _DIST, 39485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVM, 39585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWM, 39685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 39785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_NUM_FEATURES, 39885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */ 399b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod}; 400b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 401743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 402166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan, 403166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font, 404166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer); 405166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 4068bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 407afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 4083e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 409f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbodstatic void 4108bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 411afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 4123e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 413b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 414693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 41516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodcollect_features_indic (hb_ot_shape_planner_t *plan) 416b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 41716c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_ot_map_builder_t *map = &plan->map; 41816c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod 419166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Do this before any lookups have been applied. */ 420166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod map->add_gsub_pause (setup_syllables); 421166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 422e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod map->add_global_bool_feature (HB_TAG('l','o','c','l')); 423a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod /* The Indic specs do not require ccmp, but we apply it here since if 424a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod * there is a use of it, it's typically at the beginning. */ 425e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod map->add_global_bool_feature (HB_TAG('c','c','m','p')); 426f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 427f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 42885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod unsigned int i = 0; 42985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_gsub_pause (initial_reordering); 43085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_BASIC_FEATURES; i++) { 431a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ); 4323e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (NULL); 433412b91889d9a1ae477e8b6907d0b9a76e78a6c91Behdad Esfahbod } 4343e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (final_reordering); 43585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_NUM_FEATURES; i++) { 436a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ); 43785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 438b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 439b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 440693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 44116c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodoverride_features_indic (hb_ot_shape_planner_t *plan) 442d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod{ 443af92b4cc90e4184d5bdd8037c551ed482700114fBehdad Esfahbod /* Uniscribe does not apply 'kern'. */ 444bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 445ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL); 4466b389ddc3623d042ded4731f4d62dc354002fdd0Behdad Esfahbod 447ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); 448d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod} 449d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod 450867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 45185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodstruct would_substitute_feature_t 452a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 45385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag) 454a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 455a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_stage_lookups (0/*GSUB*/, 456a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_feature_stage (0/*GSUB*/, feature_tag), 457a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod &lookups, &count); 458a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 459a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 4608144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod inline bool would_substitute (const hb_codepoint_t *glyphs, 4618144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod unsigned int glyphs_count, 4628144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod bool zero_context, 4638144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod hb_face_t *face) const 464a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 465a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 466362a990b2246f5448ecb9d600761f710aea7d42dBehdad Esfahbod if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) 467a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return true; 468a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return false; 469a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 470a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 471a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod private: 472a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const hb_ot_map_t::lookup_map_t *lookups; 473a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int count; 474a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 475a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 476a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstruct indic_shape_plan_t 477a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 47885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod ASSERT_POD (); 479914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 480914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const 481914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 482914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod hb_codepoint_t glyph = virama_glyph; 483914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (unlikely (virama_glyph == (hb_codepoint_t) -1)) 484914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 48511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!config->virama || !font->get_glyph (config->virama, 0, &glyph)) 486914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod glyph = 0; 487914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Technically speaking, the spec says we should apply 'locl' to virama too. 488914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * Maybe one day... */ 489914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 490914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Our get_glyph() function needs a font, so we can't get the virama glyph 491914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */ 492914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph; 493914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 494914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 495914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod *pglyph = glyph; 496914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod return glyph != 0; 497914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 49885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 49911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod const indic_config_t *config; 50085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 50185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod bool is_old_spec; 50285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_codepoint_t virama_glyph; 50385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 504f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod would_substitute_feature_t rphf; 50585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pref; 50685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t blwf; 50785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pstf; 50885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 50985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_mask_t mask_array[INDIC_NUM_FEATURES]; 510a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 511a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 512a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void * 513a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_create_indic (const hb_ot_shape_plan_t *plan) 514a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 51585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t)); 51685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (unlikely (!indic_plan)) 517a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return NULL; 518a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 51911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[0]; 52011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++) 52111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (plan->props.script == indic_configs[i].script) { 52211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[i]; 52311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 52485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 52511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 526851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2'); 52711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->virama_glyph = (hb_codepoint_t) -1; 52885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 529f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f')); 53085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f')); 53185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f')); 53285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f')); 53385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 53485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) 535ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ? 536ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod 0 : plan->map.get_1_mask (indic_features[i].tag); 537a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 53885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod return indic_plan; 539a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 540a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 541a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void 542a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_destroy_indic (void *data) 543a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 544a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod free (data); 545a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 546a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 547a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic indic_position_t 548a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodconsonant_position_from_face (const indic_shape_plan_t *indic_plan, 5498144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod const hb_codepoint_t glyphs[2], 5508144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod hb_face_t *face) 551a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 5528144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod /* For old-spec, the order of glyphs is Consonant,Virama, 5538144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * whereas for new-spec, it's Virama,Consonant. However, 5548144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * some broken fonts (like Free Sans) simply copied lookups 5558144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * from old-spec to new-spec without modification. 5568144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * And oddly enough, Uniscribe seems to respect those lookups. 5578144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds 5588144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * base at 0. The font however, only has lookups matching 5598144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * 930,94D in 'blwf', not the expected 94D,930 (with new-spec 5608144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * table). As such, we simply match both sequences. Seems 5618144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod * to work. */ 562b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod bool zero_context = indic_plan->is_old_spec ? false : true; 5638144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod hb_codepoint_t glyphs_r[2] = {glyphs[1], glyphs[0]}; 5648144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod if (indic_plan->pref.would_substitute (glyphs , 2, zero_context, face) || 5658144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod indic_plan->pref.would_substitute (glyphs_r, 2, zero_context, face)) 5668144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod return POS_POST_C; 5678144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod if (indic_plan->blwf.would_substitute (glyphs , 2, zero_context, face) || 5688144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod indic_plan->blwf.would_substitute (glyphs_r, 2, zero_context, face)) 5698144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod return POS_BELOW_C; 5708144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod if (indic_plan->pstf.would_substitute (glyphs , 2, zero_context, face) || 5718144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod indic_plan->pstf.would_substitute (glyphs_r, 2, zero_context, face)) 5728144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod return POS_POST_C; 573a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return POS_BASE_C; 574a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 575a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 576a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 577166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodenum syllable_type_t { 578166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod consonant_syllable, 579166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod vowel_syllable, 580166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod standalone_cluster, 581166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod broken_cluster, 582166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod non_indic_cluster, 583166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod}; 584166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 585166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod#include "hb-ot-shape-complex-indic-machine.hh" 586166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 587166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 588693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 58916c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodsetup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, 59016c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_buffer_t *buffer, 59116c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_font_t *font HB_UNUSED) 59224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 59324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); 59424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); 59524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 59624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod /* We cannot setup masks here. We save information about characters 59724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod * and setup masks later on in a pause-callback. */ 59824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 59924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod unsigned int count = buffer->len; 60024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 60124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod set_indic_properties (buffer->info[i]); 60224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 60324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 604166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 605166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, 606166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font HB_UNUSED, 607166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer) 608166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod{ 609166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod find_syllables (buffer); 610166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod} 611166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 61224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic int 61324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodcompare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 61424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 61524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int a = pa->indic_position(); 61624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int b = pb->indic_position(); 61724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 61824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod return a < b ? -1 : a == b ? 0 : +1; 61924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 62024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 62124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 62224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 62324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic void 6248bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodupdate_consonant_positions (const hb_ot_shape_plan_t *plan, 62585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 62685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer) 6278ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod{ 628a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 6298ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 6308ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_codepoint_t glyphs[2]; 6318144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod if (indic_plan->get_virama_glyph (font, &glyphs[0])) 6328ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod { 6338ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_face_t *face = font->face; 6348ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod unsigned int count = buffer->len; 6358ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 6368ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod if (buffer->info[i].indic_position() == POS_BASE_C) { 6378144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod glyphs[1] = buffer->info[i].codepoint; 6388144936d072f94104242edf9e7aaa31d315b4094Behdad Esfahbod buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, face); 6398ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 6408ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 6418ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod} 6428ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 643867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 6447ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod/* Rules from: 6457ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ 6467ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod 647743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 648f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbodinitial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, 649f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 650f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_buffer_t *buffer, 651ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 652743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 653914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 654ee58f3bc75d2d071a71b94063bf12205a5871acbBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 655743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 656617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod 657743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 1. Find base consonant: 658743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 659743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The shaping engine finds the base consonant of the syllable, using the 660743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following algorithm: starting from the end of the syllable, move backwards 661743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * until a consonant is found that does not have a below-base or post-base 662743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * form (post-base forms have to follow below-base forms), or that is not a 663743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * pre-base reordering Ra, or arrive at the first consonant. The consonant 664743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * stopped at will be the base. 665743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 666743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o If the syllable starts with Ra + Halant (in a script that has Reph) 667743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 668743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * base consonants. 669743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 670743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 6715e72071062c015237b79fbd0521341a63166a204Behdad Esfahbod unsigned int base = end; 67276b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod bool has_reph = false; 673743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 67476b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod { 675617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 676617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 677617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * base consonants. */ 678617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod unsigned int limit = start; 67985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[RPHF] && 680617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod start + 3 <= end && 6818b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod ( 68211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || 68311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ) 6843285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod )) 685617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod { 686f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod /* See if it matches the 'rphf' feature. */ 687f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoint}; 688f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face)) 689f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod { 690f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit += 2; 691f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 692f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit++; 693f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod base = start; 694f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod has_reph = true; 695f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod } 6968b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha) 6978b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod { 6988b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod limit += 1; 6998b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 7008b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod limit++; 7018b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod base = start; 7028b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod has_reph = true; 7038b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod } 70476b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod 70523b0e9d7dc801e11640979af3c2b00649a519bb1Behdad Esfahbod switch (indic_plan->config->base_pos) 7065d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 707d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod default: 708d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod assert (false); 709d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod /* fallthrough */ 710d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod 71111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_LAST: 71211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 71311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> starting from the end of the syllable, move backwards */ 71411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int i = end; 71511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool seen_below = false; 71611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod do { 71711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod i--; 71811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> until a consonant is found */ 71911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i])) 7205d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 72111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> that does not have a below-base or post-base form 72211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * (post-base forms have to follow below-base forms), */ 72311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() != POS_BELOW_C && 72411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (info[i].indic_position() != POS_POST_C || seen_below)) 72511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 72611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 72711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 72811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 72911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() == POS_BELOW_C) 73011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod seen_below = true; 73111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 73211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or that is not a pre-base reordering Ra, 73311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 73411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * IMPLEMENTATION NOTES: 73511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 736fb7c182bf92142540bff1ad7fb82de0d115fb2b5Behdad Esfahbod * Our pre-base reordering Ra's are marked POS_POST_C, so will be skipped 73711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * by the logic above already. 73811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 73911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 74011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or arrive at the first consonant. The consonant stopped at will 74111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * be the base. */ 7425d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod base = i; 7435d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 74411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 74511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 74611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* A ZWJ after a Halant stops the base search, and requests an explicit 74711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * half form. 74811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * A ZWJ before a Halant, requests a subjoined form instead, and hence 74911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * search continues. This is particularly important for Bengali 750c4be9917438c45b972ec76dc68409014110f0837Behdad Esfahbod * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */ 75111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (start < i && 75211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_category() == OT_ZWJ && 75311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i - 1].indic_category() == OT_H) 75411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 75511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 75611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } while (i > limit); 75711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 75811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 7595d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 76011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_FIRST: 76111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 76211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* In scripts without half forms (eg. Khmer), the first consonant is always the base. */ 7635d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 76411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!has_reph) 76511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = limit; 76634c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 76711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Find the last base consonant that is not blocked by ZWJ. If there is 76811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * a ZWJ right before a base consonant, that would request a subjoined form. */ 76911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = limit; i < end; i++) 77011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 77111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 77211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (limit < i && info[i - 1].indic_category() == OT_ZWJ) 77311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 77411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 77511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 77611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 77734c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 77811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Mark all subsequent consonants as below. */ 77911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 78011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 78111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_position() = POS_BELOW_C; 78211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 78311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 7845d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 785743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 786617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 787617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 7882278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * base consonants. 7892278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * 7902278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ 7919621e0ba294c9cc6d458bbf632e63e92fda71e10Behdad Esfahbod if (has_reph && base == start && limit - base <= 2) { 792617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* Have no other consonant, so Reph is not formed and Ra becomes base. */ 793617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = false; 794617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod } 7955e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod } 7962278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod 7973d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 798743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 2. Decompose and reorder Matras: 799743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 800743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Each matra and any syllable modifier sign in the cluster are moved to the 801743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * appropriate position relative to the consonant(s) in the cluster. The 802743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * shaping engine decomposes two- or three-part matras into their constituent 803743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * parts before any repositioning. Matra characters are classified by which 804743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * consonant in a conjunct they have affinity for and are reordered to the 805743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following positions: 806743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 807743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o Before first half form in the syllable 808743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After subjoined consonants 809743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After post-form consonant 810743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After main consonant (for above marks) 811743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 812743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 813743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 814743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The normalize() routine has already decomposed matras for us, so we don't 815743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * need to worry about that. 816743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 817743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 818743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 819743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 3. Reorder marks to canonical order: 820743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 821743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Adjacent nukta and halant or nukta and vedic sign are always repositioned 822743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * if necessary, so that the nukta is first. 823743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 824743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 825743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 826743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * We don't need to do this: the normalize() routine already did this for us. 827743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 828743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 829743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 83045d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod /* Reorder characters */ 83145d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 8323c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 833900cf3d449bf36d4f8b1474590cae925fef48fc8Behdad Esfahbod info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position()); 83455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 835075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 836075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].indic_position() = POS_BASE_C; 83745d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 83855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod /* Mark final consonants. A final consonant is one appearing after a matra, 83955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod * like in Khmer. */ 84055f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 84155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (info[i].indic_category() == OT_M) { 84255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int j = i + 1; j < end; j++) 84355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (is_consonant (info[j])) { 84455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod info[j].indic_position() = POS_FINAL_C; 84555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 84655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 84755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 84855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 84955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 850fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod /* Handle beginning Ra */ 8515e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod if (has_reph) 852dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() = POS_RA_TO_BECOME_REPH; 853fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod 854f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* For old-style Indic script tags, move the first post-base Halant after 855ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod * last consonant. Only do this if there is *not* a Halant after last 856ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod * consonant. Otherwise it becomes messy. */ 857914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->is_old_spec) { 8583c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 859f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (info[i].indic_category() == OT_H) { 860f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod unsigned int j; 861f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod for (j = end - 1; j > i; j--) 862ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod if (is_consonant (info[j]) || info[j].indic_category() == OT_H) 863f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 864ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod if (info[j].indic_category() != OT_H && j > i) { 865f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* Move Halant to after last consonant. */ 866f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod hb_glyph_info_t t = info[i]; 867f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); 868f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod info[j] = t; 869f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 870f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 871f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 872f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 873f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod 87481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* Attach misc marks to previous char to move with them. */ 875ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 87681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod indic_position_t last_pos = POS_START; 87781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod for (unsigned int i = start; i < end; i++) 87881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 87981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS))) 88081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 88181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() = last_pos; 882dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod if (unlikely (info[i].indic_category() == OT_H && 88381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() == POS_PRE_M)) 88481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 88581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* 88681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * Uniscribe doesn't move the Halant with Left Matra. 88781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * TEST: U+092B,U+093F,U+094DE 888dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We follow. This is important for the Sinhala 889dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA 890dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * where U+0DD9 is a left matra and U+0DCA is the virama. 891dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We don't want to move the virama with the left matra. 892dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * TEST: U+0D9A,U+0DDA 89381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod */ 894ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod for (unsigned int j = i; j > start; j--) 8956a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[j - 1].indic_position() != POS_PRE_M) { 896ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod info[i].indic_position() = info[j - 1].indic_position(); 897ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod break; 898ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 89981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 90081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } else if (info[i].indic_position() != POS_SMVD) { 90181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod last_pos = (indic_position_t) info[i].indic_position(); 902ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 90381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 904ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 90574ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod /* Re-attach ZWJ, ZWNJ, and halant to next char, for after-base consonants. */ 90674ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod { 90774ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod unsigned int last_halant = end; 90874ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 909deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (is_halant_or_coeng (info[i])) 91074ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod last_halant = i; 91174ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod else if (is_consonant (info[i])) { 91274ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int j = last_halant; j < i; j++) 91381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if (info[j].indic_position() != POS_SMVD) 91481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[j].indic_position() = info[i].indic_position(); 91574ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 91674ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 91745d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 918a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod { 9197b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod /* Things are out-of-control for post base positions, they may shuffle 9207b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * around like crazy, so merge clusters. For pre-base stuff, we handle 9217b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * cluster issues in final reordering. */ 9227b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod buffer->merge_clusters (base, end); 923a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Sit tight, rock 'n roll! */ 924d3637edb248162970e202e9d0671540274192844Behdad Esfahbod hb_bubble_sort (info + start, end - start, compare_indic_order); 925a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Find base again */ 926a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = end; 9273c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < end; i++) 928a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod if (info[i].indic_position() == POS_BASE_C) { 929a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = i; 930a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod break; 931a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 932a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 93345d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 934743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Setup masks now */ 935743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 936281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod { 937281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod hb_mask_t mask; 938281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod 939dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* Reph */ 940668c6046c1b3af3bd316bda0cc8636f2a5e8df42Behdad Esfahbod for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) 94185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[RPHF]; 942dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 943281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Pre-base */ 94485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[HALF]; 9453c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 946281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 947281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Base */ 94820b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = 0; 949075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 950075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].mask |= mask; 951281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Post-base */ 95285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF]; 9533c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 954281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 955281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod } 9569da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 95785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod if (indic_plan->is_old_spec && 95885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod buffer->props.script == HB_SCRIPT_DEVANAGARI) 95985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod { 96085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod /* Old-spec eye-lash Ra needs special handling. From the 96185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * spec: 96285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 96385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * "The feature 'below-base form' is applied to consonants 96485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * having below-base forms and following the base consonant. 96585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * The exception is vattu, which may appear below half forms 96685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * as well as below the base glyph. The feature 'below-base 96785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * form' will be applied to all such occurrences of Ra as well." 96885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 96985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * Test case: U+0924,U+094D,U+0930,U+094d,U+0915 97085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * with Sanskrit 2003 font. 97185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 97285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * However, note that Ra,Halant,ZWJ is the correct way to 97385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * request eyelash form of Ra, so we wouldbn't inhibit it 97485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * in that sequence. 97585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 97685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915 97785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod */ 97885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod for (unsigned int i = start; i + 1 < base; i++) 97985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod if (info[i ].indic_category() == OT_Ra && 98085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+1].indic_category() == OT_H && 98185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod (i + 2 == base || 98285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+2].indic_category() != OT_ZWJ)) 98385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod { 98485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i ].mask |= indic_plan->mask_array[BLWF]; 98585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+1].mask |= indic_plan->mask_array[BLWF]; 98685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod } 98785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod } 98885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod 98985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 2 < end) 99017d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod { 991771a8f50289e8fa458cfc3cd84f73a380ce98077Behdad Esfahbod /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ 99256be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod for (unsigned int i = base + 1; i + 1 < end; i++) { 99356be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint}; 99456be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face)) 9958e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 99685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 99785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 9980201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 9990201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod /* Mark the subsequent stuff with 'cfar'. Used in Khmer. 10000201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * Read the feature spec. 10010201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * This allows distinguishing the following cases with MS Khmer fonts: 10020201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+179A,U+17D2,U+1782 10030201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+1782,U+17D2,U+179A 10040201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod */ 10050201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod for (; i < end; i++) 100685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[CFAR]; 10070201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 10088e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 10098e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 101056be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod } 101117d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod } 101217d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod 10139da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod /* Apply ZWJ/ZWNJ effects */ 10143c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start + 1; i < end; i++) 10159da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod if (is_joiner (info[i])) { 10169da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod bool non_joiner = info[i].indic_category() == OT_ZWNJ; 10176b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod unsigned int j = i; 10189da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 10199da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod do { 10209da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod j--; 10216b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 1022cfc507c5432e6327e8484b07b9e091212653bc92Behdad Esfahbod /* ZWJ/ZWNJ should disable CJCT. They do that by simply 1023cfc507c5432e6327e8484b07b9e091212653bc92Behdad Esfahbod * being there, since we don't skip them for the CJCT 1024a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod * feature (ie. F_MANUAL_ZWJ) */ 102520b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod 102620b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWNJ disables HALF. */ 10276b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod if (non_joiner) 102885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[j].mask &= ~indic_plan->mask_array[HALF]; 10296b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 10309da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } while (j > start && !is_consonant (info[j])); 10319da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } 1032743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1033743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1034743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1035743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 10368bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan, 1037f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 10389f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 1039ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1040743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 1041c5306b6861cfaa50af40e8ceb058791fa06d7981Behdad Esfahbod /* We made the vowels look like consonants. So let's call the consonant logic! */ 1042f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1043743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1044743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1045743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 10468bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, 1047f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 10489f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 1049ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1050743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 105118c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain. 105218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Only if not in compatibility mode that is... */ 105318c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 1054bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 105518c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod { 105618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* For dotted-circle, this is what Uniscribe does: 105718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * If dotted-circle is the last glyph, it just does nothing. 105818c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Ie. It doesn't form Reph. */ 105918c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) 106018c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod return; 106118c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod } 106218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 1063f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1064743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1065743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1066743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 1067b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodinitial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan, 1068f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 1069b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer, 1070b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int start, unsigned int end) 1071b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1072b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod /* We already inserted dotted-circles, so just call the standalone_cluster. */ 1073f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_standalone_cluster (plan, face, buffer, start, end); 1074b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1075b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1076b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 1077327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 1078f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face HB_UNUSED, 1079327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 1080327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 1081743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 1082743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 1083743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 1084743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1085743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1086327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1087743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 1088327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_syllable (const hb_ot_shape_plan_t *plan, 1089f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 1090327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer, 1091327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start, unsigned int end) 1092327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod{ 1093327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); 1094327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod switch (syllable_type) { 1095f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; 1096f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return; 1097f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return; 1098f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; 1099f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return; 1100327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 1101327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod} 1102327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1103166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic inline void 11040beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbodinsert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, 1105b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_font_t *font, 1106b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer) 1107b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1108166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Note: This loop is extra overhead, but should not be measurable. */ 1109166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod bool has_broken_syllables = false; 1110166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod unsigned int count = buffer->len; 1111166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod for (unsigned int i = 0; i < count; i++) 1112166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) { 1113166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod has_broken_syllables = true; 1114166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod break; 1115166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod } 1116166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if (likely (!has_broken_syllables)) 1117166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod return; 1118166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 1119166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 1120b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_codepoint_t dottedcircle_glyph; 1121b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) 1122b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return; 1123b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1124f41dc2d35b23220d59d38990bb66f1cbd66a55b3Behdad Esfahbod hb_glyph_info_t dottedcircle = {0}; 1125b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = 0x25CC; 1126b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod set_indic_properties (dottedcircle); 1127b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = dottedcircle_glyph; 1128b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1129b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->clear_output (); 1130b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1131b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->idx = 0; 1132b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int last_syllable = 0; 1133b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod while (buffer->idx < buffer->len) 1134b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 1135b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int syllable = buffer->cur().syllable(); 1136b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); 1137b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) 1138b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 1139596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod last_syllable = syllable; 1140596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1141b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_glyph_info_t info = dottedcircle; 1142b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.cluster = buffer->cur().cluster; 1143b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.mask = buffer->cur().mask; 1144b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.syllable() = buffer->cur().syllable(); 1145596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1146596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod /* Insert dottedcircle after possible Repha. */ 1147596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod while (buffer->idx < buffer->len && 1148596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod last_syllable == buffer->cur().syllable() && 1149596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->cur().indic_category() == OT_Repha) 1150596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->next_glyph (); 1151596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1152b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->output_info (info); 1153b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 1154596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod else 1155596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->next_glyph (); 1156b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 1157b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1158b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->swap_buffers (); 1159b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1160b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1161b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 11628bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 116324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod hb_font_t *font, 11643e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1165743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 116685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod update_consonant_positions (plan, font, buffer); 1167166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod insert_dotted_circles (plan, font, buffer); 1168327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1169327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1170b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int count = buffer->len; 1171b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (!count)) return; 1172327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last = 0; 1173327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1174327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1175327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (last_syllable != info[i].syllable()) { 1176f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, i); 1177327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last = i; 1178327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last_syllable = info[last].syllable(); 1179327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 1180f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, count); 1181b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 1182b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 1183743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 118485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodfinal_reordering_syllable (const hb_ot_shape_plan_t *plan, 118585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer, 1186ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1187743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 118885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 11894ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 11904ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 1191e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod /* 4. Final reordering: 1192e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1193e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * After the localized forms and basic shaping forms GSUB features have been 1194e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * applied (see below), the shaping engine performs some final glyph 1195e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * reordering before applying all the remaining font features to the entire 1196e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * cluster. 11974ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 11984ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 11994ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* Find base again */ 12005f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod unsigned int base; 12015f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod for (base = start; base < end; base++) 12025f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (info[base].indic_position() >= POS_BASE_C) { 12035f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (start < base && info[base].indic_position() > POS_BASE_C) 12045f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod base--; 12055f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod break; 12065f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod } 1207a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod if (base == end && start < base && 1208a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod info[base - 1].indic_category() != OT_ZWJ) 1209a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod base--; 1210a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod while (start < base && 1211a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod (info[base].indic_category() == OT_H || 1212a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod info[base].indic_category() == OT_N)) 1213a0cb9f33ee064628debe8e848094dfd661334640Behdad Esfahbod base--; 12144ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 12154705a7026900e51f6430f03a73c87f2df035df92Behdad Esfahbod 12164ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder matras: 1217e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1218e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base matra character had been reordered before applying basic 1219e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * features, the glyph can be moved closer to the main consonant based on 1220e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * whether half-forms had been formed. Actual position for the matra is 1221e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * defined as “after last standalone halant glyph, after initial matra 1222e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * position and before the main consonant”. If ZWJ or ZWNJ follow this 1223e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * halant, position is moved after it. 12244ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 12254ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 122665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ 12279d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 122865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we lost track of base, alas, position before last thingy. */ 122965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod unsigned int new_pos = base == end ? base - 2 : base - 1; 123065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 123127bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 123227bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 123327bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * We want to position matra after them. 123465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod */ 123527bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1236e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod { 123765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod while (new_pos > start && 123865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng))))) 123965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos--; 124065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 124165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we found no Halant we are done. 124265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * Otherwise only proceed if the Halant does 124365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * not belong to the Matra itself! */ 124465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (is_halant_or_coeng (info[new_pos]) && 124565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod info[new_pos].indic_position() != POS_PRE_M) 124665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 124765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 124865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) 124965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos++; 125065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 125165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod else 125265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos = start; /* No move. */ 125365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 12549d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod 125527bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M) 125665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 12579d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* Now go see if there's actually any matras... */ 1258921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod for (unsigned int i = new_pos; i > start; i--) 12596a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[i - 1].indic_position () == POS_PRE_M) 12609d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 12611a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod unsigned int old_pos = i - 1; 12621a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 12631a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0])); 12641a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod info[new_pos] = tmp; 1265f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */ 1266f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod base--; 1267921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod new_pos--; 12689d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 12692cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (new_pos, MIN (end, base + 1)); 1270abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } else { 1271e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod for (unsigned int i = start; i < base; i++) 1272abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod if (info[i].indic_position () == POS_PRE_M) { 12732cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (i, MIN (end, base + 1)); 1274abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod break; 1275abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } 12769d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 12774ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod } 12784ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 12794ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 12804ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder reph: 1281e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1282e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Reph’s original position is always at the beginning of the syllable, 1283e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * (i.e. it is not reordered at the character reordering stage). However, 1284e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * it will be reordered according to the basic-forms shaping results. 1285e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Possible positions for reph, depending on the script, are; after main, 1286e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * before post-base consonant forms, and after post-base consonant forms. 1287dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 1288dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1289dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* If there's anything after the Ra that has the REPH pos, it ought to be halant. 1290dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Which means that the font has failed to ligate the Reph. In which case, we 1291dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * shouldn't move. */ 1292dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod if (start + 1 < end && 1293dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() == POS_RA_TO_BECOME_REPH && 1294dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH) 1295dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod { 129611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int new_reph_pos; 129711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos = indic_plan->config->reph_pos; 129811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 129911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* XXX Figure out old behavior too */ 130002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1301dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* 1. If reph should be positioned after post-base consonant forms, 1302dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to step 5. 130302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 130411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_POST) 130502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 13069d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_step_5; 130702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 130802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 130902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 2. If the reph repositioning class is not after post-base: target 1310dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is after the first explicit halant glyph between the 1311dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-reph consonant and last main consonant. If ZWJ or ZWNJ 1312dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * are following this halant, position is moved after it. If such 1313dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is found, this is the target position. Otherwise, 1314dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to the next step. 1315dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * 1316dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Note: in old-implementation fonts, where classifications were 1317dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * fixed in shaping engine, there was no case where reph position 1318dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * will be found on this step. 131902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 132002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 132102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = start + 1; 1322deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 132302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 132402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 13251f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) 13261f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod { 132702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 132802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 132902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 133002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 133102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 133202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 133302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 133402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 3. If reph should be repositioned after the main consonant: find the 1335dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first consonant not ligated with main, or find the first 1336dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant that is not a potential pre-base reordering Ra. 133702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 133811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_MAIN) 133902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1340b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos = base; 1341b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod /* XXX Skip potential pre-base reordering Ra. */ 134234ae336f3fae93ef9372881d545c817bce383041Behdad Esfahbod while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN) 1343b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos++; 1344b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod if (new_reph_pos < end) 1345b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod goto reph_move; 134602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 134702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 134802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 4. If reph should be positioned before post-base consonant, find 1349dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-base classified consonant not ligated with main. If no 1350dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant is found, the target position should be before the 1351dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first matra, syllable modifier sign or vedic sign. 135202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 13539d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* This is our take on what step 4 is trying to say (and failing, BADLY). */ 135411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_SUB) 135502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 13569d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos = base; 13579d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod while (new_reph_pos < end && 1358be8b9f5f715f6fb36b98bd33c3303f79cc068f8aBehdad Esfahbod !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD)))) 13599d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos++; 13609d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (new_reph_pos < end) 13619d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_move; 136202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 136302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 136402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 5. If no consonant is found in steps 3 or 4, move reph to a position 1365dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * immediately before the first post-base matra, syllable modifier 1366dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * sign or vedic sign that has a reordering class after the intended 1367dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * reph position. For example, if the reordering position for reph 1368dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * is post-main, it will skip above-base matras that also have a 1369dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * post-main position. 1370dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 137102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_step_5: 137202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1373d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* Copied from step 2. */ 1374d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos = start + 1; 1375d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 1376d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1377d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod 13781f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) 13791f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod { 1380d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 1381d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 1382d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1383d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod goto reph_move; 1384d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod } 138502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1386dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 138702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 6. Otherwise, reorder reph to the end of the syllable. 138802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 138902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 139002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = end - 1; 139102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD) 139202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 139302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1394892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod /* 1395892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * If the Reph is to be ending up after a Matra,Halant sequence, 1396892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * position it before that Halant so it can interact with the Matra. 1397892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * However, if it's a plain Consonant,Halant we shouldn't do that. 1398892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * Uniscribe doesn't do this. 1399892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * TEST: U+0930,U+094D,U+0915,U+094B,U+094D 1400892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod */ 1401bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (!hb_options ().uniscribe_bug_compatible && 1402deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod unlikely (is_halant_or_coeng (info[new_reph_pos]))) { 140302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod for (unsigned int i = base + 1; i < new_reph_pos; i++) 140402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (info[i].indic_category() == OT_M) { 140502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Ok, got it. */ 140602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 140702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 140802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 140902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 14108df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod } 14118df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod 141202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_move: 141302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1414e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod /* Yay, one big cluster! Merge before moving. */ 1415e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 1416e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod 141702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Move */ 141802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod hb_glyph_info_t reph = info[start]; 141902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0])); 142002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod info[new_reph_pos] = reph; 1421f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod if (start < base && base <= new_reph_pos) 1422f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod base--; 142302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1424dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod } 1425dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1426dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1427dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* o Reorder pre-base reordering consonants: 1428e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1429e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base reordering consonant is found, reorder it according to 1430e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * the following rules: 1431e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod */ 1432e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 143385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ 143446e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod { 14358e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 143685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) 143778818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod { 14388e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 1. Only reorder a glyph produced by substitution during application 14398e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * of the <pref> feature. (Note that a font may shape a Ra consonant with 14408e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * the feature generally but block it in certain contexts.) 14418e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 144285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (i + 1 == end || (info[i + 1].mask & indic_plan->mask_array[PREF]) == 0) 14438e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 14448e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 14458e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 2. Try to find a target position the same way as for pre-base matra. 14468e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * If it is found, reorder pre-base consonant glyph. 14478e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 14488e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 3. If position is not found, reorder immediately before main 14498e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * consonant. 14508e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 14518e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 14528e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int new_pos = base; 145388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 145488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 145588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * We want to position matra after them. 145688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod */ 145788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1458d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 145988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod while (new_pos > start && 146088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS))) 146188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 146288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod 146388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* In Khmer coeng model, a V,Ra can go *after* matras. If it goes after a 146488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * split matra, it should be reordered to *before* the left part of such matra. */ 146588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) 146688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 146788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod unsigned int old_pos = i; 146888d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod for (unsigned int i = base + 1; i < old_pos; i++) 146988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (info[i].indic_category() == OT_M) 147088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 147188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 147288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod break; 147388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 147488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 1475d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1476d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod 1477deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) 14781f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod { 14798e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 14808e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if (new_pos < end && is_joiner (info[new_pos])) 14818e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos++; 14821f91c39677f840a1f630696d16d083060069abf5Behdad Esfahbod } 14838e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 14848e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 14858e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int old_pos = i; 1486e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (new_pos, old_pos + 1); 14878e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 14888e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0])); 14898e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[new_pos] = tmp; 1490f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod if (new_pos <= base && base < old_pos) 1491f22b7e77783fa2f44365e0fe6413c4474c07048dBehdad Esfahbod base++; 14928e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 14938e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 14948e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 14958e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 149678818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod } 149746e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod } 1498eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1499eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1500a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod /* Apply 'init' to the Left Matra if it's a word start. */ 15016a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[start].indic_position () == POS_PRE_M && 1502a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod (!start || 1503eace47b173807d94b29a6490d0bc3c9f8f6168d1Behdad Esfahbod !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & 15042c372b80f6befad69e216e3f218b38640b8cc044Behdad Esfahbod FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))) 150585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[start].mask |= indic_plan->mask_array[INIT]; 1506a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod 1507eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 15088ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod /* 15098ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod * Finish off the clusters and go home! 15108ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod */ 1511bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 1512ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 151330c3d5e9fc61b49c2c6ad4e744300edd6f3e0261Behdad Esfahbod /* Uniscribe merges the entire cluster. 151421d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This means, half forms are submerged into the main consonants cluster. 151521d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This is unnecessary, and makes cursor positioning harder, but that's what 151621d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * Uniscribe does. */ 1517e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 151821d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod } 1519ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod} 1520e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1521e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1522ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbodstatic void 15238bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 15240beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod hb_font_t *font HB_UNUSED, 15253e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1526ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod{ 1527ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int count = buffer->len; 1528327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (unlikely (!count)) return; 1529ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod 1530ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1531ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int last = 0; 1532cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1533ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1534cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod if (last_syllable != info[i].syllable()) { 153585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, i); 1536ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod last = i; 1537cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod last_syllable = info[last].syllable(); 1538ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod } 153985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, count); 1540e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 154180cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod /* Zero syllables now... */ 154280cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 154380cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod info[i].syllable() = 0; 154480cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod 1545743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); 1546743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); 1547743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1548743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1549743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1550b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic hb_ot_shape_normalization_mode_t 15510beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbodnormalization_preference_indic (const hb_segment_properties_t *props HB_UNUSED) 1552b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1553b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT; 1554b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1555b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1556eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1557eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahboddecompose_indic (const hb_ot_shape_normalize_context_t *c, 15580736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t ab, 15590736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *a, 15600736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *b) 15610736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 15620736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod switch (ab) 15630736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 15640736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Don't decompose these. */ 15650736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0931 : return false; 15660736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0B94 : return false; 15670736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 15680736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 15690736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* 15700736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod * Decompose split matras that don't have Unicode decompositions. 15710736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod */ 15720736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 15730736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true; 15740736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true; 15750736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true; 15760736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true; 15770736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true; 15780736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true; 15790736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true; 15800736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1925 : *a = 0x1920; *b= 0x1923; return true; 15810736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1926 : *a = 0x1920; *b= 0x1924; return true; 15820736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true; 15830736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1112E : *a = 0x11127; *b= 0x11131; return true; 15840736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1112F : *a = 0x11127; *b= 0x11132; return true; 15850736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#if 0 15860736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* This one has no decomposition in Unicode, but needs no decomposition either. */ 15870736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* case 0x0AC9 : return false; */ 15880736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0B57 : *a = no decomp, -> RIGHT; return true; 15890736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1C29 : *a = no decomp, -> LEFT; return true; 15900736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0xA9C0 : *a = no decomp, -> RIGHT; return true; 15910736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x111BF : *a = no decomp, -> ABOVE; return true; 15920736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#endif 15930736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 15940736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 159543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod if ((ab == 0x0DDA || hb_in_range<hb_codepoint_t> (ab, 0x0DDC, 0x0DDE))) 15960736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 159743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* 159843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Sinhala split matras... Let the fun begin. 159943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 160043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * These four characters have Unicode decompositions. However, Uniscribe 160143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * decomposes them "Khmer-style", that is, it uses the character itself to 160243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * get the second half. The first half of all four decompositions is always 160343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * U+0DD9. 160443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 160543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are 160643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * broken with Uniscribe. But we need to support them. As such, we only 160743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * do the Uniscribe-style decomposition if the character is transformed into 160843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * its "sec.half" form by the 'pstf' feature. Otherwise, we fall back to 160943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Unicode decomposition. 161043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 161143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Note that we can't unconditionally use Unicode decomposition. That would 161243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * break some other fonts, that are designed to work with Uniscribe, and 161343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * don't have positioning features for the Unicode-style decomposition. 161443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 161543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Argh... 1616b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * 1617b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * The Uniscribe behavior is now documented in the newly published Sinhala 1618b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * spec in 2012: 1619b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * 1620b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shaping 162143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod */ 162243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 162343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data; 162443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 162543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod hb_codepoint_t glyph; 162643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 1627bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible || 162843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod (c->font->get_glyph (ab, 0, &glyph) && 162943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face))) 163043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod { 163143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* Ok, safe to use Uniscribe-style decomposition. */ 163243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *a = 0x0DD9; 163343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *b = ab; 163443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod return true; 163543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod } 16360736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 16370736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1638eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->decompose (ab, a, b); 16390736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 16400736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1641eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1642eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodcompose_indic (const hb_ot_shape_normalize_context_t *c, 16430736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t a, 16440736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t b, 16450736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *ab) 16460736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 16470736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Avoid recomposing split matras. */ 1648eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a))) 16490736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod return false; 16500736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 16510736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Composition-exclusion exceptions that we want to recompose. */ 16520736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; } 16530736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1654eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->compose (a, b, ab); 16550736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 16560736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 16570736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1658693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = 1659693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{ 1660693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod "indic", 1661693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod collect_features_indic, 1662693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod override_features_indic, 1663a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_create_indic, 1664a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_destroy_indic, 16659f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod NULL, /* preprocess_text */ 1666b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod normalization_preference_indic, 16670736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod decompose_indic, 16680736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod compose_indic, 1669693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod setup_masks_indic, 1670568000274c8edb5f41bc4f876ce21fcc8bdaeed8Behdad Esfahbod HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, 1671865745b5b87236651f5663cae3461db9cb505eedBehdad Esfahbod false, /* fallback_position */ 1672693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod}; 1673