143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod/* 243f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Copyright © 2010,2012 Google, Inc. 343f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 443f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * This is part of HarfBuzz, a text shaping library. 543f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Permission is hereby granted, without written agreement and without 743f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this 843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * software and its documentation for any purpose, provided that the 943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * above copyright notice and the following two paragraphs appear in 1043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * all copies of this software. 1143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 1243f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1343f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1443f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1543f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * DAMAGE. 1743f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 1843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 1943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 2043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 2143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 2243f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 2343f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 2443f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Google Author(s): Behdad Esfahbod 2543f04a7456419153cb03e610a825056a47824780Behdad Esfahbod */ 2643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod 2743f04a7456419153cb03e610a825056a47824780Behdad Esfahbod#include "hb-ot-shape-complex-private.hh" 2843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod 2943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod 3043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod/* Thai / Lao shaper */ 3143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod 321eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 331eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod/* PUA shaping */ 341eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 351eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 361eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodenum thai_consonant_type_t 371eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod{ 381eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod NC, 391eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod AC, 401eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod RC, 411eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod DC, 421eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod NOT_CONSONANT, 431eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod NUM_CONSONANT_TYPES = NOT_CONSONANT 441eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod}; 451eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 461eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodstatic thai_consonant_type_t 471eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodget_consonant_type (hb_codepoint_t u) 481eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod{ 497627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if (u == 0x0E1Bu || u == 0x0E1Du || u == 0x0E1Fu/* || u == 0x0E2Cu*/) 501eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod return AC; 517627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if (u == 0x0E0Du || u == 0x0E10u) 521eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod return RC; 537627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if (u == 0x0E0Eu || u == 0x0E0Fu) 541eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod return DC; 557627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if (hb_in_range (u, 0x0E01u, 0x0E2Eu)) 561eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod return NC; 571eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod return NOT_CONSONANT; 581eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod} 591eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 601eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 611eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodenum thai_mark_type_t 621eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod{ 631eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod AV, 641eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod BV, 651eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod T, 661eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod NOT_MARK, 671eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod NUM_MARK_TYPES = NOT_MARK 681eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod}; 691eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 701eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodstatic thai_mark_type_t 711eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodget_mark_type (hb_codepoint_t u) 721eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod{ 737627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if (u == 0x0E31u || hb_in_range (u, 0x0E34u, 0x0E37u) || 747627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod u == 0x0E47u || hb_in_range (u, 0x0E4Du, 0x0E4Eu)) 751eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod return AV; 767627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if (hb_in_range (u, 0x0E38u, 0x0E3Au)) 771eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod return BV; 787627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod if (hb_in_range (u, 0x0E48u, 0x0E4Cu)) 791eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod return T; 801eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod return NOT_MARK; 811eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod} 821eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 831eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 841eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodenum thai_action_t 851eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod{ 861eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod NOP, 871eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod SD, /* Shift combining-mark down */ 881eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod SL, /* Shift combining-mark left */ 891eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod SDL, /* Shift combining-mark down-left */ 901eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod RD /* Remove descender from base */ 911eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod}; 921eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 931eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodstatic hb_codepoint_t 941eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodthai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font) 951eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod{ 961eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod struct thai_pua_mapping_t { 971eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod hb_codepoint_t u; 981eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod hb_codepoint_t win_pua; 991eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod hb_codepoint_t mac_pua; 1001eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod } const *pua_mappings = NULL; 1011eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod static const thai_pua_mapping_t SD_mappings[] = { 1027627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E48u, 0xF70Au, 0xF88Bu}, /* MAI EK */ 1037627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E49u, 0xF70Bu, 0xF88Eu}, /* MAI THO */ 1047627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E4Au, 0xF70Cu, 0xF891u}, /* MAI TRI */ 1057627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E4Bu, 0xF70Du, 0xF894u}, /* MAI CHATTAWA */ 1067627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E4Cu, 0xF70Eu, 0xF897u}, /* THANTHAKHAT */ 1077627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E38u, 0xF718u, 0xF89Bu}, /* SARA U */ 1087627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E39u, 0xF719u, 0xF89Cu}, /* SARA UU */ 1097627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E3Au, 0xF71Au, 0xF89Du}, /* PHINTHU */ 1107627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0000u, 0x0000u, 0x0000u} 1111eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod }; 1121eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod static const thai_pua_mapping_t SDL_mappings[] = { 1137627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E48u, 0xF705u, 0xF88Cu}, /* MAI EK */ 1147627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E49u, 0xF706u, 0xF88Fu}, /* MAI THO */ 1157627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E4Au, 0xF707u, 0xF892u}, /* MAI TRI */ 1167627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E4Bu, 0xF708u, 0xF895u}, /* MAI CHATTAWA */ 1177627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E4Cu, 0xF709u, 0xF898u}, /* THANTHAKHAT */ 1187627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0000u, 0x0000u, 0x0000u} 1191eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod }; 1201eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod static const thai_pua_mapping_t SL_mappings[] = { 1217627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E48u, 0xF713u, 0xF88Au}, /* MAI EK */ 1227627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E49u, 0xF714u, 0xF88Du}, /* MAI THO */ 1237627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E4Au, 0xF715u, 0xF890u}, /* MAI TRI */ 1247627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E4Bu, 0xF716u, 0xF893u}, /* MAI CHATTAWA */ 1257627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E4Cu, 0xF717u, 0xF896u}, /* THANTHAKHAT */ 1267627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E31u, 0xF710u, 0xF884u}, /* MAI HAN-AKAT */ 1277627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E34u, 0xF701u, 0xF885u}, /* SARA I */ 1287627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E35u, 0xF702u, 0xF886u}, /* SARA II */ 1297627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E36u, 0xF703u, 0xF887u}, /* SARA UE */ 1307627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E37u, 0xF704u, 0xF888u}, /* SARA UEE */ 1317627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E47u, 0xF712u, 0xF889u}, /* MAITAIKHU */ 1327627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E4Du, 0xF711u, 0xF899u}, /* NIKHAHIT */ 1337627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0000u, 0x0000u, 0x0000u} 1341eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod }; 1351eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod static const thai_pua_mapping_t RD_mappings[] = { 1367627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E0Du, 0xF70Fu, 0xF89Au}, /* YO YING */ 1377627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0E10u, 0xF700u, 0xF89Eu}, /* THO THAN */ 1387627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod {0x0000u, 0x0000u, 0x0000u} 1391eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod }; 1401eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 1411eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod switch (action) { 1421eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod default: assert (false); /* Fallthrough */ 1431eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod case NOP: return u; 1441eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod case SD: pua_mappings = SD_mappings; break; 1451eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod case SDL: pua_mappings = SDL_mappings; break; 1461eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod case SL: pua_mappings = SL_mappings; break; 1471eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod case RD: pua_mappings = RD_mappings; break; 1481eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod } 1491eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod for (; pua_mappings->u; pua_mappings++) 1501eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod if (pua_mappings->u == u) 1511eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod { 1521eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod hb_codepoint_t glyph; 1531eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod if (hb_font_get_glyph (font, pua_mappings->win_pua, 0, &glyph)) 1541eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod return pua_mappings->win_pua; 1551eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod if (hb_font_get_glyph (font, pua_mappings->mac_pua, 0, &glyph)) 1561eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod return pua_mappings->mac_pua; 1571eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod break; 1581eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod } 1591eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod return u; 1601eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod} 1611eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 1621eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 1631eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodstatic enum thai_above_state_t 1641eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod{ /* Cluster above looks like: */ 1651eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod T0, /* ⣤ */ 1661eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod T1, /* ⣼ */ 1671eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod T2, /* ⣾ */ 1681eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod T3, /* ⣿ */ 1691eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod NUM_ABOVE_STATES 1701eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod} thai_above_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] = 1711eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod{ 1721eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod T0, /* NC */ 1731eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod T1, /* AC */ 1741eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod T0, /* RC */ 1751eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod T0, /* DC */ 1761eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod T3, /* NOT_CONSONANT */ 1771eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod}; 1781eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 1791eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodstatic const struct thai_above_state_machine_edge_t { 1801eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod thai_action_t action; 1811eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod thai_above_state_t next_state; 1821eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod} thai_above_state_machine[NUM_ABOVE_STATES][NUM_MARK_TYPES] = 1831eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod{ /*AV*/ /*BV*/ /*T*/ 1841eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod/*T0*/ {{NOP,T3}, {NOP,T0}, {SD, T3}}, 1851eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod/*T1*/ {{SL, T2}, {NOP,T1}, {SDL,T2}}, 1861eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod/*T2*/ {{NOP,T3}, {NOP,T2}, {SL, T3}}, 1871eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod/*T3*/ {{NOP,T3}, {NOP,T3}, {NOP,T3}}, 1881eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod}; 1891eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 1901eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 1911eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodstatic enum thai_below_state_t 1921eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod{ 1931eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod B0, /* No descender */ 1941eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod B1, /* Removable descender */ 1951eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod B2, /* Strict descender */ 1961eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod NUM_BELOW_STATES 1971eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod} thai_below_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] = 1981eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod{ 1991eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod B0, /* NC */ 2001eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod B0, /* AC */ 2011eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod B1, /* RC */ 2021eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod B2, /* DC */ 2031eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod B2, /* NOT_CONSONANT */ 2041eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod}; 2051eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 2061eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbodstatic const struct thai_below_state_machine_edge_t { 2071eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod thai_action_t action; 2081eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod thai_below_state_t next_state; 2091eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod} thai_below_state_machine[NUM_BELOW_STATES][NUM_MARK_TYPES] = 2101eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod{ /*AV*/ /*BV*/ /*T*/ 2111eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod/*B0*/ {{NOP,B0}, {NOP,B2}, {NOP, B0}}, 2121eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod/*B1*/ {{NOP,B1}, {RD, B2}, {NOP, B1}}, 2131eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod/*B2*/ {{NOP,B2}, {SD, B2}, {NOP, B2}}, 2141eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod}; 2151eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 2161eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 21743f04a7456419153cb03e610a825056a47824780Behdad Esfahbodstatic void 2180beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahboddo_thai_pua_shaping (const hb_ot_shape_plan_t *plan HB_UNUSED, 219851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod hb_buffer_t *buffer, 220851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod hb_font_t *font) 221851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod{ 2221eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod thai_above_state_t above_state = thai_above_start_state[NOT_CONSONANT]; 2231eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod thai_below_state_t below_state = thai_below_start_state[NOT_CONSONANT]; 2241eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod unsigned int base = 0; 2251eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 2261eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 2271eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod unsigned int count = buffer->len; 2281eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod for (unsigned int i = 0; i < count; i++) 2291eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod { 2301eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod thai_mark_type_t mt = get_mark_type (info[i].codepoint); 2311eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 2321eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod if (mt == NOT_MARK) { 2331eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod thai_consonant_type_t ct = get_consonant_type (info[i].codepoint); 2341eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod above_state = thai_above_start_state[ct]; 2351eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod below_state = thai_below_start_state[ct]; 2361eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod base = i; 2371eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod continue; 2381eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod } 2391eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 2401eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod const thai_above_state_machine_edge_t &above_edge = thai_above_state_machine[above_state][mt]; 2411eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod const thai_below_state_machine_edge_t &below_edge = thai_below_state_machine[below_state][mt]; 2421eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod above_state = above_edge.next_state; 2431eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod below_state = below_edge.next_state; 2441eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 2451eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod /* At least one of the above/below actions is NOP. */ 2461eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod thai_action_t action = above_edge.action != NOP ? above_edge.action : below_edge.action; 2471eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 2481eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod if (action == RD) 2491eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod info[base].codepoint = thai_pua_shape (info[base].codepoint, action, font); 2501eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod else 2511eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod info[i].codepoint = thai_pua_shape (info[i].codepoint, action, font); 2521eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod } 253851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod} 254851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod 2551eb3e94fe99a072ce422e60ac4d4d89ef489b08aBehdad Esfahbod 256851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbodstatic void 257851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbodpreprocess_text_thai (const hb_ot_shape_plan_t *plan, 25843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod hb_buffer_t *buffer, 259851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod hb_font_t *font) 26043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod{ 261851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod /* This function implements the shaping logic documented here: 262851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod * 263851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod * http://linux.thai.net/~thep/th-otf/shaping.html 264851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod * 265851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod * The first shaping rule listed there is needed even if the font has Thai 266851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod * OpenType tables. The rest do fallback positioning based on PUA codepoints. 267851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod * We implement that only if there exist no Thai GSUB in the font. 268851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod */ 269851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod 27043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod /* The following is NOT specified in the MS OT Thai spec, however, it seems 27143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * to be what Uniscribe and other engines implement. According to Eric Muller: 27243f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 27343f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * When you have a SARA AM, decompose it in NIKHAHIT + SARA AA, *and* move the 27443f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * NIKHAHIT backwards over any tone mark (0E48-0E4B). 27543f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 27643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32> 27743f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 27843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * This reordering is legit only when the NIKHAHIT comes from a SARA AM, not 27943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * when it's there to start with. The string <0E14, 0E4B, 0E4D> is probably 28043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * not what a user wanted, but the rendering is nevertheless nikhahit above 28143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * chattawa. 28243f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 28343f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Same for Lao. 28443f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 28543f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Note: 28643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 28743f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Uniscribe also does some below-marks reordering. Namely, it positions U+0E3A 28843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * after U+0E38 and U+0E39. We do that by modifying the ccc for U+0E3A. 28943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * See unicode->modified_combining_class (). Lao does NOT have a U+0E3A 29043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * equivalent. 29143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod */ 29243f04a7456419153cb03e610a825056a47824780Behdad Esfahbod 29343f04a7456419153cb03e610a825056a47824780Behdad Esfahbod 29443f04a7456419153cb03e610a825056a47824780Behdad Esfahbod /* 29543f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Here are the characters of significance: 29643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 29743f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Thai Lao 29843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * SARA AM: U+0E33 U+0EB3 29943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * SARA AA: U+0E32 U+0EB2 30043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Nikhahit: U+0E4D U+0ECD 30143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 30243f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Testing shows that Uniscribe reorder the following marks: 30343f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Thai: <0E31,0E34..0E37,0E47..0E4E> 30443f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Lao: <0EB1,0EB4..0EB7,0EC7..0ECE> 30543f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * 30643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * Note how the Lao versions are the same as Thai + 0x80. 30743f04a7456419153cb03e610a825056a47824780Behdad Esfahbod */ 30843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod 30943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod /* We only get one script at a time, so a script-agnostic implementation 31043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * is adequate here. */ 3117627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_SARA_AM(x) (((x) & ~0x0080u) == 0x0E33u) 3127627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0x0E33u + 0x0E4Du) 31343f04a7456419153cb03e610a825056a47824780Behdad Esfahbod#define SARA_AA_FROM_SARA_AM(x) ((x) - 1) 3147627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod#define IS_TONE_MARK(x) (hb_in_ranges ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u)) 31543f04a7456419153cb03e610a825056a47824780Behdad Esfahbod 31643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod buffer->clear_output (); 31743f04a7456419153cb03e610a825056a47824780Behdad Esfahbod unsigned int count = buffer->len; 31843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod for (buffer->idx = 0; buffer->idx < count;) 31943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod { 32043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod hb_codepoint_t u = buffer->cur().codepoint; 32143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod if (likely (!IS_SARA_AM (u))) { 32243f04a7456419153cb03e610a825056a47824780Behdad Esfahbod buffer->next_glyph (); 32343f04a7456419153cb03e610a825056a47824780Behdad Esfahbod continue; 32443f04a7456419153cb03e610a825056a47824780Behdad Esfahbod } 32543f04a7456419153cb03e610a825056a47824780Behdad Esfahbod 32643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod /* Is SARA AM. Decompose and reorder. */ 32743f04a7456419153cb03e610a825056a47824780Behdad Esfahbod hb_codepoint_t decomposed[2] = {hb_codepoint_t (NIKHAHIT_FROM_SARA_AM (u)), 32843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod hb_codepoint_t (SARA_AA_FROM_SARA_AM (u))}; 32943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod buffer->replace_glyphs (1, 2, decomposed); 33043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod if (unlikely (buffer->in_error)) 33143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod return; 33243f04a7456419153cb03e610a825056a47824780Behdad Esfahbod 33380f7405a5208f88b8615aa4ce4c54ffeb16f04f8Jonathan Kew /* Make Nikhahit be recognized as a mark when zeroing widths. */ 33443f04a7456419153cb03e610a825056a47824780Behdad Esfahbod unsigned int end = buffer->out_len; 33580f7405a5208f88b8615aa4ce4c54ffeb16f04f8Jonathan Kew _hb_glyph_info_set_general_category (&buffer->out_info[end - 2], HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK); 33680f7405a5208f88b8615aa4ce4c54ffeb16f04f8Jonathan Kew 33780f7405a5208f88b8615aa4ce4c54ffeb16f04f8Jonathan Kew /* Ok, let's see... */ 33843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod unsigned int start = end - 2; 33943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint)) 34043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod start--; 34143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod 34243f04a7456419153cb03e610a825056a47824780Behdad Esfahbod if (start + 2 < end) 34343f04a7456419153cb03e610a825056a47824780Behdad Esfahbod { 34443f04a7456419153cb03e610a825056a47824780Behdad Esfahbod /* Move Nikhahit (end-2) to the beginning */ 34543f04a7456419153cb03e610a825056a47824780Behdad Esfahbod buffer->merge_out_clusters (start, end); 34643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod hb_glyph_info_t t = buffer->out_info[end - 2]; 34743f04a7456419153cb03e610a825056a47824780Behdad Esfahbod memmove (buffer->out_info + start + 1, 34843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod buffer->out_info + start, 34943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod sizeof (buffer->out_info[0]) * (end - start - 2)); 35043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod buffer->out_info[start] = t; 35143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod } 35243f04a7456419153cb03e610a825056a47824780Behdad Esfahbod else 35343f04a7456419153cb03e610a825056a47824780Behdad Esfahbod { 35443f04a7456419153cb03e610a825056a47824780Behdad Esfahbod /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the 35543f04a7456419153cb03e610a825056a47824780Behdad Esfahbod * previous cluster. */ 35643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod if (start) 35743f04a7456419153cb03e610a825056a47824780Behdad Esfahbod buffer->merge_out_clusters (start - 1, end); 35843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod } 35943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod } 36043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod buffer->swap_buffers (); 361851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod 362851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod /* If font has Thai GSUB, we are done. */ 363851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod if (plan->props.script == HB_SCRIPT_THAI && !plan->map.found_script[0]) 364851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod do_thai_pua_shaping (plan, buffer, font); 36543f04a7456419153cb03e610a825056a47824780Behdad Esfahbod} 36643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod 36743f04a7456419153cb03e610a825056a47824780Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai = 36843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod{ 36943f04a7456419153cb03e610a825056a47824780Behdad Esfahbod "thai", 37043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod NULL, /* collect_features */ 37143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod NULL, /* override_features */ 37243f04a7456419153cb03e610a825056a47824780Behdad Esfahbod NULL, /* data_create */ 37343f04a7456419153cb03e610a825056a47824780Behdad Esfahbod NULL, /* data_destroy */ 37443f04a7456419153cb03e610a825056a47824780Behdad Esfahbod preprocess_text_thai, 3753d6ca0d32e5c6597acfcf59301cb1905586ddb52Behdad Esfahbod HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT, 37643f04a7456419153cb03e610a825056a47824780Behdad Esfahbod NULL, /* decompose */ 37743f04a7456419153cb03e610a825056a47824780Behdad Esfahbod NULL, /* compose */ 37843f04a7456419153cb03e610a825056a47824780Behdad Esfahbod NULL, /* setup_masks */ 3796300cd72539284ca294ee8286bbbb7f9c72af320Behdad Esfahbod HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT, 38043f04a7456419153cb03e610a825056a47824780Behdad Esfahbod false,/* fallback_position */ 38143f04a7456419153cb03e610a825056a47824780Behdad Esfahbod}; 382