hb-ot-shape-complex-indic.cc revision 167b625d988b74572d6b2f646c285b666b650d49
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 60a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodinline 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 2068bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 207afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 2083e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 209f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbodstatic void 2108bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 211afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 2123e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 213b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 214693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 21516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodcollect_features_indic (hb_ot_shape_planner_t *plan) 216b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 21716c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_ot_map_builder_t *map = &plan->map; 21816c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod 219f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_bool_feature (HB_TAG('l','o','c','l')); 220a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod /* The Indic specs do not require ccmp, but we apply it here since if 221a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod * there is a use of it, it's typically at the beginning. */ 222f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_bool_feature (HB_TAG('c','c','m','p')); 223f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 224f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 22585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod unsigned int i = 0; 22685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_gsub_pause (initial_reordering); 22785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_BASIC_FEATURES; i++) { 22885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); 2293e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (NULL); 230412b91889d9a1ae477e8b6907d0b9a76e78a6c91Behdad Esfahbod } 2313e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (final_reordering); 23285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_NUM_FEATURES; i++) { 23385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); 23485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 235b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 236b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 237693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 23816c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodoverride_features_indic (hb_ot_shape_planner_t *plan) 239d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod{ 240af92b4cc90e4184d5bdd8037c551ed482700114fBehdad Esfahbod /* Uniscribe does not apply 'kern'. */ 241af92b4cc90e4184d5bdd8037c551ed482700114fBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 24216c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true); 243d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod} 244d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod 245867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 24685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodstruct would_substitute_feature_t 247a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 24885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag) 249a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 250a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_stage_lookups (0/*GSUB*/, 251a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_feature_stage (0/*GSUB*/, feature_tag), 252a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod &lookups, &count); 253a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 254a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 255a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod inline bool would_substitute (hb_codepoint_t *glyphs, 256a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int glyphs_count, 257a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_face_t *face) const 258a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 259a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 260a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod if (hb_ot_layout_would_substitute_lookup_fast (face, glyphs, glyphs_count, lookups[i].index)) 261a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return true; 262a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return false; 263a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 264a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 265a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod private: 266a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const hb_ot_map_t::lookup_map_t *lookups; 267a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int count; 268a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 269a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 270a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstruct indic_shape_plan_t 271a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 27285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod ASSERT_POD (); 273914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 274914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const 275914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 276914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod hb_codepoint_t glyph = virama_glyph; 277914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (unlikely (virama_glyph == (hb_codepoint_t) -1)) 278914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 27911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!config->virama || !font->get_glyph (config->virama, 0, &glyph)) 280914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod glyph = 0; 281914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Technically speaking, the spec says we should apply 'locl' to virama too. 282914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * Maybe one day... */ 283914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 284914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Our get_glyph() function needs a font, so we can't get the virama glyph 285914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */ 286914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph; 287914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 288914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 289914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod *pglyph = glyph; 290914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod return glyph != 0; 291914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 29285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 29311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod const indic_config_t *config; 29485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 29585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod bool is_old_spec; 29685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_codepoint_t virama_glyph; 29785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 29885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pref; 29985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t blwf; 30085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pstf; 30185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 30285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_mask_t mask_array[INDIC_NUM_FEATURES]; 303a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 304a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 305a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void * 306a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_create_indic (const hb_ot_shape_plan_t *plan) 307a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 30885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t)); 30985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (unlikely (!indic_plan)) 310a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return NULL; 311a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 31211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[0]; 31311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++) 31411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (plan->props.script == indic_configs[i].script) { 31511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[i]; 31611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 31785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 31811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 31911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.get_chosen_script (0) & 0x000000FF) != '2'); 32011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->virama_glyph = (hb_codepoint_t) -1; 32185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 32285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f')); 32385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f')); 32485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f')); 32585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 32685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) 32785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->mask_array[i] = indic_features[i].is_global ? 0 : plan->map.get_1_mask (indic_features[i].tag); 328a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 32985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod return indic_plan; 330a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 331a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 332a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void 333a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_destroy_indic (void *data) 334a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 335a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod free (data); 336a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 337a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 338a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic indic_position_t 339a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodconsonant_position_from_face (const indic_shape_plan_t *indic_plan, 340a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_codepoint_t *glyphs, unsigned int glyphs_len, 341a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_face_t *face) 342a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 3438ba8042821e4581fe4e87419e58c823520441205Behdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, glyphs_len, face)) return POS_BELOW_C; 3448ba8042821e4581fe4e87419e58c823520441205Behdad Esfahbod if (indic_plan->blwf.would_substitute (glyphs, glyphs_len, face)) return POS_BELOW_C; 3458ba8042821e4581fe4e87419e58c823520441205Behdad Esfahbod if (indic_plan->pstf.would_substitute (glyphs, glyphs_len, face)) return POS_POST_C; 346a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return POS_BASE_C; 347a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 348a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 349a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 350693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 35116c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodsetup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, 35216c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_buffer_t *buffer, 35316c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_font_t *font HB_UNUSED) 35424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 35524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); 35624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); 35724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 35824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod /* We cannot setup masks here. We save information about characters 35924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod * and setup masks later on in a pause-callback. */ 36024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 36124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod unsigned int count = buffer->len; 36224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 36324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod set_indic_properties (buffer->info[i]); 36424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 36524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 36624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic int 36724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodcompare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 36824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 36924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int a = pa->indic_position(); 37024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int b = pb->indic_position(); 37124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 37224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod return a < b ? -1 : a == b ? 0 : +1; 37324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 37424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 37524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 37624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 37724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic void 3788bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodupdate_consonant_positions (const hb_ot_shape_plan_t *plan, 37985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 38085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer) 3818ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod{ 382a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 3838ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 384a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int consonant_pos = indic_plan->is_old_spec ? 0 : 1; 3858ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_codepoint_t glyphs[2]; 386914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->get_virama_glyph (font, &glyphs[1 - consonant_pos])) 3878ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod { 3888ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_face_t *face = font->face; 3898ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod unsigned int count = buffer->len; 3908ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 3918ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod if (buffer->info[i].indic_position() == POS_BASE_C) { 39224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod glyphs[consonant_pos] = buffer->info[i].codepoint; 393a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, 2, face); 3948ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 3958ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 3968ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod} 3978ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 398867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 3997ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod/* Rules from: 4007ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ 4017ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod 402743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 40385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodinitial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, 404ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 405743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 406914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 407ee58f3bc75d2d071a71b94063bf12205a5871acbBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 408743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 409617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod 410743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 1. Find base consonant: 411743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 412743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The shaping engine finds the base consonant of the syllable, using the 413743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following algorithm: starting from the end of the syllable, move backwards 414743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * until a consonant is found that does not have a below-base or post-base 415743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * form (post-base forms have to follow below-base forms), or that is not a 416743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * pre-base reordering Ra, or arrive at the first consonant. The consonant 417743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * stopped at will be the base. 418743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 419743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o If the syllable starts with Ra + Halant (in a script that has Reph) 420743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 421743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * base consonants. 422743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 423743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 4245e72071062c015237b79fbd0521341a63166a204Behdad Esfahbod unsigned int base = end; 42576b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod bool has_reph = false; 426743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 42776b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod { 428617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 429617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 430617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * base consonants. */ 431617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod unsigned int limit = start; 43285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[RPHF] && 433617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod start + 3 <= end && 434617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod info[start].indic_category() == OT_Ra && 435617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod info[start + 1].indic_category() == OT_H && 43611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (/* TODO Handle other Reph modes. */ 43711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || 43811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ) 4393285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod )) 440617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod { 441617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod limit += 2; 4423285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 4433285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod limit++; 444617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod base = start; 445617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = true; 446617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod }; 44776b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod 44811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod switch (indic_plan->config->base_pos == BASE_POS_LAST) 4495d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 45011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_LAST: 45111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 45211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> starting from the end of the syllable, move backwards */ 45311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int i = end; 45411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool seen_below = false; 45511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod do { 45611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod i--; 45711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> until a consonant is found */ 45811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i])) 4595d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 46011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> that does not have a below-base or post-base form 46111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * (post-base forms have to follow below-base forms), */ 46211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() != POS_BELOW_C && 46311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (info[i].indic_position() != POS_POST_C || seen_below)) 46411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 46511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 46611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 46711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 46811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() == POS_BELOW_C) 46911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod seen_below = true; 47011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 47111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or that is not a pre-base reordering Ra, 47211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 47311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * IMPLEMENTATION NOTES: 47411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 47511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Our pre-base reordering Ra's are marked POS_BELOW, so will be skipped 47611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * by the logic above already. 47711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 47811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 47911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or arrive at the first consonant. The consonant stopped at will 48011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * be the base. */ 4815d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod base = i; 4825d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 48311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 48411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 48511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* A ZWJ after a Halant stops the base search, and requests an explicit 48611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * half form. 48711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * A ZWJ before a Halant, requests a subjoined form instead, and hence 48811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * search continues. This is particularly important for Bengali 48911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * sequence Ra,H,Ya that shouls form Ya-Phalaa by subjoining Ya. */ 49011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (start < i && 49111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_category() == OT_ZWJ && 49211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i - 1].indic_category() == OT_H) 49311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 49411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 49511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } while (i > limit); 49611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 49711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 4985d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 49911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_FIRST: 50011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 50111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* In scripts without half forms (eg. Khmer), the first consonant is always the base. */ 5025d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 50311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!has_reph) 50411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = limit; 50534c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 50611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Find the last base consonant that is not blocked by ZWJ. If there is 50711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * a ZWJ right before a base consonant, that would request a subjoined form. */ 50811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = limit; i < end; i++) 50911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 51011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 51111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (limit < i && info[i - 1].indic_category() == OT_ZWJ) 51211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 51311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 51411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 51511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 51634c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 51711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Mark all subsequent consonants as below. */ 51811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 51911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 52011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_position() = POS_BELOW_C; 52111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 52211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 52311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 52411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod default: 52511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod abort (); 5265d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 527743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 528617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 529617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 5302278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * base consonants. 5312278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * 5322278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ 5332278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod if (has_reph && base == start && start + 2 == limit) { 534617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* Have no other consonant, so Reph is not formed and Ra becomes base. */ 535617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = false; 536617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod } 5375e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod } 5382278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod 53934c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod if (base < end) 54034c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod info[base].indic_position() = POS_BASE_C; 5413d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 5423d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 543743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 2. Decompose and reorder Matras: 544743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 545743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Each matra and any syllable modifier sign in the cluster are moved to the 546743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * appropriate position relative to the consonant(s) in the cluster. The 547743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * shaping engine decomposes two- or three-part matras into their constituent 548743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * parts before any repositioning. Matra characters are classified by which 549743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * consonant in a conjunct they have affinity for and are reordered to the 550743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following positions: 551743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 552743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o Before first half form in the syllable 553743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After subjoined consonants 554743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After post-form consonant 555743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After main consonant (for above marks) 556743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 557743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 558743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 559743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The normalize() routine has already decomposed matras for us, so we don't 560743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * need to worry about that. 561743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 562743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 563743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 564743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 3. Reorder marks to canonical order: 565743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 566743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Adjacent nukta and halant or nukta and vedic sign are always repositioned 567743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * if necessary, so that the nukta is first. 568743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 569743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 570743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 571743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * We don't need to do this: the normalize() routine already did this for us. 572743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 573743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 574743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 57545d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod /* Reorder characters */ 57645d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 5773c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 578900cf3d449bf36d4f8b1474590cae925fef48fc8Behdad Esfahbod info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position()); 57955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 580075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 581075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].indic_position() = POS_BASE_C; 58245d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 58355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod /* Mark final consonants. A final consonant is one appearing after a matra, 58455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod * like in Khmer. */ 58555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 58655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (info[i].indic_category() == OT_M) { 58755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int j = i + 1; j < end; j++) 58855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (is_consonant (info[j])) { 58955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod info[j].indic_position() = POS_FINAL_C; 59055f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 59155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 59255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 59355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 59455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 595fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod /* Handle beginning Ra */ 5965e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod if (has_reph) 597dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() = POS_RA_TO_BECOME_REPH; 598fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod 599f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* For old-style Indic script tags, move the first post-base Halant after 600f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod * last consonant. */ 601914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->is_old_spec) { 6023c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 603f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (info[i].indic_category() == OT_H) { 604f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod unsigned int j; 605f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod for (j = end - 1; j > i; j--) 606190eb31a16178269aecaf5d2ecc9012f956749f4Behdad Esfahbod if (is_consonant (info[j])) 607f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 608f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (j > i) { 609f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* Move Halant to after last consonant. */ 610f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod hb_glyph_info_t t = info[i]; 611f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); 612f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod info[j] = t; 613f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 614f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 615f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 616f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 617f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod 61881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* Attach misc marks to previous char to move with them. */ 619ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 62081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod indic_position_t last_pos = POS_START; 62181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod for (unsigned int i = start; i < end; i++) 62281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 62381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS))) 62481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 62581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() = last_pos; 62681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if (unlikely (indic_options ().uniscribe_bug_compatible && 62781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_category() == OT_H && 62881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() == POS_PRE_M)) 62981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 63081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* 63181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * Uniscribe doesn't move the Halant with Left Matra. 63281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * TEST: U+092B,U+093F,U+094DE 63381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod */ 634ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod for (unsigned int j = i; j > start; j--) 6356a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[j - 1].indic_position() != POS_PRE_M) { 636ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod info[i].indic_position() = info[j - 1].indic_position(); 637ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod break; 638ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 63981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 64081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } else if (info[i].indic_position() != POS_SMVD) { 64181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod last_pos = (indic_position_t) info[i].indic_position(); 642ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 64381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 644ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 64574ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod /* Re-attach ZWJ, ZWNJ, and halant to next char, for after-base consonants. */ 64674ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod { 64774ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod unsigned int last_halant = end; 64874ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 649deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (is_halant_or_coeng (info[i])) 65074ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod last_halant = i; 65174ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod else if (is_consonant (info[i])) { 65274ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int j = last_halant; j < i; j++) 65381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if (info[j].indic_position() != POS_SMVD) 65481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[j].indic_position() = info[i].indic_position(); 65574ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 65674ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 65745d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 658a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod { 6597b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod /* Things are out-of-control for post base positions, they may shuffle 6607b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * around like crazy, so merge clusters. For pre-base stuff, we handle 6617b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * cluster issues in final reordering. */ 6627b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod buffer->merge_clusters (base, end); 663a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Sit tight, rock 'n roll! */ 664d3637edb248162970e202e9d0671540274192844Behdad Esfahbod hb_bubble_sort (info + start, end - start, compare_indic_order); 665a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Find base again */ 666a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = end; 6673c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < end; i++) 668a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod if (info[i].indic_position() == POS_BASE_C) { 669a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = i; 670a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod break; 671a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 672a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 67345d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 674743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Setup masks now */ 675743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 676281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod { 677281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod hb_mask_t mask; 678281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod 679dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* Reph */ 680668c6046c1b3af3bd316bda0cc8636f2a5e8df42Behdad Esfahbod for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) 68185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[RPHF]; 682dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 683281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Pre-base */ 68485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[HALF]; 6853c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 686281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 687281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Base */ 68820b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = 0; 689075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 690075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].mask |= mask; 691281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Post-base */ 69285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF]; 6933c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 694281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 695281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod } 6969da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 69717d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod /* XXX This will not match for old-Indic spec since the Halant-Ra order is reversed already. */ 69885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 2 < end) 69917d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod { 700771a8f50289e8fa458cfc3cd84f73a380ce98077Behdad Esfahbod /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ 7018e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i + 1 < end; i++) 702deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (is_halant_or_coeng (info[i]) && 7038e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[i + 1].indic_category() == OT_Ra) 7048e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 70585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 70685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 7070201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 7080201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod /* Mark the subsequent stuff with 'cfar'. Used in Khmer. 7090201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * Read the feature spec. 7100201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * This allows distinguishing the following cases with MS Khmer fonts: 7110201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+179A,U+17D2,U+1782 7120201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+1782,U+17D2,U+179A 7130201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod */ 7140201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod for (; i < end; i++) 71585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[CFAR]; 7160201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 7178e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 7188e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 71917d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod } 72017d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod 7219da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod /* Apply ZWJ/ZWNJ effects */ 7223c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start + 1; i < end; i++) 7239da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod if (is_joiner (info[i])) { 7249da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod bool non_joiner = info[i].indic_category() == OT_ZWNJ; 7256b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod unsigned int j = i; 7269da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 7279da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod do { 7289da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod j--; 7296b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 73020b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWJ disables CJCT, however, it's mere presence is enough 73120b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod * to disable ligation. No explicit action needed. */ 73220b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod 73320b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWNJ disables HALF. */ 7346b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod if (non_joiner) 73585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[j].mask &= ~indic_plan->mask_array[HALF]; 7366b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 7379da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } while (j > start && !is_consonant (info[j])); 7389da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } 739743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 740743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 741743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 742743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7438bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan, 7449f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 745ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 746743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 747c5306b6861cfaa50af40e8ceb058791fa06d7981Behdad Esfahbod /* We made the vowels look like consonants. So let's call the consonant logic! */ 74885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod initial_reordering_consonant_syllable (plan, buffer, start, end); 749743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 750743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 751743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7528bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, 7539f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 754ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 755743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 75618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain. 75718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Only if not in compatibility mode that is... */ 75818c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 759a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 76018c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod { 76118c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* For dotted-circle, this is what Uniscribe does: 76218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * If dotted-circle is the last glyph, it just does nothing. 76318c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Ie. It doesn't form Reph. */ 76418c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) 76518c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod return; 76618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod } 76718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 76885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod initial_reordering_consonant_syllable (plan, buffer, start, end); 769743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 770743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 771743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7728bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_non_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, 7739f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 7743f18236a03880c0960f5990dc90685f6146951a6Behdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 775743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 776743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 777743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 778743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 779743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 780743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod#include "hb-ot-shape-complex-indic-machine.hh" 781743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 782743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7838bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 78424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod hb_font_t *font, 7853e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 786743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 78785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod update_consonant_positions (plan, font, buffer); 78885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod find_syllables (plan, buffer); 789b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 790b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 791743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 79285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodfinal_reordering_syllable (const hb_ot_shape_plan_t *plan, 79385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer, 794ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 795743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 79685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 7974ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 7984ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 799e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod /* 4. Final reordering: 800e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 801e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * After the localized forms and basic shaping forms GSUB features have been 802e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * applied (see below), the shaping engine performs some final glyph 803e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * reordering before applying all the remaining font features to the entire 804e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * cluster. 8054ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 8064ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 8074ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* Find base again */ 8085f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod unsigned int base; 8095f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod for (base = start; base < end; base++) 8105f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (info[base].indic_position() >= POS_BASE_C) { 8115f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (start < base && info[base].indic_position() > POS_BASE_C) 8125f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod base--; 8135f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod break; 8145f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod } 8154ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 8164705a7026900e51f6430f03a73c87f2df035df92Behdad Esfahbod 8174ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder matras: 818e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 819e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base matra character had been reordered before applying basic 820e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * features, the glyph can be moved closer to the main consonant based on 821e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * whether half-forms had been formed. Actual position for the matra is 822e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * defined as “after last standalone halant glyph, after initial matra 823e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * position and before the main consonant”. If ZWJ or ZWNJ follow this 824e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * halant, position is moved after it. 8254ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 8264ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 82765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ 8289d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 82965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we lost track of base, alas, position before last thingy. */ 83065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod unsigned int new_pos = base == end ? base - 2 : base - 1; 83165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 83265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* Malayalam does not have "half" forms or explicit virama forms. 83365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * The glyphs formed by 'half' are Chillus. We want to position 83465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * matra after them all. 83565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod */ 83665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM) 837e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod { 83865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod while (new_pos > start && 83965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng))))) 84065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos--; 84165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 84265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we found no Halant we are done. 84365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * Otherwise only proceed if the Halant does 84465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * not belong to the Matra itself! */ 84565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (is_halant_or_coeng (info[new_pos]) && 84665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod info[new_pos].indic_position() != POS_PRE_M) 84765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 84865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 84965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) 85065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos++; 85165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 85265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod else 85365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos = start; /* No move. */ 85465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 8559d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod 85665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start < new_pos) 85765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 8589d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* Now go see if there's actually any matras... */ 859921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod for (unsigned int i = new_pos; i > start; i--) 8606a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[i - 1].indic_position () == POS_PRE_M) 8619d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 8621a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod unsigned int old_pos = i - 1; 8631a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 8641a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0])); 8651a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod info[new_pos] = tmp; 866921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod new_pos--; 8679d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 8682cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (new_pos, MIN (end, base + 1)); 869abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } else { 870e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod for (unsigned int i = start; i < base; i++) 871abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod if (info[i].indic_position () == POS_PRE_M) { 8722cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (i, MIN (end, base + 1)); 873abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod break; 874abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } 8759d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 8764ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod } 8774ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 8784ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 8794ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder reph: 880e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 881e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Reph’s original position is always at the beginning of the syllable, 882e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * (i.e. it is not reordered at the character reordering stage). However, 883e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * it will be reordered according to the basic-forms shaping results. 884e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Possible positions for reph, depending on the script, are; after main, 885e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * before post-base consonant forms, and after post-base consonant forms. 886dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 887dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 888dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* If there's anything after the Ra that has the REPH pos, it ought to be halant. 889dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Which means that the font has failed to ligate the Reph. In which case, we 890dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * shouldn't move. */ 891dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod if (start + 1 < end && 892dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() == POS_RA_TO_BECOME_REPH && 893dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH) 894dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod { 89511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int new_reph_pos; 89611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos = indic_plan->config->reph_pos; 89711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 89811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* XXX Figure out old behavior too */ 89902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 900dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* 1. If reph should be positioned after post-base consonant forms, 901dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to step 5. 90202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 90311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_POST) 90402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 9059d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_step_5; 90602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 90702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 90802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 2. If the reph repositioning class is not after post-base: target 909dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is after the first explicit halant glyph between the 910dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-reph consonant and last main consonant. If ZWJ or ZWNJ 911dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * are following this halant, position is moved after it. If such 912dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is found, this is the target position. Otherwise, 913dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to the next step. 914dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * 915dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Note: in old-implementation fonts, where classifications were 916dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * fixed in shaping engine, there was no case where reph position 917dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * will be found on this step. 91802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 91902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 92002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = start + 1; 921deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 92202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 92302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 924deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 92502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 92602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 92702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 92802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 92902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 93002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 93102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 93202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 3. If reph should be repositioned after the main consonant: find the 933dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first consonant not ligated with main, or find the first 934dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant that is not a potential pre-base reordering Ra. 93502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 93611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_MAIN) 93702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 938b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos = base; 939b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod /* XXX Skip potential pre-base reordering Ra. */ 94034ae336f3fae93ef9372881d545c817bce383041Behdad Esfahbod while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN) 941b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos++; 942b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod if (new_reph_pos < end) 943b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod goto reph_move; 94402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 94502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 94602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 4. If reph should be positioned before post-base consonant, find 947dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-base classified consonant not ligated with main. If no 948dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant is found, the target position should be before the 949dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first matra, syllable modifier sign or vedic sign. 95002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 9519d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* This is our take on what step 4 is trying to say (and failing, BADLY). */ 95211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_SUB) 95302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 9549d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos = base; 9559d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod while (new_reph_pos < end && 956be8b9f5f715f6fb36b98bd33c3303f79cc068f8aBehdad Esfahbod !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD)))) 9579d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos++; 9589d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (new_reph_pos < end) 9599d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_move; 96002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 96102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 96202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 5. If no consonant is found in steps 3 or 4, move reph to a position 963dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * immediately before the first post-base matra, syllable modifier 964dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * sign or vedic sign that has a reordering class after the intended 965dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * reph position. For example, if the reordering position for reph 966dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * is post-main, it will skip above-base matras that also have a 967dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * post-main position. 968dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 96902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_step_5: 97002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 971d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* Copied from step 2. */ 972d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos = start + 1; 973d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 974d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 975d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod 976d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 977d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 978d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 979d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 980d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod goto reph_move; 981d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod } 98202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 983dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 98402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 6. Otherwise, reorder reph to the end of the syllable. 98502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 98602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 98702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = end - 1; 98802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD) 98902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 99002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 991892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod /* 992892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * If the Reph is to be ending up after a Matra,Halant sequence, 993892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * position it before that Halant so it can interact with the Matra. 994892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * However, if it's a plain Consonant,Halant we shouldn't do that. 995892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * Uniscribe doesn't do this. 996892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * TEST: U+0930,U+094D,U+0915,U+094B,U+094D 997892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod */ 998a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (!indic_options ().uniscribe_bug_compatible && 999deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod unlikely (is_halant_or_coeng (info[new_reph_pos]))) { 100002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod for (unsigned int i = base + 1; i < new_reph_pos; i++) 100102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (info[i].indic_category() == OT_M) { 100202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Ok, got it. */ 100302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 100402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 100502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 100602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 10078df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod } 10088df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod 100902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_move: 101002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1011e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod /* Yay, one big cluster! Merge before moving. */ 1012e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 1013e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod 101402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Move */ 101502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod hb_glyph_info_t reph = info[start]; 101602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0])); 101702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod info[new_reph_pos] = reph; 101802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1019dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod } 1020dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1021dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1022dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* o Reorder pre-base reordering consonants: 1023e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1024e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base reordering consonant is found, reorder it according to 1025e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * the following rules: 1026e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod */ 1027e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 102885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ 102946e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod { 10308e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 103185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) 103278818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod { 10338e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 1. Only reorder a glyph produced by substitution during application 10348e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * of the <pref> feature. (Note that a font may shape a Ra consonant with 10358e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * the feature generally but block it in certain contexts.) 10368e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 103785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (i + 1 == end || (info[i + 1].mask & indic_plan->mask_array[PREF]) == 0) 10388e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 10398e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 10408e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 2. Try to find a target position the same way as for pre-base matra. 10418e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * If it is found, reorder pre-base consonant glyph. 10428e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 10438e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 3. If position is not found, reorder immediately before main 10448e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * consonant. 10458e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 10468e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 10478e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int new_pos = base; 10480afb84c12567ac35adac657bf8be29999b8c5a50Behdad Esfahbod while (new_pos > start && 10490afb84c12567ac35adac657bf8be29999b8c5a50Behdad Esfahbod !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS))) 10508e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos--; 10518e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 1052d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod /* In Khmer coeng model, a V,Ra can go *after* matras. If it goes after a 1053d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod * split matra, it should be reordered to *before* the left part of such matra. */ 1054d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) 1055d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 1056d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod unsigned int old_pos = i; 1057d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod for (unsigned int i = base + 1; i < old_pos; i++) 1058d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod if (info[i].indic_category() == OT_M) 1059d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 1060d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod new_pos--; 1061d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod break; 1062d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1063d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1064d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod 1065deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) 10668e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 10678e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if (new_pos < end && is_joiner (info[new_pos])) 10688e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos++; 10698e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 10708e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 10718e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int old_pos = i; 1072e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (new_pos, old_pos + 1); 10738e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 10748e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0])); 10758e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[new_pos] = tmp; 10768e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 10778e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 10788e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 10798e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 108078818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod } 108146e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod } 1082eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1083eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1084a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod /* Apply 'init' to the Left Matra if it's a word start. */ 10856a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[start].indic_position () == POS_PRE_M && 1086a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod (!start || 1087eace47b173807d94b29a6490d0bc3c9f8f6168d1Behdad Esfahbod !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & 10882c372b80f6befad69e216e3f218b38640b8cc044Behdad Esfahbod FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))) 108985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[start].mask |= indic_plan->mask_array[INIT]; 1090a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod 1091eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 10928ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod /* 10938ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod * Finish off the clusters and go home! 10948ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod */ 1095decf6ffca475fe01ff3151b7641f629f031137d2Behdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 1096ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 109730c3d5e9fc61b49c2c6ad4e744300edd6f3e0261Behdad Esfahbod /* Uniscribe merges the entire cluster. 109821d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This means, half forms are submerged into the main consonants cluster. 109921d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This is unnecessary, and makes cursor positioning harder, but that's what 110021d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * Uniscribe does. */ 1101e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 110221d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod } 1103ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod} 1104e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1105e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1106ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbodstatic void 11078bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 110885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 11093e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1110ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod{ 1111ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int count = buffer->len; 1112ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod if (!count) return; 1113ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod 1114ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1115ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int last = 0; 1116cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1117ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1118cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod if (last_syllable != info[i].syllable()) { 111985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, i); 1120ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod last = i; 1121cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod last_syllable = info[last].syllable(); 1122ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod } 112385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, count); 1124e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1125743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); 1126743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); 1127743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1128743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1129743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1130693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = 1131693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{ 1132693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod "indic", 1133693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod collect_features_indic, 1134693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod override_features_indic, 1135a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_create_indic, 1136a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_destroy_indic, 1137693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod NULL, /* normalization_preference */ 1138693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod setup_masks_indic, 11391e7d860613032e40a3f90e2caa2ee5ac44ab8c8cBehdad Esfahbod false, /* zero_width_attached_marks */ 1140693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod}; 1141