hb-ot-shape-complex-indic.cc revision 568000274c8edb5f41bc4f876ce21fcc8bdaeed8
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 301d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 3111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 3211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Global Indic shaper options. 3311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 341d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 35a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodstruct indic_options_t 36ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod{ 37a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod int initialized : 1; 38a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod int uniscribe_bug_compatible : 1; 39a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod}; 40a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 41a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodunion indic_options_union_t { 42a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod int i; 43a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod indic_options_t opts; 44a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod}; 45a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad EsfahbodASSERT_STATIC (sizeof (int) == sizeof (indic_options_union_t)); 46a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 47a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodstatic indic_options_union_t 48a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodindic_options_init (void) 49a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod{ 50a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod indic_options_union_t u; 51a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod u.i = 0; 52a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod u.opts.initialized = 1; 53a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 54a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod char *c = getenv ("HB_OT_INDIC_OPTIONS"); 55a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible"); 56a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 57a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod return u; 58a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod} 59a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 60a02d86484be870615297abfc7be9f94645434762Behdad Esfahbodstatic inline indic_options_t 61a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodindic_options (void) 62a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod{ 63a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod static indic_options_union_t options; 64a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 65a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (unlikely (!options.i)) { 66a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod /* This is idempotent and threadsafe. */ 67a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod options = indic_options_init (); 68ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 69ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod 70a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod return options.opts; 71a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod} 72a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 73ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod 7411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 7511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic configurations. Note that we do not want to keep every single script-specific 7611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * behavior in these tables necessarily. This should mainly be used for per-script 7711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * properties that are cheaper keeping here, than in the code. Ie. if, say, one and 7811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * only one script has an exception, that one script can be if'ed directly in the code, 7911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * instead of adding a new flag in these structs. 8011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 8111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 8211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum base_position_t { 8311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_FIRST, 8411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_LAST 8511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 8611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_position_t { 8711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_DEFAULT = POS_BEFORE_POST, 8811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 8911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_MAIN = POS_AFTER_MAIN, 9011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_SUB = POS_BEFORE_SUB, 9111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_SUB = POS_AFTER_SUB, 9211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_POST = POS_BEFORE_POST, 9311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_POST = POS_AFTER_POST 9411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 9511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_mode_t { 9611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_IMPLICIT, /* Reph formed out of initial Ra,H sequence. */ 9711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_EXPLICIT, /* Reph formed out of initial Ra,H,ZWJ sequence. */ 9811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */ 9911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_LOG_REPHA /* Encoded Repha character, needs reordering. */ 10011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 10111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstruct indic_config_t 10211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 10311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_script_t script; 10411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool has_old_spec; 10511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_codepoint_t virama; 10611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base_position_t base_pos; 10711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos; 10811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_mode_t reph_mode; 10911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 11011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 11111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstatic const indic_config_t indic_configs[] = 11211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 11311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Default. Should be first. */ 11411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_DEFAULT, REPH_MODE_IMPLICIT}, 11511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT}, 11611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_BENGALI, true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT}, 11711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_GURMUKHI, true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT}, 11811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_GUJARATI, true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT}, 11911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_ORIYA, true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT}, 12011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_TAMIL, true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT}, 12111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_TELUGU, true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT}, 12211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_KANNADA, true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT}, 12311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA}, 12411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT}, 12511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT, REPH_MODE_VIS_REPHA}, 12611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 12711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 12811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 12911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 13011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 13111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic shaper. 13211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 1339ccc6382ba43760167c134c18c1c4ada4b8c3f22Behdad Esfahbod 134eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstruct feature_list_t { 135c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_tag_t tag; 136c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_bool_t is_global; 137eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod}; 138eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 139eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstatic const feature_list_t 14085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodindic_features[] = 141b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 14285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 14385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Basic features. 14485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied in order, one at a time, after initial_reordering. 14585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 146c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('n','u','k','t'), true}, 147e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod {HB_TAG('a','k','h','n'), true}, 148c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('r','p','h','f'), false}, 1491ac075b227090a9ad930dcc1670236c176b27067Behdad Esfahbod {HB_TAG('r','k','r','f'), true}, 150c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('p','r','e','f'), false}, 151c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('h','a','l','f'), false}, 152167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod {HB_TAG('b','l','w','f'), false}, 15329f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod {HB_TAG('a','b','v','f'), false}, 154c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('p','s','t','f'), false}, 1550201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod {HB_TAG('c','f','a','r'), false}, 15620b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod {HB_TAG('c','j','c','t'), true}, 1571d6846db9ebf84561bb30a4e48c6c43184914099Behdad Esfahbod {HB_TAG('v','a','t','u'), true}, 15885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 15985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Other features. 16085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied all at once, after final_reordering. 16185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 16285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('i','n','i','t'), false}, 16385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('p','r','e','s'), true}, 16485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('a','b','v','s'), true}, 16585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('b','l','w','s'), true}, 16685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('p','s','t','s'), true}, 16785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('h','a','l','n'), true}, 16885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* Positioning features, though we don't care about the types. */ 16985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('d','i','s','t'), true}, 17085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('a','b','v','m'), true}, 17185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('b','l','w','m'), true}, 172c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod}; 173c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod 17485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod/* 17585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Must be in the same order as the indic_features array. 17685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 177c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbodenum { 178c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod _NUKT, 179e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod _AKHN, 180c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod RPHF, 181df6d45c693c417bf311e6fa49f18a8558542e525Behdad Esfahbod _RKRF, 182c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PREF, 183c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod HALF, 184167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod BLWF, 18529f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod ABVF, 186c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PSTF, 1870201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod CFAR, 18820b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod _CJCT, 18985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _VATU, 19085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 19185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INIT, 19285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PRES, 19385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVS, 19485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWS, 19585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PSTS, 19685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _HALN, 19785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _DIST, 19885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVM, 19985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWM, 20085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 20185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_NUM_FEATURES, 20285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */ 203b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod}; 204b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 205743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 206166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan, 207166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font, 208166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer); 209166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 2108bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 211afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 2123e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 213f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbodstatic void 2148bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 215afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 2163e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 217b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 218693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 21916c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodcollect_features_indic (hb_ot_shape_planner_t *plan) 220b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 22116c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_ot_map_builder_t *map = &plan->map; 22216c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod 223166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Do this before any lookups have been applied. */ 224166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod map->add_gsub_pause (setup_syllables); 225166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 226f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_bool_feature (HB_TAG('l','o','c','l')); 227a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod /* The Indic specs do not require ccmp, but we apply it here since if 228a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod * there is a use of it, it's typically at the beginning. */ 229f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_bool_feature (HB_TAG('c','c','m','p')); 230f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 231f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 23285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod unsigned int i = 0; 23385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_gsub_pause (initial_reordering); 23485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_BASIC_FEATURES; i++) { 23585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); 2363e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (NULL); 237412b91889d9a1ae477e8b6907d0b9a76e78a6c91Behdad Esfahbod } 2383e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (final_reordering); 23985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_NUM_FEATURES; i++) { 24085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); 24185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 242b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 243b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 244693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 24516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodoverride_features_indic (hb_ot_shape_planner_t *plan) 246d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod{ 247af92b4cc90e4184d5bdd8037c551ed482700114fBehdad Esfahbod /* Uniscribe does not apply 'kern'. */ 248af92b4cc90e4184d5bdd8037c551ed482700114fBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 24916c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true); 2506b389ddc3623d042ded4731f4d62dc354002fdd0Behdad Esfahbod 2516b389ddc3623d042ded4731f4d62dc354002fdd0Behdad Esfahbod plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true); 252d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod} 253d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod 254867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 25585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodstruct would_substitute_feature_t 256a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 25785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag) 258a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 259a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_stage_lookups (0/*GSUB*/, 260a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_feature_stage (0/*GSUB*/, feature_tag), 261a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod &lookups, &count); 262a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 263a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 264a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod inline bool would_substitute (hb_codepoint_t *glyphs, 265a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int glyphs_count, 266b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod bool zero_context, 267a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_face_t *face) const 268a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 269a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 270362a990b2246f5448ecb9d600761f710aea7d42dBehdad Esfahbod if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) 271a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return true; 272a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return false; 273a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 274a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 275a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod private: 276a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const hb_ot_map_t::lookup_map_t *lookups; 277a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int count; 278a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 279a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 280a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstruct indic_shape_plan_t 281a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 28285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod ASSERT_POD (); 283914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 284914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const 285914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 286914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod hb_codepoint_t glyph = virama_glyph; 287914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (unlikely (virama_glyph == (hb_codepoint_t) -1)) 288914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 28911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!config->virama || !font->get_glyph (config->virama, 0, &glyph)) 290914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod glyph = 0; 291914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Technically speaking, the spec says we should apply 'locl' to virama too. 292914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * Maybe one day... */ 293914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 294914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Our get_glyph() function needs a font, so we can't get the virama glyph 295914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */ 296914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph; 297914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 298914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 299914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod *pglyph = glyph; 300914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod return glyph != 0; 301914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 30285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 30311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod const indic_config_t *config; 30485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 30585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod bool is_old_spec; 30685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_codepoint_t virama_glyph; 30785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 308f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod would_substitute_feature_t rphf; 30985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pref; 31085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t blwf; 31185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pstf; 31285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 31385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_mask_t mask_array[INDIC_NUM_FEATURES]; 314a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 315a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 316a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void * 317a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_create_indic (const hb_ot_shape_plan_t *plan) 318a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 31985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t)); 32085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (unlikely (!indic_plan)) 321a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return NULL; 322a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 32311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[0]; 32411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++) 32511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (plan->props.script == indic_configs[i].script) { 32611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[i]; 32711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 32885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 32911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 330851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2'); 33111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->virama_glyph = (hb_codepoint_t) -1; 33285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 333f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f')); 33485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f')); 33585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f')); 33685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f')); 33785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 33885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) 33985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->mask_array[i] = indic_features[i].is_global ? 0 : plan->map.get_1_mask (indic_features[i].tag); 340a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 34185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod return indic_plan; 342a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 343a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 344a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void 345a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_destroy_indic (void *data) 346a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 347a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod free (data); 348a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 349a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 350a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic indic_position_t 351a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodconsonant_position_from_face (const indic_shape_plan_t *indic_plan, 352a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_codepoint_t *glyphs, unsigned int glyphs_len, 353a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_face_t *face) 354a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 355b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod bool zero_context = indic_plan->is_old_spec ? false : true; 356b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C; 357b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->blwf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C; 358b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->pstf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_POST_C; 359a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return POS_BASE_C; 360a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 361a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 362a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 363166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodenum syllable_type_t { 364166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod consonant_syllable, 365166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod vowel_syllable, 366166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod standalone_cluster, 367166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod broken_cluster, 368166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod non_indic_cluster, 369166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod}; 370166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 371166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod#include "hb-ot-shape-complex-indic-machine.hh" 372166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 373166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 374693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 37516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodsetup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, 37616c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_buffer_t *buffer, 37716c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_font_t *font HB_UNUSED) 37824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 37924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); 38024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); 38124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 38224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod /* We cannot setup masks here. We save information about characters 38324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod * and setup masks later on in a pause-callback. */ 38424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 38524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod unsigned int count = buffer->len; 38624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 38724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod set_indic_properties (buffer->info[i]); 38824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 38924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 390166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 391166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, 392166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font HB_UNUSED, 393166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer) 394166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod{ 395166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod find_syllables (buffer); 396166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod} 397166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 39824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic int 39924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodcompare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 40024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 40124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int a = pa->indic_position(); 40224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int b = pb->indic_position(); 40324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 40424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod return a < b ? -1 : a == b ? 0 : +1; 40524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 40624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 40724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 40824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 40924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic void 4108bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodupdate_consonant_positions (const hb_ot_shape_plan_t *plan, 41185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 41285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer) 4138ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod{ 414a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 4158ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 416a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int consonant_pos = indic_plan->is_old_spec ? 0 : 1; 4178ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_codepoint_t glyphs[2]; 418914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->get_virama_glyph (font, &glyphs[1 - consonant_pos])) 4198ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod { 4208ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_face_t *face = font->face; 4218ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod unsigned int count = buffer->len; 4228ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 4238ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod if (buffer->info[i].indic_position() == POS_BASE_C) { 42424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod glyphs[consonant_pos] = buffer->info[i].codepoint; 425a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, 2, face); 4268ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 4278ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 4288ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod} 4298ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 430867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 4317ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod/* Rules from: 4327ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ 4337ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod 434743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 435f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbodinitial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, 436f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 437f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_buffer_t *buffer, 438ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 439743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 440914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 441ee58f3bc75d2d071a71b94063bf12205a5871acbBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 442743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 443617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod 444743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 1. Find base consonant: 445743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 446743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The shaping engine finds the base consonant of the syllable, using the 447743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following algorithm: starting from the end of the syllable, move backwards 448743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * until a consonant is found that does not have a below-base or post-base 449743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * form (post-base forms have to follow below-base forms), or that is not a 450743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * pre-base reordering Ra, or arrive at the first consonant. The consonant 451743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * stopped at will be the base. 452743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 453743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o If the syllable starts with Ra + Halant (in a script that has Reph) 454743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 455743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * base consonants. 456743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 457743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 4585e72071062c015237b79fbd0521341a63166a204Behdad Esfahbod unsigned int base = end; 45976b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod bool has_reph = false; 460743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 46176b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod { 462617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 463617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 464617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * base consonants. */ 465617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod unsigned int limit = start; 46685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[RPHF] && 467617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod start + 3 <= end && 4688b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod ( 46911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || 47011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ) 4713285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod )) 472617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod { 473f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod /* See if it matches the 'rphf' feature. */ 474f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoint}; 475f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face)) 476f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod { 477f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit += 2; 478f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 479f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit++; 480f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod base = start; 481f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod has_reph = true; 482f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod } 4838b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha) 4848b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod { 4858b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod limit += 1; 4868b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 4878b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod limit++; 4888b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod base = start; 4898b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod has_reph = true; 4908b217f5ac54aa0dcbba2dd6d59aa89dde33e56c2Behdad Esfahbod } 49176b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod 49223b0e9d7dc801e11640979af3c2b00649a519bb1Behdad Esfahbod switch (indic_plan->config->base_pos) 4935d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 494d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod default: 495d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod assert (false); 496d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod /* fallthrough */ 497d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod 49811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_LAST: 49911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 50011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> starting from the end of the syllable, move backwards */ 50111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int i = end; 50211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool seen_below = false; 50311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod do { 50411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod i--; 50511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> until a consonant is found */ 50611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i])) 5075d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 50811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> that does not have a below-base or post-base form 50911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * (post-base forms have to follow below-base forms), */ 51011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() != POS_BELOW_C && 51111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (info[i].indic_position() != POS_POST_C || seen_below)) 51211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 51311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 51411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 51511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 51611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() == POS_BELOW_C) 51711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod seen_below = true; 51811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 51911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or that is not a pre-base reordering Ra, 52011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 52111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * IMPLEMENTATION NOTES: 52211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 52311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Our pre-base reordering Ra's are marked POS_BELOW, so will be skipped 52411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * by the logic above already. 52511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 52611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 52711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or arrive at the first consonant. The consonant stopped at will 52811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * be the base. */ 5295d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod base = i; 5305d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 53111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 53211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 53311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* A ZWJ after a Halant stops the base search, and requests an explicit 53411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * half form. 53511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * A ZWJ before a Halant, requests a subjoined form instead, and hence 53611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * search continues. This is particularly important for Bengali 537c4be9917438c45b972ec76dc68409014110f0837Behdad Esfahbod * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */ 53811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (start < i && 53911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_category() == OT_ZWJ && 54011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i - 1].indic_category() == OT_H) 54111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 54211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 54311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } while (i > limit); 54411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 54511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 5465d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 54711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_FIRST: 54811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 54911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* In scripts without half forms (eg. Khmer), the first consonant is always the base. */ 5505d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 55111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!has_reph) 55211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = limit; 55334c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 55411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Find the last base consonant that is not blocked by ZWJ. If there is 55511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * a ZWJ right before a base consonant, that would request a subjoined form. */ 55611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = limit; i < end; i++) 55711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 55811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 55911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (limit < i && info[i - 1].indic_category() == OT_ZWJ) 56011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 56111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 56211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 56311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 56434c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 56511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Mark all subsequent consonants as below. */ 56611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 56711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 56811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_position() = POS_BELOW_C; 56911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 57011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 5715d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 572743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 573617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 574617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 5752278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * base consonants. 5762278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * 5772278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ 5789621e0ba294c9cc6d458bbf632e63e92fda71e10Behdad Esfahbod if (has_reph && base == start && limit - base <= 2) { 579617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* Have no other consonant, so Reph is not formed and Ra becomes base. */ 580617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = false; 581617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod } 5825e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod } 5832278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod 5843d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 585743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 2. Decompose and reorder Matras: 586743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 587743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Each matra and any syllable modifier sign in the cluster are moved to the 588743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * appropriate position relative to the consonant(s) in the cluster. The 589743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * shaping engine decomposes two- or three-part matras into their constituent 590743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * parts before any repositioning. Matra characters are classified by which 591743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * consonant in a conjunct they have affinity for and are reordered to the 592743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following positions: 593743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 594743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o Before first half form in the syllable 595743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After subjoined consonants 596743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After post-form consonant 597743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After main consonant (for above marks) 598743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 599743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 600743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 601743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The normalize() routine has already decomposed matras for us, so we don't 602743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * need to worry about that. 603743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 604743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 605743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 606743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 3. Reorder marks to canonical order: 607743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 608743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Adjacent nukta and halant or nukta and vedic sign are always repositioned 609743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * if necessary, so that the nukta is first. 610743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 611743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 612743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 613743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * We don't need to do this: the normalize() routine already did this for us. 614743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 615743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 616743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 61745d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod /* Reorder characters */ 61845d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 6193c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 620900cf3d449bf36d4f8b1474590cae925fef48fc8Behdad Esfahbod info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position()); 62155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 622075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 623075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].indic_position() = POS_BASE_C; 62445d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 62555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod /* Mark final consonants. A final consonant is one appearing after a matra, 62655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod * like in Khmer. */ 62755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 62855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (info[i].indic_category() == OT_M) { 62955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int j = i + 1; j < end; j++) 63055f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (is_consonant (info[j])) { 63155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod info[j].indic_position() = POS_FINAL_C; 63255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 63355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 63455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 63555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 63655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 637fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod /* Handle beginning Ra */ 6385e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod if (has_reph) 639dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() = POS_RA_TO_BECOME_REPH; 640fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod 641f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* For old-style Indic script tags, move the first post-base Halant after 642ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod * last consonant. Only do this if there is *not* a Halant after last 643ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod * consonant. Otherwise it becomes messy. */ 644914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->is_old_spec) { 6453c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 646f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (info[i].indic_category() == OT_H) { 647f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod unsigned int j; 648f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod for (j = end - 1; j > i; j--) 649ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod if (is_consonant (info[j]) || info[j].indic_category() == OT_H) 650f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 651ecd454b3cd75050e0c95e1d2aa55744559338ec8Behdad Esfahbod if (info[j].indic_category() != OT_H && j > i) { 652f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* Move Halant to after last consonant. */ 653f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod hb_glyph_info_t t = info[i]; 654f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); 655f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod info[j] = t; 656f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 657f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 658f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 659f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 660f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod 66181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* Attach misc marks to previous char to move with them. */ 662ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 66381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod indic_position_t last_pos = POS_START; 66481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod for (unsigned int i = start; i < end; i++) 66581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 66681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS))) 66781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 66881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() = last_pos; 669dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod if (unlikely (info[i].indic_category() == OT_H && 67081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() == POS_PRE_M)) 67181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 67281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* 67381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * Uniscribe doesn't move the Halant with Left Matra. 67481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * TEST: U+092B,U+093F,U+094DE 675dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We follow. This is important for the Sinhala 676dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA 677dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * where U+0DD9 is a left matra and U+0DCA is the virama. 678dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We don't want to move the virama with the left matra. 679dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * TEST: U+0D9A,U+0DDA 68081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod */ 681ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod for (unsigned int j = i; j > start; j--) 6826a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[j - 1].indic_position() != POS_PRE_M) { 683ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod info[i].indic_position() = info[j - 1].indic_position(); 684ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod break; 685ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 68681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 68781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } else if (info[i].indic_position() != POS_SMVD) { 68881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod last_pos = (indic_position_t) info[i].indic_position(); 689ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 69081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 691ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 69274ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod /* Re-attach ZWJ, ZWNJ, and halant to next char, for after-base consonants. */ 69374ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod { 69474ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod unsigned int last_halant = end; 69574ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 696deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (is_halant_or_coeng (info[i])) 69774ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod last_halant = i; 69874ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod else if (is_consonant (info[i])) { 69974ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int j = last_halant; j < i; j++) 70081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if (info[j].indic_position() != POS_SMVD) 70181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[j].indic_position() = info[i].indic_position(); 70274ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 70374ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 70445d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 705a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod { 7067b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod /* Things are out-of-control for post base positions, they may shuffle 7077b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * around like crazy, so merge clusters. For pre-base stuff, we handle 7087b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * cluster issues in final reordering. */ 7097b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod buffer->merge_clusters (base, end); 710a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Sit tight, rock 'n roll! */ 711d3637edb248162970e202e9d0671540274192844Behdad Esfahbod hb_bubble_sort (info + start, end - start, compare_indic_order); 712a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Find base again */ 713a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = end; 7143c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < end; i++) 715a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod if (info[i].indic_position() == POS_BASE_C) { 716a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = i; 717a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod break; 718a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 719a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 72045d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 721743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Setup masks now */ 722743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 723281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod { 724281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod hb_mask_t mask; 725281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod 726dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* Reph */ 727668c6046c1b3af3bd316bda0cc8636f2a5e8df42Behdad Esfahbod for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) 72885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[RPHF]; 729dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 730281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Pre-base */ 73185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[HALF]; 7323c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 733281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 734281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Base */ 73520b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = 0; 736075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 737075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].mask |= mask; 738281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Post-base */ 73985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF]; 7403c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 741281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 742281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod } 7439da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 74485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 2 < end) 74517d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod { 746771a8f50289e8fa458cfc3cd84f73a380ce98077Behdad Esfahbod /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ 74756be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod for (unsigned int i = base + 1; i + 1 < end; i++) { 74856be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint}; 74956be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face)) 7508e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 75185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 75285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 7530201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 7540201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod /* Mark the subsequent stuff with 'cfar'. Used in Khmer. 7550201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * Read the feature spec. 7560201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * This allows distinguishing the following cases with MS Khmer fonts: 7570201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+179A,U+17D2,U+1782 7580201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+1782,U+17D2,U+179A 7590201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod */ 7600201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod for (; i < end; i++) 76185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[CFAR]; 7620201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 7638e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 7648e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 76556be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod } 76617d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod } 76717d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod 7689da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod /* Apply ZWJ/ZWNJ effects */ 7693c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start + 1; i < end; i++) 7709da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod if (is_joiner (info[i])) { 7719da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod bool non_joiner = info[i].indic_category() == OT_ZWNJ; 7726b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod unsigned int j = i; 7739da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 7749da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod do { 7759da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod j--; 7766b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 77720b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWJ disables CJCT, however, it's mere presence is enough 77820b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod * to disable ligation. No explicit action needed. */ 77920b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod 78020b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWNJ disables HALF. */ 7816b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod if (non_joiner) 78285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[j].mask &= ~indic_plan->mask_array[HALF]; 7836b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 7849da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } while (j > start && !is_consonant (info[j])); 7859da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } 786743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 787743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 788743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 789743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7908bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan, 791f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 7929f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 793ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 794743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 795c5306b6861cfaa50af40e8ceb058791fa06d7981Behdad Esfahbod /* We made the vowels look like consonants. So let's call the consonant logic! */ 796f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 797743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 798743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 799743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 8008bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, 801f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 8029f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 803ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 804743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 80518c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain. 80618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Only if not in compatibility mode that is... */ 80718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 808a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 80918c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod { 81018c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* For dotted-circle, this is what Uniscribe does: 81118c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * If dotted-circle is the last glyph, it just does nothing. 81218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Ie. It doesn't form Reph. */ 81318c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) 81418c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod return; 81518c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod } 81618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 817f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 818743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 819743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 820743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 821b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodinitial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan, 822f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 823b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer, 824b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int start, unsigned int end) 825b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 826b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod /* We already inserted dotted-circles, so just call the standalone_cluster. */ 827f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_standalone_cluster (plan, face, buffer, start, end); 828b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 829b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 830b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 831327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 832f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face HB_UNUSED, 833327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 834327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 835743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 836743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 837743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 838743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 839743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 840327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 841743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 842327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_syllable (const hb_ot_shape_plan_t *plan, 843f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 844327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer, 845327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start, unsigned int end) 846327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod{ 847327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); 848327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod switch (syllable_type) { 849f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; 850f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return; 851f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return; 852f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; 853f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return; 854327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 855327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod} 856327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 857166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic inline void 8580beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbodinsert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, 859b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_font_t *font, 860b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer) 861b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 862166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Note: This loop is extra overhead, but should not be measurable. */ 863166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod bool has_broken_syllables = false; 864166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod unsigned int count = buffer->len; 865166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod for (unsigned int i = 0; i < count; i++) 866166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) { 867166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod has_broken_syllables = true; 868166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod break; 869166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod } 870166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if (likely (!has_broken_syllables)) 871166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod return; 872166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 873166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 874b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_codepoint_t dottedcircle_glyph; 875b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) 876b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return; 877b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 878f41dc2d35b23220d59d38990bb66f1cbd66a55b3Behdad Esfahbod hb_glyph_info_t dottedcircle = {0}; 879b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = 0x25CC; 880b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod set_indic_properties (dottedcircle); 881b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = dottedcircle_glyph; 882b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 883b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->clear_output (); 884b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 885b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->idx = 0; 886b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int last_syllable = 0; 887b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod while (buffer->idx < buffer->len) 888b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 889b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int syllable = buffer->cur().syllable(); 890b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); 891b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) 892b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 893596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod last_syllable = syllable; 894596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 895b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_glyph_info_t info = dottedcircle; 896b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.cluster = buffer->cur().cluster; 897b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.mask = buffer->cur().mask; 898b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.syllable() = buffer->cur().syllable(); 899596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 900596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod /* Insert dottedcircle after possible Repha. */ 901596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod while (buffer->idx < buffer->len && 902596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod last_syllable == buffer->cur().syllable() && 903596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->cur().indic_category() == OT_Repha) 904596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->next_glyph (); 905596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod 906b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->output_info (info); 907b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 908596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod else 909596740db04e7c1dadae0d8be6e401089fcaffc2dBehdad Esfahbod buffer->next_glyph (); 910b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 911b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 912b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->swap_buffers (); 913b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 914b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 915b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 9168bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 91724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod hb_font_t *font, 9183e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 919743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 92085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod update_consonant_positions (plan, font, buffer); 921166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod insert_dotted_circles (plan, font, buffer); 922327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 923327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 924b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int count = buffer->len; 925b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (!count)) return; 926327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last = 0; 927327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 928327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 929327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (last_syllable != info[i].syllable()) { 930f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, i); 931327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last = i; 932327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last_syllable = info[last].syllable(); 933327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 934f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, count); 935b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 936b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 937743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 93885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodfinal_reordering_syllable (const hb_ot_shape_plan_t *plan, 93985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer, 940ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 941743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 94285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 9434ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 9444ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 945e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod /* 4. Final reordering: 946e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 947e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * After the localized forms and basic shaping forms GSUB features have been 948e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * applied (see below), the shaping engine performs some final glyph 949e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * reordering before applying all the remaining font features to the entire 950e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * cluster. 9514ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 9524ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 9534ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* Find base again */ 9545f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod unsigned int base; 9555f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod for (base = start; base < end; base++) 9565f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (info[base].indic_position() >= POS_BASE_C) { 9575f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (start < base && info[base].indic_position() > POS_BASE_C) 9585f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod base--; 9595f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod break; 9605f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod } 9614ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 9624705a7026900e51f6430f03a73c87f2df035df92Behdad Esfahbod 9634ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder matras: 964e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 965e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base matra character had been reordered before applying basic 966e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * features, the glyph can be moved closer to the main consonant based on 967e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * whether half-forms had been formed. Actual position for the matra is 968e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * defined as “after last standalone halant glyph, after initial matra 969e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * position and before the main consonant”. If ZWJ or ZWNJ follow this 970e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * halant, position is moved after it. 9714ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 9724ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 97365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ 9749d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 97565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we lost track of base, alas, position before last thingy. */ 97665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod unsigned int new_pos = base == end ? base - 2 : base - 1; 97765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 97827bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 97927bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 98027bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * We want to position matra after them. 98165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod */ 98227bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 983e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod { 98465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod while (new_pos > start && 98565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng))))) 98665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos--; 98765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 98865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we found no Halant we are done. 98965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * Otherwise only proceed if the Halant does 99065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * not belong to the Matra itself! */ 99165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (is_halant_or_coeng (info[new_pos]) && 99265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod info[new_pos].indic_position() != POS_PRE_M) 99365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 99465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 99565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) 99665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos++; 99765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 99865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod else 99965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos = start; /* No move. */ 100065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 10019d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod 100227bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M) 100365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 10049d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* Now go see if there's actually any matras... */ 1005921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod for (unsigned int i = new_pos; i > start; i--) 10066a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[i - 1].indic_position () == POS_PRE_M) 10079d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 10081a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod unsigned int old_pos = i - 1; 10091a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 10101a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0])); 10111a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod info[new_pos] = tmp; 1012921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod new_pos--; 10139d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 10142cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (new_pos, MIN (end, base + 1)); 1015abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } else { 1016e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod for (unsigned int i = start; i < base; i++) 1017abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod if (info[i].indic_position () == POS_PRE_M) { 10182cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (i, MIN (end, base + 1)); 1019abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod break; 1020abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } 10219d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 10224ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod } 10234ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 10244ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 10254ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder reph: 1026e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1027e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Reph’s original position is always at the beginning of the syllable, 1028e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * (i.e. it is not reordered at the character reordering stage). However, 1029e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * it will be reordered according to the basic-forms shaping results. 1030e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Possible positions for reph, depending on the script, are; after main, 1031e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * before post-base consonant forms, and after post-base consonant forms. 1032dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 1033dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1034dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* If there's anything after the Ra that has the REPH pos, it ought to be halant. 1035dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Which means that the font has failed to ligate the Reph. In which case, we 1036dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * shouldn't move. */ 1037dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod if (start + 1 < end && 1038dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() == POS_RA_TO_BECOME_REPH && 1039dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH) 1040dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod { 104111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int new_reph_pos; 104211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos = indic_plan->config->reph_pos; 104311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 104411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* XXX Figure out old behavior too */ 104502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1046dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* 1. If reph should be positioned after post-base consonant forms, 1047dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to step 5. 104802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 104911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_POST) 105002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 10519d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_step_5; 105202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 105302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 105402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 2. If the reph repositioning class is not after post-base: target 1055dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is after the first explicit halant glyph between the 1056dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-reph consonant and last main consonant. If ZWJ or ZWNJ 1057dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * are following this halant, position is moved after it. If such 1058dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is found, this is the target position. Otherwise, 1059dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to the next step. 1060dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * 1061dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Note: in old-implementation fonts, where classifications were 1062dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * fixed in shaping engine, there was no case where reph position 1063dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * will be found on this step. 106402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 106502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 106602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = start + 1; 1067deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 106802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 106902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1070deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 107102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 107202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 107302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 107402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 107502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 107602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 107702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 107802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 3. If reph should be repositioned after the main consonant: find the 1079dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first consonant not ligated with main, or find the first 1080dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant that is not a potential pre-base reordering Ra. 108102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 108211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_MAIN) 108302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1084b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos = base; 1085b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod /* XXX Skip potential pre-base reordering Ra. */ 108634ae336f3fae93ef9372881d545c817bce383041Behdad Esfahbod while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN) 1087b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos++; 1088b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod if (new_reph_pos < end) 1089b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod goto reph_move; 109002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 109102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 109202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 4. If reph should be positioned before post-base consonant, find 1093dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-base classified consonant not ligated with main. If no 1094dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant is found, the target position should be before the 1095dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first matra, syllable modifier sign or vedic sign. 109602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 10979d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* This is our take on what step 4 is trying to say (and failing, BADLY). */ 109811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_SUB) 109902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 11009d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos = base; 11019d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod while (new_reph_pos < end && 1102be8b9f5f715f6fb36b98bd33c3303f79cc068f8aBehdad Esfahbod !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD)))) 11039d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos++; 11049d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (new_reph_pos < end) 11059d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_move; 110602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 110702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 110802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 5. If no consonant is found in steps 3 or 4, move reph to a position 1109dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * immediately before the first post-base matra, syllable modifier 1110dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * sign or vedic sign that has a reordering class after the intended 1111dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * reph position. For example, if the reordering position for reph 1112dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * is post-main, it will skip above-base matras that also have a 1113dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * post-main position. 1114dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 111502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_step_5: 111602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1117d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* Copied from step 2. */ 1118d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos = start + 1; 1119d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 1120d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1121d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod 1122d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 1123d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 1124d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 1125d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1126d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod goto reph_move; 1127d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod } 112802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1129dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 113002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 6. Otherwise, reorder reph to the end of the syllable. 113102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 113202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 113302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = end - 1; 113402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD) 113502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 113602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1137892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod /* 1138892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * If the Reph is to be ending up after a Matra,Halant sequence, 1139892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * position it before that Halant so it can interact with the Matra. 1140892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * However, if it's a plain Consonant,Halant we shouldn't do that. 1141892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * Uniscribe doesn't do this. 1142892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * TEST: U+0930,U+094D,U+0915,U+094B,U+094D 1143892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod */ 1144a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (!indic_options ().uniscribe_bug_compatible && 1145deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod unlikely (is_halant_or_coeng (info[new_reph_pos]))) { 114602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod for (unsigned int i = base + 1; i < new_reph_pos; i++) 114702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (info[i].indic_category() == OT_M) { 114802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Ok, got it. */ 114902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 115002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 115102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 115202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 11538df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod } 11548df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod 115502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_move: 115602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1157e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod /* Yay, one big cluster! Merge before moving. */ 1158e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 1159e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod 116002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Move */ 116102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod hb_glyph_info_t reph = info[start]; 116202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0])); 116302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod info[new_reph_pos] = reph; 116402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1165dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod } 1166dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1167dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1168dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* o Reorder pre-base reordering consonants: 1169e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1170e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base reordering consonant is found, reorder it according to 1171e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * the following rules: 1172e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod */ 1173e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 117485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ 117546e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod { 11768e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 117785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) 117878818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod { 11798e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 1. Only reorder a glyph produced by substitution during application 11808e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * of the <pref> feature. (Note that a font may shape a Ra consonant with 11818e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * the feature generally but block it in certain contexts.) 11828e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 118385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (i + 1 == end || (info[i + 1].mask & indic_plan->mask_array[PREF]) == 0) 11848e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 11858e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 11868e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 2. Try to find a target position the same way as for pre-base matra. 11878e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * If it is found, reorder pre-base consonant glyph. 11888e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 11898e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 3. If position is not found, reorder immediately before main 11908e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * consonant. 11918e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 11928e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 11938e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int new_pos = base; 119488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 119588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 119688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * We want to position matra after them. 119788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod */ 119888d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1199d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 120088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod while (new_pos > start && 120188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS))) 120288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 120388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod 120488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* In Khmer coeng model, a V,Ra can go *after* matras. If it goes after a 120588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * split matra, it should be reordered to *before* the left part of such matra. */ 120688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) 120788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 120888d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod unsigned int old_pos = i; 120988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod for (unsigned int i = base + 1; i < old_pos; i++) 121088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (info[i].indic_category() == OT_M) 121188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 121288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 121388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod break; 121488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 121588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 1216d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1217d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod 1218deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) 12198e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 12208e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if (new_pos < end && is_joiner (info[new_pos])) 12218e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos++; 12228e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 12238e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 12248e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int old_pos = i; 1225e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (new_pos, old_pos + 1); 12268e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 12278e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0])); 12288e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[new_pos] = tmp; 12298e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 12308e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 12318e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 12328e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 123378818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod } 123446e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod } 1235eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1236eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1237a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod /* Apply 'init' to the Left Matra if it's a word start. */ 12386a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[start].indic_position () == POS_PRE_M && 1239a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod (!start || 1240eace47b173807d94b29a6490d0bc3c9f8f6168d1Behdad Esfahbod !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & 12412c372b80f6befad69e216e3f218b38640b8cc044Behdad Esfahbod FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))) 124285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[start].mask |= indic_plan->mask_array[INIT]; 1243a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod 1244eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 12458ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod /* 12468ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod * Finish off the clusters and go home! 12478ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod */ 1248decf6ffca475fe01ff3151b7641f629f031137d2Behdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 1249ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 125030c3d5e9fc61b49c2c6ad4e744300edd6f3e0261Behdad Esfahbod /* Uniscribe merges the entire cluster. 125121d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This means, half forms are submerged into the main consonants cluster. 125221d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This is unnecessary, and makes cursor positioning harder, but that's what 125321d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * Uniscribe does. */ 1254e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 125521d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod } 1256ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod} 1257e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1258e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1259ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbodstatic void 12608bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 12610beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod hb_font_t *font HB_UNUSED, 12623e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1263ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod{ 1264ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int count = buffer->len; 1265327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (unlikely (!count)) return; 1266ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod 1267ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1268ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int last = 0; 1269cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1270ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1271cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod if (last_syllable != info[i].syllable()) { 127285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, i); 1273ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod last = i; 1274cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod last_syllable = info[last].syllable(); 1275ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod } 127685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, count); 1277e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 127880cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod /* Zero syllables now... */ 127980cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 128080cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod info[i].syllable() = 0; 128180cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod 1282743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); 1283743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); 1284743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1285743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1286743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1287b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic hb_ot_shape_normalization_mode_t 12880beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbodnormalization_preference_indic (const hb_segment_properties_t *props HB_UNUSED) 1289b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1290b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT; 1291b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1292b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1293eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1294eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahboddecompose_indic (const hb_ot_shape_normalize_context_t *c, 12950736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t ab, 12960736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *a, 12970736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *b) 12980736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 12990736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod switch (ab) 13000736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 13010736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Don't decompose these. */ 13020736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0931 : return false; 13030736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0B94 : return false; 13040736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 13050736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 13060736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* 13070736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod * Decompose split matras that don't have Unicode decompositions. 13080736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod */ 13090736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 13100736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true; 13110736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true; 13120736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true; 13130736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true; 13140736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true; 13150736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true; 13160736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true; 13170736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1925 : *a = 0x1920; *b= 0x1923; return true; 13180736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1926 : *a = 0x1920; *b= 0x1924; return true; 13190736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true; 13200736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1112E : *a = 0x11127; *b= 0x11131; return true; 13210736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1112F : *a = 0x11127; *b= 0x11132; return true; 13220736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#if 0 13230736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* This one has no decomposition in Unicode, but needs no decomposition either. */ 13240736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* case 0x0AC9 : return false; */ 13250736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0B57 : *a = no decomp, -> RIGHT; return true; 13260736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1C29 : *a = no decomp, -> LEFT; return true; 13270736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0xA9C0 : *a = no decomp, -> RIGHT; return true; 13280736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x111BF : *a = no decomp, -> ABOVE; return true; 13290736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#endif 13300736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 13310736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 133243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod if ((ab == 0x0DDA || hb_in_range<hb_codepoint_t> (ab, 0x0DDC, 0x0DDE))) 13330736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 133443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* 133543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Sinhala split matras... Let the fun begin. 133643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 133743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * These four characters have Unicode decompositions. However, Uniscribe 133843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * decomposes them "Khmer-style", that is, it uses the character itself to 133943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * get the second half. The first half of all four decompositions is always 134043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * U+0DD9. 134143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 134243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are 134343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * broken with Uniscribe. But we need to support them. As such, we only 134443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * do the Uniscribe-style decomposition if the character is transformed into 134543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * its "sec.half" form by the 'pstf' feature. Otherwise, we fall back to 134643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Unicode decomposition. 134743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 134843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Note that we can't unconditionally use Unicode decomposition. That would 134943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * break some other fonts, that are designed to work with Uniscribe, and 135043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * don't have positioning features for the Unicode-style decomposition. 135143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 135243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Argh... 1353b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * 1354b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * The Uniscribe behavior is now documented in the newly published Sinhala 1355b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * spec in 2012: 1356b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * 1357b71b0bd9ee64feadd7289e195bc58f6361ce707aBehdad Esfahbod * http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shaping 135843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod */ 135943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 136043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data; 136143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 136243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod hb_codepoint_t glyph; 136343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 136443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible || 136543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod (c->font->get_glyph (ab, 0, &glyph) && 136643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face))) 136743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod { 136843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* Ok, safe to use Uniscribe-style decomposition. */ 136943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *a = 0x0DD9; 137043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *b = ab; 137143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod return true; 137243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod } 13730736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 13740736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1375eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->decompose (ab, a, b); 13760736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 13770736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1378eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1379eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodcompose_indic (const hb_ot_shape_normalize_context_t *c, 13800736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t a, 13810736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t b, 13820736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *ab) 13830736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 13840736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Avoid recomposing split matras. */ 1385eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a))) 13860736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod return false; 13870736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 13880736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Composition-exclusion exceptions that we want to recompose. */ 13890736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; } 13900736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1391eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->compose (a, b, ab); 13920736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 13930736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 13940736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1395693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = 1396693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{ 1397693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod "indic", 1398693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod collect_features_indic, 1399693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod override_features_indic, 1400a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_create_indic, 1401a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_destroy_indic, 14029f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod NULL, /* preprocess_text */ 1403b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod normalization_preference_indic, 14040736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod decompose_indic, 14050736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod compose_indic, 1406693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod setup_masks_indic, 1407568000274c8edb5f41bc4f876ce21fcc8bdaeed8Behdad Esfahbod HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, 1408865745b5b87236651f5663cae3461db9cb505eedBehdad Esfahbod false, /* fallback_position */ 1409693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod}; 1410