hb-ot-shape-complex-indic.cc revision 23b0e9d7dc801e11640979af3c2b00649a519bb1
1b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod/* 227aba594c90b4444c35273a38f5fedc8e09d9a88Behdad Esfahbod * Copyright © 2011,2012 Google, Inc. 3b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 4b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * This is part of HarfBuzz, a text shaping library. 5b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 6b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * Permission is hereby granted, without written agreement and without 7b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this 8b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * software and its documentation for any purpose, provided that the 9b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * above copyright notice and the following two paragraphs appear in 10b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * all copies of this software. 11b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 12b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * DAMAGE. 17b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 18b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 24b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * Google Author(s): Behdad Esfahbod 25b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod */ 26b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 273ed4634ec349fa9e943ad23718c04be4dd4bba62Behdad Esfahbod#include "hb-ot-shape-complex-indic-private.hh" 2849c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod#include "hb-ot-layout-private.hh" 29352372ae5ea0998e40cf9fe43c22b6b610a5764eBehdad Esfahbod 301d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 3111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 3211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Global Indic shaper options. 3311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 341d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 35a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodstruct indic_options_t 36ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod{ 37a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod int initialized : 1; 38a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod int uniscribe_bug_compatible : 1; 39a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod}; 40a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 41a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodunion indic_options_union_t { 42a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod int i; 43a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod indic_options_t opts; 44a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod}; 45a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad EsfahbodASSERT_STATIC (sizeof (int) == sizeof (indic_options_union_t)); 46a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 47a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodstatic indic_options_union_t 48a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodindic_options_init (void) 49a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod{ 50a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod indic_options_union_t u; 51a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod u.i = 0; 52a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod u.opts.initialized = 1; 53a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 54a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod char *c = getenv ("HB_OT_INDIC_OPTIONS"); 55a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible"); 56a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 57a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod return u; 58a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod} 59a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 60a02d86484be870615297abfc7be9f94645434762Behdad Esfahbodstatic inline indic_options_t 61a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodindic_options (void) 62a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod{ 63a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod static indic_options_union_t options; 64a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 65a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (unlikely (!options.i)) { 66a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod /* This is idempotent and threadsafe. */ 67a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod options = indic_options_init (); 68ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 69ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod 70a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod return options.opts; 71a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod} 72a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 73ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod 7411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 7511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic configurations. Note that we do not want to keep every single script-specific 7611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * behavior in these tables necessarily. This should mainly be used for per-script 7711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * properties that are cheaper keeping here, than in the code. Ie. if, say, one and 7811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * only one script has an exception, that one script can be if'ed directly in the code, 7911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * instead of adding a new flag in these structs. 8011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 8111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 8211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum base_position_t { 8311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_FIRST, 8411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_LAST 8511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 8611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_position_t { 8711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_DEFAULT = POS_BEFORE_POST, 8811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 8911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_MAIN = POS_AFTER_MAIN, 9011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_SUB = POS_BEFORE_SUB, 9111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_SUB = POS_AFTER_SUB, 9211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_POST = POS_BEFORE_POST, 9311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_POST = POS_AFTER_POST 9411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 9511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_mode_t { 9611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_IMPLICIT, /* Reph formed out of initial Ra,H sequence. */ 9711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_EXPLICIT, /* Reph formed out of initial Ra,H,ZWJ sequence. */ 9811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */ 9911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_LOG_REPHA /* Encoded Repha character, needs reordering. */ 10011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 10111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstruct indic_config_t 10211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 10311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_script_t script; 10411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool has_old_spec; 10511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_codepoint_t virama; 10611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base_position_t base_pos; 10711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos; 10811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_mode_t reph_mode; 10911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 11011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 11111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstatic const indic_config_t indic_configs[] = 11211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 11311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Default. Should be first. */ 11411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_DEFAULT, REPH_MODE_IMPLICIT}, 11511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT}, 11611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_BENGALI, true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT}, 11711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_GURMUKHI, true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT}, 11811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_GUJARATI, true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT}, 11911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_ORIYA, true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT}, 12011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_TAMIL, true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT}, 12111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_TELUGU, true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT}, 12211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_KANNADA, true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT}, 12311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA}, 12411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT}, 12511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT, REPH_MODE_VIS_REPHA}, 12611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 12711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 12811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 12911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 13011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 13111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic shaper. 13211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 1339ccc6382ba43760167c134c18c1c4ada4b8c3f22Behdad Esfahbod 134eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstruct feature_list_t { 135c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_tag_t tag; 136c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_bool_t is_global; 137eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod}; 138eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 139eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstatic const feature_list_t 14085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodindic_features[] = 141b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 14285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 14385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Basic features. 14485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied in order, one at a time, after initial_reordering. 14585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 146c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('n','u','k','t'), true}, 147e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod {HB_TAG('a','k','h','n'), true}, 148c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('r','p','h','f'), false}, 1491ac075b227090a9ad930dcc1670236c176b27067Behdad Esfahbod {HB_TAG('r','k','r','f'), true}, 150c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('p','r','e','f'), false}, 151c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('h','a','l','f'), false}, 152167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod {HB_TAG('b','l','w','f'), false}, 15329f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod {HB_TAG('a','b','v','f'), false}, 154c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('p','s','t','f'), false}, 1550201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod {HB_TAG('c','f','a','r'), false}, 15620b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod {HB_TAG('c','j','c','t'), true}, 1571d6846db9ebf84561bb30a4e48c6c43184914099Behdad Esfahbod {HB_TAG('v','a','t','u'), true}, 15885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 15985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Other features. 16085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied all at once, after final_reordering. 16185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 16285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('i','n','i','t'), false}, 16385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('p','r','e','s'), true}, 16485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('a','b','v','s'), true}, 16585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('b','l','w','s'), true}, 16685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('p','s','t','s'), true}, 16785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('h','a','l','n'), true}, 16885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* Positioning features, though we don't care about the types. */ 16985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('d','i','s','t'), true}, 17085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('a','b','v','m'), true}, 17185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('b','l','w','m'), true}, 172c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod}; 173c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod 17485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod/* 17585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Must be in the same order as the indic_features array. 17685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 177c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbodenum { 178c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod _NUKT, 179e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod _AKHN, 180c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod RPHF, 181df6d45c693c417bf311e6fa49f18a8558542e525Behdad Esfahbod _RKRF, 182c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PREF, 183c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod HALF, 184167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod BLWF, 18529f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod ABVF, 186c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PSTF, 1870201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod CFAR, 18820b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod _CJCT, 18985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _VATU, 19085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 19185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INIT, 19285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PRES, 19385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVS, 19485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWS, 19585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PSTS, 19685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _HALN, 19785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _DIST, 19885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVM, 19985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWM, 20085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 20185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_NUM_FEATURES, 20285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */ 203b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod}; 204b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 205743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 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, 257b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod bool zero_context, 258a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_face_t *face) const 259a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 260a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 261b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (hb_ot_layout_would_substitute_lookup_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) 262a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return true; 263a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return false; 264a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 265a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 266a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod private: 267a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const hb_ot_map_t::lookup_map_t *lookups; 268a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int count; 269a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 270a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 271a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstruct indic_shape_plan_t 272a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 27385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod ASSERT_POD (); 274914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 275914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const 276914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 277914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod hb_codepoint_t glyph = virama_glyph; 278914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (unlikely (virama_glyph == (hb_codepoint_t) -1)) 279914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 28011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!config->virama || !font->get_glyph (config->virama, 0, &glyph)) 281914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod glyph = 0; 282914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Technically speaking, the spec says we should apply 'locl' to virama too. 283914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * Maybe one day... */ 284914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 285914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Our get_glyph() function needs a font, so we can't get the virama glyph 286914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */ 287914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph; 288914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 289914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 290914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod *pglyph = glyph; 291914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod return glyph != 0; 292914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 29385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 29411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod const indic_config_t *config; 29585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 29685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod bool is_old_spec; 29785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_codepoint_t virama_glyph; 29885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 29985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pref; 30085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t blwf; 30185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pstf; 30285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 30385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_mask_t mask_array[INDIC_NUM_FEATURES]; 304a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 305a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 306a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void * 307a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_create_indic (const hb_ot_shape_plan_t *plan) 308a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 30985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t)); 31085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (unlikely (!indic_plan)) 311a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return NULL; 312a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 31311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[0]; 31411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++) 31511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (plan->props.script == indic_configs[i].script) { 31611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[i]; 31711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 31885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 31911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 32011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.get_chosen_script (0) & 0x000000FF) != '2'); 32111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->virama_glyph = (hb_codepoint_t) -1; 32285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 32385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f')); 32485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f')); 32585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f')); 32685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 32785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) 32885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->mask_array[i] = indic_features[i].is_global ? 0 : plan->map.get_1_mask (indic_features[i].tag); 329a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 33085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod return indic_plan; 331a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 332a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 333a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void 334a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_destroy_indic (void *data) 335a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 336a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod free (data); 337a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 338a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 339a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic indic_position_t 340a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodconsonant_position_from_face (const indic_shape_plan_t *indic_plan, 341a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_codepoint_t *glyphs, unsigned int glyphs_len, 342a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_face_t *face) 343a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 344b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod bool zero_context = indic_plan->is_old_spec ? false : true; 345b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C; 346b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->blwf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C; 347b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->pstf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_POST_C; 348a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return POS_BASE_C; 349a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 350a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 351a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 352693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 35316c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodsetup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, 35416c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_buffer_t *buffer, 35516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_font_t *font HB_UNUSED) 35624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 35724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); 35824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); 35924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 36024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod /* We cannot setup masks here. We save information about characters 36124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod * and setup masks later on in a pause-callback. */ 36224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 36324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod unsigned int count = buffer->len; 36424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 36524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod set_indic_properties (buffer->info[i]); 36624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 36724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 36824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic int 36924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodcompare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 37024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 37124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int a = pa->indic_position(); 37224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int b = pb->indic_position(); 37324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 37424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod return a < b ? -1 : a == b ? 0 : +1; 37524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 37624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 37724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 37824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 37924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic void 3808bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodupdate_consonant_positions (const hb_ot_shape_plan_t *plan, 38185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 38285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer) 3838ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod{ 384a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 3858ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 386a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int consonant_pos = indic_plan->is_old_spec ? 0 : 1; 3878ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_codepoint_t glyphs[2]; 388914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->get_virama_glyph (font, &glyphs[1 - consonant_pos])) 3898ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod { 3908ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_face_t *face = font->face; 3918ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod unsigned int count = buffer->len; 3928ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 3938ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod if (buffer->info[i].indic_position() == POS_BASE_C) { 39424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod glyphs[consonant_pos] = buffer->info[i].codepoint; 395a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, 2, face); 3968ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 3978ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 3988ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod} 3998ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 400867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 4017ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod/* Rules from: 4027ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ 4037ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod 404743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 40585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodinitial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, 406ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 407743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 408914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 409ee58f3bc75d2d071a71b94063bf12205a5871acbBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 410743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 411617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod 412743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 1. Find base consonant: 413743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 414743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The shaping engine finds the base consonant of the syllable, using the 415743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following algorithm: starting from the end of the syllable, move backwards 416743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * until a consonant is found that does not have a below-base or post-base 417743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * form (post-base forms have to follow below-base forms), or that is not a 418743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * pre-base reordering Ra, or arrive at the first consonant. The consonant 419743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * stopped at will be the base. 420743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 421743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o If the syllable starts with Ra + Halant (in a script that has Reph) 422743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 423743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * base consonants. 424743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 425743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 4265e72071062c015237b79fbd0521341a63166a204Behdad Esfahbod unsigned int base = end; 42776b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod bool has_reph = false; 428743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 42976b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod { 430617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 431617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 432617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * base consonants. */ 433617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod unsigned int limit = start; 43485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[RPHF] && 435617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod start + 3 <= end && 436617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod info[start].indic_category() == OT_Ra && 437617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod info[start + 1].indic_category() == OT_H && 43811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (/* TODO Handle other Reph modes. */ 43911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || 44011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ) 4413285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod )) 442617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod { 443617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod limit += 2; 4443285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 4453285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod limit++; 446617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod base = start; 447617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = true; 448617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod }; 44976b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod 45023b0e9d7dc801e11640979af3c2b00649a519bb1Behdad Esfahbod switch (indic_plan->config->base_pos) 4515d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 45211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_LAST: 45311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 45411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> starting from the end of the syllable, move backwards */ 45511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int i = end; 45611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool seen_below = false; 45711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod do { 45811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod i--; 45911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> until a consonant is found */ 46011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i])) 4615d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 46211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> that does not have a below-base or post-base form 46311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * (post-base forms have to follow below-base forms), */ 46411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() != POS_BELOW_C && 46511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (info[i].indic_position() != POS_POST_C || seen_below)) 46611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 46711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 46811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 46911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 47011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() == POS_BELOW_C) 47111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod seen_below = true; 47211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 47311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or that is not a pre-base reordering Ra, 47411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 47511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * IMPLEMENTATION NOTES: 47611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 47711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Our pre-base reordering Ra's are marked POS_BELOW, so will be skipped 47811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * by the logic above already. 47911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 48011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 48111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or arrive at the first consonant. The consonant stopped at will 48211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * be the base. */ 4835d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod base = i; 4845d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 48511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 48611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 48711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* A ZWJ after a Halant stops the base search, and requests an explicit 48811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * half form. 48911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * A ZWJ before a Halant, requests a subjoined form instead, and hence 49011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * search continues. This is particularly important for Bengali 49111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * sequence Ra,H,Ya that shouls form Ya-Phalaa by subjoining Ya. */ 49211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (start < i && 49311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_category() == OT_ZWJ && 49411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i - 1].indic_category() == OT_H) 49511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 49611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 49711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } while (i > limit); 49811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 49911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 5005d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 50111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_FIRST: 50211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 50311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* In scripts without half forms (eg. Khmer), the first consonant is always the base. */ 5045d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 50511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!has_reph) 50611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = limit; 50734c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 50811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Find the last base consonant that is not blocked by ZWJ. If there is 50911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * a ZWJ right before a base consonant, that would request a subjoined form. */ 51011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = limit; i < end; i++) 51111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 51211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 51311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (limit < i && info[i - 1].indic_category() == OT_ZWJ) 51411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 51511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 51611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 51711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 51834c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 51911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Mark all subsequent consonants as below. */ 52011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 52111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 52211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_position() = POS_BELOW_C; 52311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 52411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 52511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 52611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod default: 52711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod abort (); 5285d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 529743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 530617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 531617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 5322278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * base consonants. 5332278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * 5342278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ 5352278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod if (has_reph && base == start && start + 2 == limit) { 536617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* Have no other consonant, so Reph is not formed and Ra becomes base. */ 537617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = false; 538617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod } 5395e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod } 5402278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod 54134c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod if (base < end) 54234c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod info[base].indic_position() = POS_BASE_C; 5433d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 5443d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 545743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 2. Decompose and reorder Matras: 546743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 547743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Each matra and any syllable modifier sign in the cluster are moved to the 548743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * appropriate position relative to the consonant(s) in the cluster. The 549743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * shaping engine decomposes two- or three-part matras into their constituent 550743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * parts before any repositioning. Matra characters are classified by which 551743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * consonant in a conjunct they have affinity for and are reordered to the 552743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following positions: 553743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 554743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o Before first half form in the syllable 555743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After subjoined consonants 556743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After post-form consonant 557743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After main consonant (for above marks) 558743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 559743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 560743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 561743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The normalize() routine has already decomposed matras for us, so we don't 562743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * need to worry about that. 563743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 564743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 565743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 566743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 3. Reorder marks to canonical order: 567743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 568743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Adjacent nukta and halant or nukta and vedic sign are always repositioned 569743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * if necessary, so that the nukta is first. 570743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 571743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 572743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 573743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * We don't need to do this: the normalize() routine already did this for us. 574743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 575743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 576743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 57745d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod /* Reorder characters */ 57845d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 5793c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 580900cf3d449bf36d4f8b1474590cae925fef48fc8Behdad Esfahbod info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position()); 58155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 582075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 583075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].indic_position() = POS_BASE_C; 58445d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 58555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod /* Mark final consonants. A final consonant is one appearing after a matra, 58655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod * like in Khmer. */ 58755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 58855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (info[i].indic_category() == OT_M) { 58955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int j = i + 1; j < end; j++) 59055f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (is_consonant (info[j])) { 59155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod info[j].indic_position() = POS_FINAL_C; 59255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 59355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 59455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 59555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 59655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 597fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod /* Handle beginning Ra */ 5985e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod if (has_reph) 599dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() = POS_RA_TO_BECOME_REPH; 600fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod 601f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* For old-style Indic script tags, move the first post-base Halant after 602f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod * last consonant. */ 603914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->is_old_spec) { 6043c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 605f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (info[i].indic_category() == OT_H) { 606f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod unsigned int j; 607f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod for (j = end - 1; j > i; j--) 608190eb31a16178269aecaf5d2ecc9012f956749f4Behdad Esfahbod if (is_consonant (info[j])) 609f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 610f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (j > i) { 611f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* Move Halant to after last consonant. */ 612f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod hb_glyph_info_t t = info[i]; 613f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); 614f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod info[j] = t; 615f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 616f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 617f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 618f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 619f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod 62081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* Attach misc marks to previous char to move with them. */ 621ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 62281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod indic_position_t last_pos = POS_START; 62381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod for (unsigned int i = start; i < end; i++) 62481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 62581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS))) 62681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 62781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() = last_pos; 62881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if (unlikely (indic_options ().uniscribe_bug_compatible && 62981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_category() == OT_H && 63081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() == POS_PRE_M)) 63181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 63281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* 63381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * Uniscribe doesn't move the Halant with Left Matra. 63481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * TEST: U+092B,U+093F,U+094DE 63581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod */ 636ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod for (unsigned int j = i; j > start; j--) 6376a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[j - 1].indic_position() != POS_PRE_M) { 638ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod info[i].indic_position() = info[j - 1].indic_position(); 639ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod break; 640ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 64181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 64281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } else if (info[i].indic_position() != POS_SMVD) { 64381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod last_pos = (indic_position_t) info[i].indic_position(); 644ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 64581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 646ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 64774ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod /* Re-attach ZWJ, ZWNJ, and halant to next char, for after-base consonants. */ 64874ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod { 64974ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod unsigned int last_halant = end; 65074ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 651deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (is_halant_or_coeng (info[i])) 65274ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod last_halant = i; 65374ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod else if (is_consonant (info[i])) { 65474ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int j = last_halant; j < i; j++) 65581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if (info[j].indic_position() != POS_SMVD) 65681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[j].indic_position() = info[i].indic_position(); 65774ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 65874ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 65945d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 660a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod { 6617b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod /* Things are out-of-control for post base positions, they may shuffle 6627b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * around like crazy, so merge clusters. For pre-base stuff, we handle 6637b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * cluster issues in final reordering. */ 6647b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod buffer->merge_clusters (base, end); 665a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Sit tight, rock 'n roll! */ 666d3637edb248162970e202e9d0671540274192844Behdad Esfahbod hb_bubble_sort (info + start, end - start, compare_indic_order); 667a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Find base again */ 668a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = end; 6693c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < end; i++) 670a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod if (info[i].indic_position() == POS_BASE_C) { 671a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = i; 672a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod break; 673a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 674a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 67545d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 676743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Setup masks now */ 677743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 678281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod { 679281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod hb_mask_t mask; 680281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod 681dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* Reph */ 682668c6046c1b3af3bd316bda0cc8636f2a5e8df42Behdad Esfahbod for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) 68385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[RPHF]; 684dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 685281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Pre-base */ 68685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[HALF]; 6873c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 688281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 689281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Base */ 69020b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = 0; 691075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 692075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].mask |= mask; 693281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Post-base */ 69485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF]; 6953c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 696281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 697281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod } 6989da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 69985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 2 < end) 70017d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod { 701771a8f50289e8fa458cfc3cd84f73a380ce98077Behdad Esfahbod /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ 7028e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i + 1 < end; i++) 7036732d62e78b13842ead9549c97bede25c73976cbBehdad Esfahbod if (is_halant_or_coeng (info[i + (indic_plan->is_old_spec ? 1 : 0)]) && 7046732d62e78b13842ead9549c97bede25c73976cbBehdad Esfahbod info[i + (indic_plan->is_old_spec ? 0 : 1)].indic_category() == OT_Ra) 7058e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 70685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 70785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 7080201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 7090201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod /* Mark the subsequent stuff with 'cfar'. Used in Khmer. 7100201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * Read the feature spec. 7110201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * This allows distinguishing the following cases with MS Khmer fonts: 7120201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+179A,U+17D2,U+1782 7130201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+1782,U+17D2,U+179A 7140201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod */ 7150201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod for (; i < end; i++) 71685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[CFAR]; 7170201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 7188e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 7198e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 72017d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod } 72117d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod 7229da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod /* Apply ZWJ/ZWNJ effects */ 7233c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start + 1; i < end; i++) 7249da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod if (is_joiner (info[i])) { 7259da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod bool non_joiner = info[i].indic_category() == OT_ZWNJ; 7266b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod unsigned int j = i; 7279da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 7289da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod do { 7299da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod j--; 7306b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 73120b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWJ disables CJCT, however, it's mere presence is enough 73220b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod * to disable ligation. No explicit action needed. */ 73320b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod 73420b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWNJ disables HALF. */ 7356b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod if (non_joiner) 73685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[j].mask &= ~indic_plan->mask_array[HALF]; 7376b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 7389da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } while (j > start && !is_consonant (info[j])); 7399da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } 740743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 741743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 742743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 743743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7448bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan, 7459f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 746ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 747743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 748c5306b6861cfaa50af40e8ceb058791fa06d7981Behdad Esfahbod /* We made the vowels look like consonants. So let's call the consonant logic! */ 74985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod initial_reordering_consonant_syllable (plan, buffer, start, end); 750743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 751743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 752743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7538bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, 7549f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 755ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 756743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 75718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain. 75818c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Only if not in compatibility mode that is... */ 75918c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 760a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 76118c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod { 76218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* For dotted-circle, this is what Uniscribe does: 76318c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * If dotted-circle is the last glyph, it just does nothing. 76418c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Ie. It doesn't form Reph. */ 76518c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) 76618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod return; 76718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod } 76818c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 76985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod initial_reordering_consonant_syllable (plan, buffer, start, end); 770743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 771743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 772743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7738bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_non_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, 7749f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 7753f18236a03880c0960f5990dc90685f6146951a6Behdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 776743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 777743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 778743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 779743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 780743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 781743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod#include "hb-ot-shape-complex-indic-machine.hh" 782743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 783743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7848bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 78524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod hb_font_t *font, 7863e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 787743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 78885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod update_consonant_positions (plan, font, buffer); 78985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod find_syllables (plan, buffer); 790b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 791b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 792743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 79385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodfinal_reordering_syllable (const hb_ot_shape_plan_t *plan, 79485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer, 795ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 796743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 79785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 7984ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 7994ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 800e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod /* 4. Final reordering: 801e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 802e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * After the localized forms and basic shaping forms GSUB features have been 803e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * applied (see below), the shaping engine performs some final glyph 804e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * reordering before applying all the remaining font features to the entire 805e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * cluster. 8064ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 8074ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 8084ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* Find base again */ 8095f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod unsigned int base; 8105f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod for (base = start; base < end; base++) 8115f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (info[base].indic_position() >= POS_BASE_C) { 8125f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (start < base && info[base].indic_position() > POS_BASE_C) 8135f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod base--; 8145f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod break; 8155f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod } 8164ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 8174705a7026900e51f6430f03a73c87f2df035df92Behdad Esfahbod 8184ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder matras: 819e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 820e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base matra character had been reordered before applying basic 821e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * features, the glyph can be moved closer to the main consonant based on 822e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * whether half-forms had been formed. Actual position for the matra is 823e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * defined as “after last standalone halant glyph, after initial matra 824e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * position and before the main consonant”. If ZWJ or ZWNJ follow this 825e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * halant, position is moved after it. 8264ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 8274ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 82865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ 8299d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 83065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we lost track of base, alas, position before last thingy. */ 83165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod unsigned int new_pos = base == end ? base - 2 : base - 1; 83265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 83365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* Malayalam does not have "half" forms or explicit virama forms. 83465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * The glyphs formed by 'half' are Chillus. We want to position 83565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * matra after them all. 83665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod */ 83765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM) 838e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod { 83965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod while (new_pos > start && 84065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng))))) 84165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos--; 84265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 84365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we found no Halant we are done. 84465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * Otherwise only proceed if the Halant does 84565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * not belong to the Matra itself! */ 84665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (is_halant_or_coeng (info[new_pos]) && 84765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod info[new_pos].indic_position() != POS_PRE_M) 84865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 84965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 85065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) 85165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos++; 85265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 85365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod else 85465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos = start; /* No move. */ 85565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 8569d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod 85765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start < new_pos) 85865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 8599d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* Now go see if there's actually any matras... */ 860921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod for (unsigned int i = new_pos; i > start; i--) 8616a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[i - 1].indic_position () == POS_PRE_M) 8629d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 8631a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod unsigned int old_pos = i - 1; 8641a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 8651a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0])); 8661a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod info[new_pos] = tmp; 867921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod new_pos--; 8689d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 8692cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (new_pos, MIN (end, base + 1)); 870abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } else { 871e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod for (unsigned int i = start; i < base; i++) 872abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod if (info[i].indic_position () == POS_PRE_M) { 8732cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (i, MIN (end, base + 1)); 874abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod break; 875abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } 8769d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 8774ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod } 8784ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 8794ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 8804ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder reph: 881e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 882e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Reph’s original position is always at the beginning of the syllable, 883e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * (i.e. it is not reordered at the character reordering stage). However, 884e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * it will be reordered according to the basic-forms shaping results. 885e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Possible positions for reph, depending on the script, are; after main, 886e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * before post-base consonant forms, and after post-base consonant forms. 887dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 888dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 889dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* If there's anything after the Ra that has the REPH pos, it ought to be halant. 890dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Which means that the font has failed to ligate the Reph. In which case, we 891dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * shouldn't move. */ 892dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod if (start + 1 < end && 893dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() == POS_RA_TO_BECOME_REPH && 894dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH) 895dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod { 89611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int new_reph_pos; 89711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos = indic_plan->config->reph_pos; 89811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 89911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* XXX Figure out old behavior too */ 90002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 901dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* 1. If reph should be positioned after post-base consonant forms, 902dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to step 5. 90302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 90411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_POST) 90502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 9069d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_step_5; 90702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 90802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 90902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 2. If the reph repositioning class is not after post-base: target 910dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is after the first explicit halant glyph between the 911dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-reph consonant and last main consonant. If ZWJ or ZWNJ 912dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * are following this halant, position is moved after it. If such 913dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is found, this is the target position. Otherwise, 914dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to the next step. 915dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * 916dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Note: in old-implementation fonts, where classifications were 917dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * fixed in shaping engine, there was no case where reph position 918dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * will be found on this step. 91902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 92002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 92102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = start + 1; 922deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 92302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 92402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 925deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 92602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 92702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 92802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 92902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 93002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 93102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 93202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 93302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 3. If reph should be repositioned after the main consonant: find the 934dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first consonant not ligated with main, or find the first 935dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant that is not a potential pre-base reordering Ra. 93602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 93711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_MAIN) 93802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 939b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos = base; 940b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod /* XXX Skip potential pre-base reordering Ra. */ 94134ae336f3fae93ef9372881d545c817bce383041Behdad Esfahbod while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN) 942b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos++; 943b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod if (new_reph_pos < end) 944b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod goto reph_move; 94502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 94602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 94702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 4. If reph should be positioned before post-base consonant, find 948dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-base classified consonant not ligated with main. If no 949dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant is found, the target position should be before the 950dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first matra, syllable modifier sign or vedic sign. 95102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 9529d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* This is our take on what step 4 is trying to say (and failing, BADLY). */ 95311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_SUB) 95402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 9559d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos = base; 9569d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod while (new_reph_pos < end && 957be8b9f5f715f6fb36b98bd33c3303f79cc068f8aBehdad Esfahbod !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD)))) 9589d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos++; 9599d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (new_reph_pos < end) 9609d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_move; 96102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 96202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 96302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 5. If no consonant is found in steps 3 or 4, move reph to a position 964dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * immediately before the first post-base matra, syllable modifier 965dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * sign or vedic sign that has a reordering class after the intended 966dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * reph position. For example, if the reordering position for reph 967dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * is post-main, it will skip above-base matras that also have a 968dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * post-main position. 969dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 97002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_step_5: 97102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 972d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* Copied from step 2. */ 973d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos = start + 1; 974d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 975d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 976d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod 977d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 978d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 979d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 980d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 981d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod goto reph_move; 982d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod } 98302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 984dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 98502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 6. Otherwise, reorder reph to the end of the syllable. 98602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 98702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 98802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = end - 1; 98902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD) 99002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 99102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 992892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod /* 993892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * If the Reph is to be ending up after a Matra,Halant sequence, 994892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * position it before that Halant so it can interact with the Matra. 995892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * However, if it's a plain Consonant,Halant we shouldn't do that. 996892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * Uniscribe doesn't do this. 997892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * TEST: U+0930,U+094D,U+0915,U+094B,U+094D 998892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod */ 999a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (!indic_options ().uniscribe_bug_compatible && 1000deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod unlikely (is_halant_or_coeng (info[new_reph_pos]))) { 100102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod for (unsigned int i = base + 1; i < new_reph_pos; i++) 100202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (info[i].indic_category() == OT_M) { 100302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Ok, got it. */ 100402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 100502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 100602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 100702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 10088df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod } 10098df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod 101002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_move: 101102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1012e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod /* Yay, one big cluster! Merge before moving. */ 1013e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 1014e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod 101502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Move */ 101602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod hb_glyph_info_t reph = info[start]; 101702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0])); 101802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod info[new_reph_pos] = reph; 101902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1020dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod } 1021dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1022dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1023dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* o Reorder pre-base reordering consonants: 1024e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1025e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base reordering consonant is found, reorder it according to 1026e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * the following rules: 1027e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod */ 1028e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 102985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ 103046e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod { 10318e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 103285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) 103378818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod { 10348e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 1. Only reorder a glyph produced by substitution during application 10358e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * of the <pref> feature. (Note that a font may shape a Ra consonant with 10368e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * the feature generally but block it in certain contexts.) 10378e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 103885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (i + 1 == end || (info[i + 1].mask & indic_plan->mask_array[PREF]) == 0) 10398e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 10408e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 10418e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 2. Try to find a target position the same way as for pre-base matra. 10428e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * If it is found, reorder pre-base consonant glyph. 10438e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 10448e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 3. If position is not found, reorder immediately before main 10458e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * consonant. 10468e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 10478e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 10488e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int new_pos = base; 10490afb84c12567ac35adac657bf8be29999b8c5a50Behdad Esfahbod while (new_pos > start && 10500afb84c12567ac35adac657bf8be29999b8c5a50Behdad Esfahbod !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS))) 10518e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos--; 10528e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 1053d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod /* In Khmer coeng model, a V,Ra can go *after* matras. If it goes after a 1054d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod * split matra, it should be reordered to *before* the left part of such matra. */ 1055d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) 1056d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 1057d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod unsigned int old_pos = i; 1058d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod for (unsigned int i = base + 1; i < old_pos; i++) 1059d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod if (info[i].indic_category() == OT_M) 1060d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 1061d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod new_pos--; 1062d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod break; 1063d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1064d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1065d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod 1066deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) 10678e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 10688e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if (new_pos < end && is_joiner (info[new_pos])) 10698e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos++; 10708e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 10718e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 10728e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int old_pos = i; 1073e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (new_pos, old_pos + 1); 10748e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 10758e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0])); 10768e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[new_pos] = tmp; 10778e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 10788e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 10798e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 10808e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 108178818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod } 108246e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod } 1083eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1084eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1085a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod /* Apply 'init' to the Left Matra if it's a word start. */ 10866a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[start].indic_position () == POS_PRE_M && 1087a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod (!start || 1088eace47b173807d94b29a6490d0bc3c9f8f6168d1Behdad Esfahbod !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & 10892c372b80f6befad69e216e3f218b38640b8cc044Behdad Esfahbod FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))) 109085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[start].mask |= indic_plan->mask_array[INIT]; 1091a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod 1092eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 10938ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod /* 10948ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod * Finish off the clusters and go home! 10958ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod */ 1096decf6ffca475fe01ff3151b7641f629f031137d2Behdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 1097ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 109830c3d5e9fc61b49c2c6ad4e744300edd6f3e0261Behdad Esfahbod /* Uniscribe merges the entire cluster. 109921d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This means, half forms are submerged into the main consonants cluster. 110021d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This is unnecessary, and makes cursor positioning harder, but that's what 110121d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * Uniscribe does. */ 1102e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 110321d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod } 1104ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod} 1105e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1106e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1107ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbodstatic void 11088bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 110985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 11103e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1111ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod{ 1112ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int count = buffer->len; 1113ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod if (!count) return; 1114ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod 1115ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1116ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int last = 0; 1117cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1118ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1119cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod if (last_syllable != info[i].syllable()) { 112085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, i); 1121ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod last = i; 1122cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod last_syllable = info[last].syllable(); 1123ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod } 112485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, count); 1125e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 112680cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod /* Zero syllables now... */ 112780cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 112880cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod info[i].syllable() = 0; 112980cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod 1130743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); 1131743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); 1132743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1133743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1134743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1135693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = 1136693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{ 1137693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod "indic", 1138693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod collect_features_indic, 1139693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod override_features_indic, 1140a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_create_indic, 1141a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_destroy_indic, 11429f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod NULL, /* preprocess_text */ 1143693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod NULL, /* normalization_preference */ 1144693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod setup_masks_indic, 11451e7d860613032e40a3f90e2caa2ee5ac44ab8c8cBehdad Esfahbod false, /* zero_width_attached_marks */ 1146693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod}; 1147