hb-ot-shape-complex-indic.cc revision 85c51ec2e1d518019e32801ae38659c74fc20d80
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; 332c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_bool_t is_global; 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 */ 342c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('n','u','k','t'), true}, 343e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod {HB_TAG('a','k','h','n'), true}, 344c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('r','p','h','f'), false}, 3451ac075b227090a9ad930dcc1670236c176b27067Behdad Esfahbod {HB_TAG('r','k','r','f'), true}, 346c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('p','r','e','f'), false}, 347167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod {HB_TAG('b','l','w','f'), false}, 34863e48bc33b68f940c351af623a55a4cf650db102Behdad Esfahbod {HB_TAG('h','a','l','f'), false}, 34929f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod {HB_TAG('a','b','v','f'), false}, 350c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('p','s','t','f'), false}, 3510201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod {HB_TAG('c','f','a','r'), false}, 3521d6846db9ebf84561bb30a4e48c6c43184914099Behdad Esfahbod {HB_TAG('v','a','t','u'), true}, 35370d656571194d2bd32671244530edbe159722cecBehdad Esfahbod {HB_TAG('c','j','c','t'), true}, 35485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 35585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Other features. 35685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied all at once, after final_reordering. 35785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 35885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('i','n','i','t'), false}, 35985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('p','r','e','s'), true}, 36085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('a','b','v','s'), true}, 36185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('b','l','w','s'), true}, 36285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('p','s','t','s'), true}, 36385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('h','a','l','n'), true}, 36485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* Positioning features, though we don't care about the types. */ 36585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('d','i','s','t'), true}, 36685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('a','b','v','m'), true}, 36785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('b','l','w','m'), true}, 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 422f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_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. */ 425f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_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++) { 43185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); 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++) { 43685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); 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) 44516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true); 4466b389ddc3623d042ded4731f4d62dc354002fdd0Behdad Esfahbod 4476b389ddc3623d042ded4731f4d62dc354002fdd0Behdad Esfahbod plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true); 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 460a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod inline bool would_substitute (hb_codepoint_t *glyphs, 461a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int glyphs_count, 462b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod bool zero_context, 463a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad 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++) 53585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->mask_array[i] = indic_features[i].is_global ? 0 : plan->map.get_1_mask (indic_features[i].tag); 536a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 53785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod return indic_plan; 538a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 539a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 540a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void 541a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_destroy_indic (void *data) 542a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 543a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod free (data); 544a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 545a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 546a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic indic_position_t 547a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodconsonant_position_from_face (const indic_shape_plan_t *indic_plan, 548a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_codepoint_t *glyphs, unsigned int glyphs_len, 549a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_face_t *face) 550a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 551b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod bool zero_context = indic_plan->is_old_spec ? false : true; 552b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C; 553b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->blwf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C; 554b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->pstf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_POST_C; 555a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return POS_BASE_C; 556a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 557a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 558a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 559166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodenum syllable_type_t { 560166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod consonant_syllable, 561166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod vowel_syllable, 562166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod standalone_cluster, 563166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod broken_cluster, 564166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod non_indic_cluster, 565166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod}; 566166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 567166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod#include "hb-ot-shape-complex-indic-machine.hh" 568166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 569166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 570693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 57116c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodsetup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, 57216c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_buffer_t *buffer, 57316c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_font_t *font HB_UNUSED) 57424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 57524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); 57624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); 57724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 57824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod /* We cannot setup masks here. We save information about characters 57924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod * and setup masks later on in a pause-callback. */ 58024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 58124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod unsigned int count = buffer->len; 58224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 58324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod set_indic_properties (buffer->info[i]); 58424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 58524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 586166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 587166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, 588166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font HB_UNUSED, 589166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer) 590166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod{ 591166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod find_syllables (buffer); 592166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod} 593166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 59424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic int 59524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodcompare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 59624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 59724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int a = pa->indic_position(); 59824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int b = pb->indic_position(); 59924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 60024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod return a < b ? -1 : a == b ? 0 : +1; 60124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 60224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 60324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 60424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 60524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic void 6068bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodupdate_consonant_positions (const hb_ot_shape_plan_t *plan, 60785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 60885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer) 6098ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod{ 610a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 6118ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 612a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int consonant_pos = indic_plan->is_old_spec ? 0 : 1; 6138ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_codepoint_t glyphs[2]; 614914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->get_virama_glyph (font, &glyphs[1 - consonant_pos])) 6158ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod { 6168ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_face_t *face = font->face; 6178ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod unsigned int count = buffer->len; 6188ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 6198ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod if (buffer->info[i].indic_position() == POS_BASE_C) { 62024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod glyphs[consonant_pos] = buffer->info[i].codepoint; 621a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, 2, face); 6228ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 6238ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 6248ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod} 6258ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 626867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 6277ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod/* Rules from: 6287ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ 6297ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod 630743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 631f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbodinitial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, 632f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 633f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_buffer_t *buffer, 634ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 635743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 636914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 637ee58f3bc75d2d071a71b94063bf12205a5871acbBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 638743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 639617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod 640743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 1. Find base consonant: 641743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 642743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The shaping engine finds the base consonant of the syllable, using the 643743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following algorithm: starting from the end of the syllable, move backwards 644743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * until a consonant is found that does not have a below-base or post-base 645743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * form (post-base forms have to follow below-base forms), or that is not a 646743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * pre-base reordering Ra, or arrive at the first consonant. The consonant 647743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * stopped at will be the base. 648743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 649743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o If the syllable starts with Ra + Halant (in a script that has Reph) 650743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 651743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * base consonants. 652743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 653743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 6545e72071062c015237b79fbd0521341a63166a204Behdad Esfahbod unsigned int base = end; 65576b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod bool has_reph = false; 656743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 65776b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod { 658617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 659617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 660617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * base consonants. */ 661617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod unsigned int limit = start; 66285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[RPHF] && 663617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod start + 3 <= end && 6648b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod ( 66511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || 66611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ) 6673285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod )) 668617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod { 669f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod /* See if it matches the 'rphf' feature. */ 670f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoint}; 671f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face)) 672f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod { 673f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit += 2; 674f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 675f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit++; 676f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod base = start; 677f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod has_reph = true; 678f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod } 6798b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha) 6808b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod { 6818b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod limit += 1; 6828b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 6838b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod limit++; 6848b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod base = start; 6858b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod has_reph = true; 6868b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod } 68776b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod 68823b0e9d7dc801e11640979af3c2b00649a519bb1Behdad Esfahbod switch (indic_plan->config->base_pos) 6895d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 690d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod default: 691d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod assert (false); 692d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod /* fallthrough */ 693d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod 69411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_LAST: 69511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 69611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> starting from the end of the syllable, move backwards */ 69711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int i = end; 69811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool seen_below = false; 69911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod do { 70011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod i--; 70111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> until a consonant is found */ 70211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i])) 7035d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 70411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> that does not have a below-base or post-base form 70511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * (post-base forms have to follow below-base forms), */ 70611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() != POS_BELOW_C && 70711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (info[i].indic_position() != POS_POST_C || seen_below)) 70811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 70911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 71011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 71111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 71211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() == POS_BELOW_C) 71311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod seen_below = true; 71411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 71511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or that is not a pre-base reordering Ra, 71611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 71711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * IMPLEMENTATION NOTES: 71811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 71911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Our pre-base reordering Ra's are marked POS_BELOW, so will be skipped 72011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * by the logic above already. 72111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 72211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 72311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or arrive at the first consonant. The consonant stopped at will 72411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * be the base. */ 7255d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod base = i; 7265d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 72711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 72811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 72911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* A ZWJ after a Halant stops the base search, and requests an explicit 73011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * half form. 73111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * A ZWJ before a Halant, requests a subjoined form instead, and hence 73211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * search continues. This is particularly important for Bengali 733c4be9917438c45b972ec76dc68409014110f0837Behdad Esfahbod * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */ 73411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (start < i && 73511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_category() == OT_ZWJ && 73611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i - 1].indic_category() == OT_H) 73711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 73811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 73911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } while (i > limit); 74011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 74111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 7425d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 74311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_FIRST: 74411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 74511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* In scripts without half forms (eg. Khmer), the first consonant is always the base. */ 7465d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 74711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!has_reph) 74811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = limit; 74934c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 75011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Find the last base consonant that is not blocked by ZWJ. If there is 75111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * a ZWJ right before a base consonant, that would request a subjoined form. */ 75211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = limit; i < end; i++) 75311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 75411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 75511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (limit < i && info[i - 1].indic_category() == OT_ZWJ) 75611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 75711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 75811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 75911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 76034c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 76111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Mark all subsequent consonants as below. */ 76211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 76311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 76411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_position() = POS_BELOW_C; 76511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 76611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 7675d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 768743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 769617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 770617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 7712278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * base consonants. 7722278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * 7732278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ 7749621e0ba294c9cc6d458bbf632e63e92fda71e10Behdad Esfahbod if (has_reph && base == start && limit - base <= 2) { 775617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* Have no other consonant, so Reph is not formed and Ra becomes base. */ 776617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = false; 777617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod } 7785e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod } 7792278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod 7803d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 781743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 2. Decompose and reorder Matras: 782743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 783743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Each matra and any syllable modifier sign in the cluster are moved to the 784743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * appropriate position relative to the consonant(s) in the cluster. The 785743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * shaping engine decomposes two- or three-part matras into their constituent 786743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * parts before any repositioning. Matra characters are classified by which 787743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * consonant in a conjunct they have affinity for and are reordered to the 788743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following positions: 789743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 790743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o Before first half form in the syllable 791743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After subjoined consonants 792743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After post-form consonant 793743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After main consonant (for above marks) 794743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 795743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 796743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 797743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The normalize() routine has already decomposed matras for us, so we don't 798743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * need to worry about that. 799743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 800743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 801743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 802743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 3. Reorder marks to canonical order: 803743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 804743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Adjacent nukta and halant or nukta and vedic sign are always repositioned 805743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * if necessary, so that the nukta is first. 806743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 807743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 808743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 809743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * We don't need to do this: the normalize() routine already did this for us. 810743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 811743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 812743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 81345d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod /* Reorder characters */ 81445d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 8153c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 816900cf3d449bf36d4f8b1474590cae925fef48fc8Behdad Esfahbod info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position()); 81755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 818075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 819075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].indic_position() = POS_BASE_C; 82045d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 82155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod /* Mark final consonants. A final consonant is one appearing after a matra, 82255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod * like in Khmer. */ 82355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 82455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (info[i].indic_category() == OT_M) { 82555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int j = i + 1; j < end; j++) 82655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (is_consonant (info[j])) { 82755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod info[j].indic_position() = POS_FINAL_C; 82855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 82955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 83055f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 83155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 83255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 833fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod /* Handle beginning Ra */ 8345e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod if (has_reph) 835dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() = POS_RA_TO_BECOME_REPH; 836fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod 837f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* For old-style Indic script tags, move the first post-base Halant after 838ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod * last consonant. Only do this if there is *not* a Halant after last 839ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod * consonant. Otherwise it becomes messy. */ 840914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->is_old_spec) { 8413c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 842f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (info[i].indic_category() == OT_H) { 843f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod unsigned int j; 844f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod for (j = end - 1; j > i; j--) 845ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod if (is_consonant (info[j]) || info[j].indic_category() == OT_H) 846f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 847ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod if (info[j].indic_category() != OT_H && j > i) { 848f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* Move Halant to after last consonant. */ 849f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod hb_glyph_info_t t = info[i]; 850f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); 851f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod info[j] = t; 852f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 853f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 854f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 855f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 856f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod 85781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* Attach misc marks to previous char to move with them. */ 858ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 85981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod indic_position_t last_pos = POS_START; 86081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod for (unsigned int i = start; i < end; i++) 86181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 86281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS))) 86381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 86481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() = last_pos; 865dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod if (unlikely (info[i].indic_category() == OT_H && 86681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() == POS_PRE_M)) 86781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 86881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* 86981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * Uniscribe doesn't move the Halant with Left Matra. 87081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * TEST: U+092B,U+093F,U+094DE 871dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We follow. This is important for the Sinhala 872dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA 873dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * where U+0DD9 is a left matra and U+0DCA is the virama. 874dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We don't want to move the virama with the left matra. 875dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * TEST: U+0D9A,U+0DDA 87681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod */ 877ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod for (unsigned int j = i; j > start; j--) 8786a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[j - 1].indic_position() != POS_PRE_M) { 879ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod info[i].indic_position() = info[j - 1].indic_position(); 880ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod break; 881ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 88281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 88381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } else if (info[i].indic_position() != POS_SMVD) { 88481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod last_pos = (indic_position_t) info[i].indic_position(); 885ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 88681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 887ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 88874ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod /* Re-attach ZWJ, ZWNJ, and halant to next char, for after-base consonants. */ 88974ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod { 89074ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod unsigned int last_halant = end; 89174ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 892deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (is_halant_or_coeng (info[i])) 89374ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod last_halant = i; 89474ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod else if (is_consonant (info[i])) { 89574ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int j = last_halant; j < i; j++) 89681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if (info[j].indic_position() != POS_SMVD) 89781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[j].indic_position() = info[i].indic_position(); 89874ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 89974ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 90045d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 901a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod { 9027b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod /* Things are out-of-control for post base positions, they may shuffle 9037b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * around like crazy, so merge clusters. For pre-base stuff, we handle 9047b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * cluster issues in final reordering. */ 9057b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod buffer->merge_clusters (base, end); 906a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Sit tight, rock 'n roll! */ 907d3637edb248162970e202e9d0671540274192844Behdad Esfahbod hb_bubble_sort (info + start, end - start, compare_indic_order); 908a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Find base again */ 909a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = end; 9103c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < end; i++) 911a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod if (info[i].indic_position() == POS_BASE_C) { 912a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = i; 913a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod break; 914a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 915a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 91645d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 917743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Setup masks now */ 918743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 919281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod { 920281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod hb_mask_t mask; 921281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod 922dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* Reph */ 923668c6046c1b3af3bd316bda0cc8636f2a5e8df42Behdad Esfahbod for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) 92485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[RPHF]; 925dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 926281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Pre-base */ 92785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[HALF]; 9283c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 929281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 930281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Base */ 93120b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = 0; 932075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 933075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].mask |= mask; 934281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Post-base */ 93585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF]; 9363c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 937281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 938281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod } 9399da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 94085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod if (indic_plan->is_old_spec && 94185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod buffer->props.script == HB_SCRIPT_DEVANAGARI) 94285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod { 94385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod /* Old-spec eye-lash Ra needs special handling. From the 94485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * spec: 94585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 94685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * "The feature 'below-base form' is applied to consonants 94785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * having below-base forms and following the base consonant. 94885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * The exception is vattu, which may appear below half forms 94985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * as well as below the base glyph. The feature 'below-base 95085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * form' will be applied to all such occurrences of Ra as well." 95185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 95285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * Test case: U+0924,U+094D,U+0930,U+094d,U+0915 95385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * with Sanskrit 2003 font. 95485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 95585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * However, note that Ra,Halant,ZWJ is the correct way to 95685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * request eyelash form of Ra, so we wouldbn't inhibit it 95785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * in that sequence. 95885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * 95985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod * Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915 96085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod */ 96185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod for (unsigned int i = start; i + 1 < base; i++) 96285c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod if (info[i ].indic_category() == OT_Ra && 96385c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+1].indic_category() == OT_H && 96485c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod (i + 2 == base || 96585c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+2].indic_category() != OT_ZWJ)) 96685c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod { 96785c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i ].mask |= indic_plan->mask_array[BLWF]; 96885c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod info[i+1].mask |= indic_plan->mask_array[BLWF]; 96985c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod } 97085c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod } 97185c51ec2e1d518019e32801ae38659c74fc20d80Behdad Esfahbod 97285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 2 < end) 97317d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod { 974771a8f50289e8fa458cfc3cd84f73a380ce98077Behdad Esfahbod /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ 97556be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod for (unsigned int i = base + 1; i + 1 < end; i++) { 97656be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint}; 97756be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face)) 9788e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 97985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 98085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 9810201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 9820201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod /* Mark the subsequent stuff with 'cfar'. Used in Khmer. 9830201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * Read the feature spec. 9840201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * This allows distinguishing the following cases with MS Khmer fonts: 9850201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+179A,U+17D2,U+1782 9860201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+1782,U+17D2,U+179A 9870201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod */ 9880201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod for (; i < end; i++) 98985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[CFAR]; 9900201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 9918e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 9928e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 99356be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod } 99417d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod } 99517d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod 9969da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod /* Apply ZWJ/ZWNJ effects */ 9973c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start + 1; i < end; i++) 9989da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod if (is_joiner (info[i])) { 9999da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod bool non_joiner = info[i].indic_category() == OT_ZWNJ; 10006b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod unsigned int j = i; 10019da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 10029da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod do { 10039da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod j--; 10046b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 100520b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWJ disables CJCT, however, it's mere presence is enough 100620b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod * to disable ligation. No explicit action needed. */ 100720b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod 100820b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWNJ disables HALF. */ 10096b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod if (non_joiner) 101085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[j].mask &= ~indic_plan->mask_array[HALF]; 10116b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 10129da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } while (j > start && !is_consonant (info[j])); 10139da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } 1014743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1015743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1016743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1017743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 10188bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan, 1019f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 10209f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 1021ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1022743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 1023c5306b6861cfaa50af40e8ceb058791fa06d7981Behdad Esfahbod /* We made the vowels look like consonants. So let's call the consonant logic! */ 1024f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1025743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1026743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1027743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 10288bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, 1029f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 10309f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 1031ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1032743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 103318c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain. 103418c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Only if not in compatibility mode that is... */ 103518c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 1036bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 103718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod { 103818c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* For dotted-circle, this is what Uniscribe does: 103918c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * If dotted-circle is the last glyph, it just does nothing. 104018c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Ie. It doesn't form Reph. */ 104118c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) 104218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod return; 104318c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod } 104418c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 1045f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1046743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1047743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1048743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 1049b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodinitial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan, 1050f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 1051b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer, 1052b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int start, unsigned int end) 1053b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1054b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod /* We already inserted dotted-circles, so just call the standalone_cluster. */ 1055f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_standalone_cluster (plan, face, buffer, start, end); 1056b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1057b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1058b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 1059327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 1060f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face HB_UNUSED, 1061327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 1062327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 1063743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 1064743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 1065743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 1066743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1067743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1068327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1069743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 1070327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_syllable (const hb_ot_shape_plan_t *plan, 1071f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 1072327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer, 1073327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start, unsigned int end) 1074327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod{ 1075327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); 1076327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod switch (syllable_type) { 1077f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; 1078f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return; 1079f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return; 1080f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; 1081f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return; 1082327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 1083327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod} 1084327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1085166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic inline void 10860beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbodinsert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, 1087b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_font_t *font, 1088b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer) 1089b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1090166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Note: This loop is extra overhead, but should not be measurable. */ 1091166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod bool has_broken_syllables = false; 1092166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod unsigned int count = buffer->len; 1093166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod for (unsigned int i = 0; i < count; i++) 1094166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) { 1095166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod has_broken_syllables = true; 1096166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod break; 1097166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod } 1098166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if (likely (!has_broken_syllables)) 1099166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod return; 1100166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 1101166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 1102b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_codepoint_t dottedcircle_glyph; 1103b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) 1104b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return; 1105b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1106f41dc2d35b23220d59d38990bb66f1cbd66a55b3Behdad Esfahbod hb_glyph_info_t dottedcircle = {0}; 1107b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = 0x25CC; 1108b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod set_indic_properties (dottedcircle); 1109b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = dottedcircle_glyph; 1110b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1111b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->clear_output (); 1112b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1113b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->idx = 0; 1114b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int last_syllable = 0; 1115b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod while (buffer->idx < buffer->len) 1116b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 1117b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int syllable = buffer->cur().syllable(); 1118b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); 1119b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) 1120b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 1121596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod last_syllable = syllable; 1122596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1123b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_glyph_info_t info = dottedcircle; 1124b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.cluster = buffer->cur().cluster; 1125b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.mask = buffer->cur().mask; 1126b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.syllable() = buffer->cur().syllable(); 1127596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1128596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod /* Insert dottedcircle after possible Repha. */ 1129596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod while (buffer->idx < buffer->len && 1130596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod last_syllable == buffer->cur().syllable() && 1131596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->cur().indic_category() == OT_Repha) 1132596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->next_glyph (); 1133596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 1134b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->output_info (info); 1135b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 1136596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod else 1137596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->next_glyph (); 1138b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 1139b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1140b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->swap_buffers (); 1141b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1142b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1143b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 11448bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 114524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod hb_font_t *font, 11463e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1147743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 114885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod update_consonant_positions (plan, font, buffer); 1149166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod insert_dotted_circles (plan, font, buffer); 1150327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 1151327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1152b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int count = buffer->len; 1153b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (!count)) return; 1154327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last = 0; 1155327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1156327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1157327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (last_syllable != info[i].syllable()) { 1158f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, i); 1159327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last = i; 1160327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last_syllable = info[last].syllable(); 1161327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 1162f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, count); 1163b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 1164b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 1165743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 116685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodfinal_reordering_syllable (const hb_ot_shape_plan_t *plan, 116785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer, 1168ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 1169743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 117085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 11714ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 11724ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 1173e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod /* 4. Final reordering: 1174e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1175e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * After the localized forms and basic shaping forms GSUB features have been 1176e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * applied (see below), the shaping engine performs some final glyph 1177e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * reordering before applying all the remaining font features to the entire 1178e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * cluster. 11794ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 11804ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 11814ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* Find base again */ 11825f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod unsigned int base; 11835f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod for (base = start; base < end; base++) 11845f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (info[base].indic_position() >= POS_BASE_C) { 11855f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (start < base && info[base].indic_position() > POS_BASE_C) 11865f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod base--; 11875f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod break; 11885f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod } 11894ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 11904705a7026900e51f6430f03a73c87f2df035df92Behdad Esfahbod 11914ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder matras: 1192e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1193e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base matra character had been reordered before applying basic 1194e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * features, the glyph can be moved closer to the main consonant based on 1195e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * whether half-forms had been formed. Actual position for the matra is 1196e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * defined as “after last standalone halant glyph, after initial matra 1197e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * position and before the main consonant”. If ZWJ or ZWNJ follow this 1198e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * halant, position is moved after it. 11994ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 12004ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 120165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ 12029d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 120365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we lost track of base, alas, position before last thingy. */ 120465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod unsigned int new_pos = base == end ? base - 2 : base - 1; 120565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 120627bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 120727bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 120827bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * We want to position matra after them. 120965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod */ 121027bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1211e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod { 121265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod while (new_pos > start && 121365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng))))) 121465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos--; 121565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 121665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we found no Halant we are done. 121765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * Otherwise only proceed if the Halant does 121865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * not belong to the Matra itself! */ 121965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (is_halant_or_coeng (info[new_pos]) && 122065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod info[new_pos].indic_position() != POS_PRE_M) 122165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 122265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 122365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) 122465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos++; 122565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 122665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod else 122765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos = start; /* No move. */ 122865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 12299d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod 123027bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M) 123165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 12329d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* Now go see if there's actually any matras... */ 1233921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod for (unsigned int i = new_pos; i > start; i--) 12346a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[i - 1].indic_position () == POS_PRE_M) 12359d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 12361a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod unsigned int old_pos = i - 1; 12371a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 12381a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0])); 12391a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod info[new_pos] = tmp; 1240921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod new_pos--; 12419d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 12422cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (new_pos, MIN (end, base + 1)); 1243abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } else { 1244e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod for (unsigned int i = start; i < base; i++) 1245abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod if (info[i].indic_position () == POS_PRE_M) { 12462cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (i, MIN (end, base + 1)); 1247abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod break; 1248abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } 12499d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 12504ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod } 12514ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 12524ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 12534ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder reph: 1254e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1255e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Reph’s original position is always at the beginning of the syllable, 1256e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * (i.e. it is not reordered at the character reordering stage). However, 1257e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * it will be reordered according to the basic-forms shaping results. 1258e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Possible positions for reph, depending on the script, are; after main, 1259e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * before post-base consonant forms, and after post-base consonant forms. 1260dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 1261dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1262dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* If there's anything after the Ra that has the REPH pos, it ought to be halant. 1263dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Which means that the font has failed to ligate the Reph. In which case, we 1264dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * shouldn't move. */ 1265dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod if (start + 1 < end && 1266dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() == POS_RA_TO_BECOME_REPH && 1267dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH) 1268dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod { 126911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int new_reph_pos; 127011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos = indic_plan->config->reph_pos; 127111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 127211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* XXX Figure out old behavior too */ 127302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1274dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* 1. If reph should be positioned after post-base consonant forms, 1275dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to step 5. 127602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 127711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_POST) 127802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 12799d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_step_5; 128002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 128102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 128202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 2. If the reph repositioning class is not after post-base: target 1283dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is after the first explicit halant glyph between the 1284dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-reph consonant and last main consonant. If ZWJ or ZWNJ 1285dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * are following this halant, position is moved after it. If such 1286dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is found, this is the target position. Otherwise, 1287dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to the next step. 1288dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * 1289dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Note: in old-implementation fonts, where classifications were 1290dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * fixed in shaping engine, there was no case where reph position 1291dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * will be found on this step. 129202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 129302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 129402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = start + 1; 1295deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 129602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 129702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1298deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 129902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 130002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 130102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 130202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 130302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 130402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 130502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 130602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 3. If reph should be repositioned after the main consonant: find the 1307dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first consonant not ligated with main, or find the first 1308dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant that is not a potential pre-base reordering Ra. 130902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 131011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_MAIN) 131102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1312b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos = base; 1313b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod /* XXX Skip potential pre-base reordering Ra. */ 131434ae336f3fae93ef9372881d545c817bce383041Behdad Esfahbod while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN) 1315b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos++; 1316b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod if (new_reph_pos < end) 1317b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod goto reph_move; 131802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 131902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 132002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 4. If reph should be positioned before post-base consonant, find 1321dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-base classified consonant not ligated with main. If no 1322dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant is found, the target position should be before the 1323dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first matra, syllable modifier sign or vedic sign. 132402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 13259d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* This is our take on what step 4 is trying to say (and failing, BADLY). */ 132611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_SUB) 132702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 13289d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos = base; 13299d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod while (new_reph_pos < end && 1330be8b9f5f715f6fb36b98bd33c3303f79cc068f8aBehdad Esfahbod !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD)))) 13319d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos++; 13329d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (new_reph_pos < end) 13339d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_move; 133402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 133502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 133602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 5. If no consonant is found in steps 3 or 4, move reph to a position 1337dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * immediately before the first post-base matra, syllable modifier 1338dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * sign or vedic sign that has a reordering class after the intended 1339dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * reph position. For example, if the reordering position for reph 1340dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * is post-main, it will skip above-base matras that also have a 1341dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * post-main position. 1342dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 134302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_step_5: 134402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1345d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* Copied from step 2. */ 1346d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos = start + 1; 1347d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 1348d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1349d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod 1350d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 1351d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 1352d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 1353d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1354d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod goto reph_move; 1355d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod } 135602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1357dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 135802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 6. Otherwise, reorder reph to the end of the syllable. 135902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 136002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 136102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = end - 1; 136202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD) 136302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 136402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1365892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod /* 1366892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * If the Reph is to be ending up after a Matra,Halant sequence, 1367892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * position it before that Halant so it can interact with the Matra. 1368892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * However, if it's a plain Consonant,Halant we shouldn't do that. 1369892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * Uniscribe doesn't do this. 1370892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * TEST: U+0930,U+094D,U+0915,U+094B,U+094D 1371892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod */ 1372bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (!hb_options ().uniscribe_bug_compatible && 1373deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod unlikely (is_halant_or_coeng (info[new_reph_pos]))) { 137402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod for (unsigned int i = base + 1; i < new_reph_pos; i++) 137502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (info[i].indic_category() == OT_M) { 137602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Ok, got it. */ 137702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 137802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 137902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 138002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 13818df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod } 13828df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod 138302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_move: 138402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1385e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod /* Yay, one big cluster! Merge before moving. */ 1386e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 1387e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod 138802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Move */ 138902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod hb_glyph_info_t reph = info[start]; 139002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0])); 139102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod info[new_reph_pos] = reph; 139202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1393dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod } 1394dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1395dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1396dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* o Reorder pre-base reordering consonants: 1397e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1398e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base reordering consonant is found, reorder it according to 1399e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * the following rules: 1400e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod */ 1401e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 140285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ 140346e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod { 14048e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 140585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) 140678818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod { 14078e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 1. Only reorder a glyph produced by substitution during application 14088e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * of the <pref> feature. (Note that a font may shape a Ra consonant with 14098e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * the feature generally but block it in certain contexts.) 14108e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 141185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (i + 1 == end || (info[i + 1].mask & indic_plan->mask_array[PREF]) == 0) 14128e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 14138e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 14148e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 2. Try to find a target position the same way as for pre-base matra. 14158e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * If it is found, reorder pre-base consonant glyph. 14168e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 14178e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 3. If position is not found, reorder immediately before main 14188e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * consonant. 14198e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 14208e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 14218e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int new_pos = base; 142288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 142388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 142488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * We want to position matra after them. 142588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod */ 142688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1427d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 142888d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod while (new_pos > start && 142988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS))) 143088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 143188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod 143288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* In Khmer coeng model, a V,Ra can go *after* matras. If it goes after a 143388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * split matra, it should be reordered to *before* the left part of such matra. */ 143488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) 143588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 143688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod unsigned int old_pos = i; 143788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod for (unsigned int i = base + 1; i < old_pos; i++) 143888d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (info[i].indic_category() == OT_M) 143988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 144088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 144188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod break; 144288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 144388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 1444d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1445d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod 1446deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) 14478e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 14488e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if (new_pos < end && is_joiner (info[new_pos])) 14498e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos++; 14508e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 14518e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 14528e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int old_pos = i; 1453e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (new_pos, old_pos + 1); 14548e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 14558e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0])); 14568e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[new_pos] = tmp; 14578e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 14588e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 14598e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 14608e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 146178818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod } 146246e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod } 1463eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1464eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1465a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod /* Apply 'init' to the Left Matra if it's a word start. */ 14666a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[start].indic_position () == POS_PRE_M && 1467a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod (!start || 1468eace47b173807d94b29a6490d0bc3c9f8f6168d1Behdad Esfahbod !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & 14692c372b80f6befad69e216e3f218b38640b8cc044Behdad Esfahbod FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))) 147085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[start].mask |= indic_plan->mask_array[INIT]; 1471a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod 1472eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 14738ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod /* 14748ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod * Finish off the clusters and go home! 14758ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod */ 1476bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible) 1477ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 147830c3d5e9fc61b49c2c6ad4e744300edd6f3e0261Behdad Esfahbod /* Uniscribe merges the entire cluster. 147921d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This means, half forms are submerged into the main consonants cluster. 148021d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This is unnecessary, and makes cursor positioning harder, but that's what 148121d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * Uniscribe does. */ 1482e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 148321d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod } 1484ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod} 1485e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1486e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1487ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbodstatic void 14888bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 14890beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod hb_font_t *font HB_UNUSED, 14903e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1491ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod{ 1492ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int count = buffer->len; 1493327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (unlikely (!count)) return; 1494ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod 1495ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1496ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int last = 0; 1497cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1498ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1499cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod if (last_syllable != info[i].syllable()) { 150085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, i); 1501ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod last = i; 1502cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod last_syllable = info[last].syllable(); 1503ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod } 150485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, count); 1505e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 150680cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod /* Zero syllables now... */ 150780cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 150880cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod info[i].syllable() = 0; 150980cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod 1510743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); 1511743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); 1512743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1513743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1514743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1515b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic hb_ot_shape_normalization_mode_t 15160beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbodnormalization_preference_indic (const hb_segment_properties_t *props HB_UNUSED) 1517b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1518b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT; 1519b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1520b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1521eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1522eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahboddecompose_indic (const hb_ot_shape_normalize_context_t *c, 15230736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t ab, 15240736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *a, 15250736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *b) 15260736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 15270736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod switch (ab) 15280736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 15290736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Don't decompose these. */ 15300736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0931 : return false; 15310736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0B94 : return false; 15320736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 15330736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 15340736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* 15350736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod * Decompose split matras that don't have Unicode decompositions. 15360736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod */ 15370736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 15380736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true; 15390736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true; 15400736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true; 15410736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true; 15420736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true; 15430736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true; 15440736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true; 15450736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1925 : *a = 0x1920; *b= 0x1923; return true; 15460736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1926 : *a = 0x1920; *b= 0x1924; return true; 15470736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true; 15480736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1112E : *a = 0x11127; *b= 0x11131; return true; 15490736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1112F : *a = 0x11127; *b= 0x11132; return true; 15500736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#if 0 15510736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* This one has no decomposition in Unicode, but needs no decomposition either. */ 15520736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* case 0x0AC9 : return false; */ 15530736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0B57 : *a = no decomp, -> RIGHT; return true; 15540736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1C29 : *a = no decomp, -> LEFT; return true; 15550736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0xA9C0 : *a = no decomp, -> RIGHT; return true; 15560736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x111BF : *a = no decomp, -> ABOVE; return true; 15570736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#endif 15580736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 15590736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 156043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod if ((ab == 0x0DDA || hb_in_range<hb_codepoint_t> (ab, 0x0DDC, 0x0DDE))) 15610736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 156243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* 156343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Sinhala split matras... Let the fun begin. 156443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 156543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * These four characters have Unicode decompositions. However, Uniscribe 156643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * decomposes them "Khmer-style", that is, it uses the character itself to 156743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * get the second half. The first half of all four decompositions is always 156843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * U+0DD9. 156943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 157043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are 157143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * broken with Uniscribe. But we need to support them. As such, we only 157243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * do the Uniscribe-style decomposition if the character is transformed into 157343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * its "sec.half" form by the 'pstf' feature. Otherwise, we fall back to 157443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Unicode decomposition. 157543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 157643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Note that we can't unconditionally use Unicode decomposition. That would 157743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * break some other fonts, that are designed to work with Uniscribe, and 157843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * don't have positioning features for the Unicode-style decomposition. 157943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 158043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Argh... 1581b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * 1582b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * The Uniscribe behavior is now documented in the newly published Sinhala 1583b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * spec in 2012: 1584b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * 1585b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shaping 158643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod */ 158743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 158843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data; 158943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 159043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod hb_codepoint_t glyph; 159143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 1592bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod if (hb_options ().uniscribe_bug_compatible || 159343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod (c->font->get_glyph (ab, 0, &glyph) && 159443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face))) 159543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod { 159643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* Ok, safe to use Uniscribe-style decomposition. */ 159743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *a = 0x0DD9; 159843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *b = ab; 159943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod return true; 160043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod } 16010736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 16020736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1603eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->decompose (ab, a, b); 16040736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 16050736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1606eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1607eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodcompose_indic (const hb_ot_shape_normalize_context_t *c, 16080736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t a, 16090736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t b, 16100736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *ab) 16110736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 16120736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Avoid recomposing split matras. */ 1613eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a))) 16140736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod return false; 16150736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 16160736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Composition-exclusion exceptions that we want to recompose. */ 16170736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; } 16180736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1619eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->compose (a, b, ab); 16200736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 16210736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 16220736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1623693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = 1624693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{ 1625693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod "indic", 1626693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod collect_features_indic, 1627693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod override_features_indic, 1628a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_create_indic, 1629a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_destroy_indic, 16309f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod NULL, /* preprocess_text */ 1631b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod normalization_preference_indic, 16320736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod decompose_indic, 16330736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod compose_indic, 1634693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod setup_masks_indic, 1635568000274c8edb5f41bc4f876ce21fcc8bdaeed8Behdad Esfahbod HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, 1636865745b5b87236651f5663cae3461db9cb505eedBehdad Esfahbod false, /* fallback_position */ 1637693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod}; 1638