hb-ot-shape-complex-indic.cc revision 6b389ddc3623d042ded4731f4d62dc354002fdd0
1b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod/* 227aba594c90b4444c35273a38f5fedc8e09d9a88Behdad Esfahbod * Copyright © 2011,2012 Google, Inc. 3b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 4b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * This is part of HarfBuzz, a text shaping library. 5b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 6b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * Permission is hereby granted, without written agreement and without 7b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this 8b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * software and its documentation for any purpose, provided that the 9b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * above copyright notice and the following two paragraphs appear in 10b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * all copies of this software. 11b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 12b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * DAMAGE. 17b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 18b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * 24b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod * Google Author(s): Behdad Esfahbod 25b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod */ 26b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 273ed4634ec349fa9e943ad23718c04be4dd4bba62Behdad Esfahbod#include "hb-ot-shape-complex-indic-private.hh" 2849c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod#include "hb-ot-layout-private.hh" 29352372ae5ea0998e40cf9fe43c22b6b610a5764eBehdad Esfahbod 301d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 3111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 3211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Global Indic shaper options. 3311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 341d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 35a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodstruct indic_options_t 36ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod{ 37a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod int initialized : 1; 38a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod int uniscribe_bug_compatible : 1; 39a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod}; 40a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 41a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodunion indic_options_union_t { 42a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod int i; 43a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod indic_options_t opts; 44a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod}; 45a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad EsfahbodASSERT_STATIC (sizeof (int) == sizeof (indic_options_union_t)); 46a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 47a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodstatic indic_options_union_t 48a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodindic_options_init (void) 49a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod{ 50a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod indic_options_union_t u; 51a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod u.i = 0; 52a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod u.opts.initialized = 1; 53a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 54a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod char *c = getenv ("HB_OT_INDIC_OPTIONS"); 55a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible"); 56a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 57a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod return u; 58a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod} 59a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 60a02d86484be870615297abfc7be9f94645434762Behdad Esfahbodstatic inline indic_options_t 61a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodindic_options (void) 62a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod{ 63a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod static indic_options_union_t options; 64a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 65a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (unlikely (!options.i)) { 66a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod /* This is idempotent and threadsafe. */ 67a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod options = indic_options_init (); 68ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 69ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod 70a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod return options.opts; 71a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod} 72a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 73ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod 7411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 7511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic configurations. Note that we do not want to keep every single script-specific 7611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * behavior in these tables necessarily. This should mainly be used for per-script 7711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * properties that are cheaper keeping here, than in the code. Ie. if, say, one and 7811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * only one script has an exception, that one script can be if'ed directly in the code, 7911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * instead of adding a new flag in these structs. 8011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 8111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 8211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum base_position_t { 8311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_FIRST, 8411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod BASE_POS_LAST 8511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 8611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_position_t { 8711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_DEFAULT = POS_BEFORE_POST, 8811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 8911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_MAIN = POS_AFTER_MAIN, 9011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_SUB = POS_BEFORE_SUB, 9111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_SUB = POS_AFTER_SUB, 9211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_BEFORE_POST = POS_BEFORE_POST, 9311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_POS_AFTER_POST = POS_AFTER_POST 9411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 9511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodenum reph_mode_t { 9611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_IMPLICIT, /* Reph formed out of initial Ra,H sequence. */ 9711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_EXPLICIT, /* Reph formed out of initial Ra,H,ZWJ sequence. */ 9811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */ 9911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod REPH_MODE_LOG_REPHA /* Encoded Repha character, needs reordering. */ 10011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 10111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstruct indic_config_t 10211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 10311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_script_t script; 10411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool has_old_spec; 10511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod hb_codepoint_t virama; 10611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base_position_t base_pos; 10711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos; 10811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_mode_t reph_mode; 10911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 11011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 11111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbodstatic const indic_config_t indic_configs[] = 11211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod{ 11311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Default. Should be first. */ 11411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_DEFAULT, REPH_MODE_IMPLICIT}, 11511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT}, 11611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_BENGALI, true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT}, 11711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_GURMUKHI, true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT}, 11811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_GUJARATI, true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT}, 11911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_ORIYA, true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT}, 12011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_TAMIL, true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT}, 12111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_TELUGU, true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT}, 12211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_KANNADA, true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT}, 12311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA}, 12411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT}, 12511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod {HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT, REPH_MODE_VIS_REPHA}, 12611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 12711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 12811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 12911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 13011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 13111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic shaper. 13211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 1339ccc6382ba43760167c134c18c1c4ada4b8c3f22Behdad Esfahbod 134eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstruct feature_list_t { 135c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_tag_t tag; 136c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_bool_t is_global; 137eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod}; 138eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 139eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstatic const feature_list_t 14085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodindic_features[] = 141b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 14285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 14385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Basic features. 14485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied in order, one at a time, after initial_reordering. 14585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 146c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('n','u','k','t'), true}, 147e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod {HB_TAG('a','k','h','n'), true}, 148c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('r','p','h','f'), false}, 1491ac075b227090a9ad930dcc1670236c176b27067Behdad Esfahbod {HB_TAG('r','k','r','f'), true}, 150c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('p','r','e','f'), false}, 151c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('h','a','l','f'), false}, 152167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod {HB_TAG('b','l','w','f'), false}, 15329f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod {HB_TAG('a','b','v','f'), false}, 154c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('p','s','t','f'), false}, 1550201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod {HB_TAG('c','f','a','r'), false}, 15620b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod {HB_TAG('c','j','c','t'), true}, 1571d6846db9ebf84561bb30a4e48c6c43184914099Behdad Esfahbod {HB_TAG('v','a','t','u'), true}, 15885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 15985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Other features. 16085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied all at once, after final_reordering. 16185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 16285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('i','n','i','t'), false}, 16385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('p','r','e','s'), true}, 16485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('a','b','v','s'), true}, 16585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('b','l','w','s'), true}, 16685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('p','s','t','s'), true}, 16785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('h','a','l','n'), true}, 16885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* Positioning features, though we don't care about the types. */ 16985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('d','i','s','t'), true}, 17085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('a','b','v','m'), true}, 17185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('b','l','w','m'), true}, 172c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod}; 173c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod 17485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod/* 17585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Must be in the same order as the indic_features array. 17685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 177c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbodenum { 178c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod _NUKT, 179e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod _AKHN, 180c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod RPHF, 181df6d45c693c417bf311e6fa49f18a8558542e525Behdad Esfahbod _RKRF, 182c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PREF, 183c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod HALF, 184167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod BLWF, 18529f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod ABVF, 186c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PSTF, 1870201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod CFAR, 18820b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod _CJCT, 18985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _VATU, 19085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 19185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INIT, 19285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PRES, 19385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVS, 19485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWS, 19585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PSTS, 19685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _HALN, 19785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _DIST, 19885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVM, 19985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWM, 20085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 20185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_NUM_FEATURES, 20285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */ 203b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod}; 204b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 205743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 206166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan, 207166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font, 208166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer); 209166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 2108bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 211afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 2123e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 213f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbodstatic void 2148bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 215afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 2163e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 217b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 218693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 21916c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodcollect_features_indic (hb_ot_shape_planner_t *plan) 220b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 22116c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_ot_map_builder_t *map = &plan->map; 22216c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod 223166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Do this before any lookups have been applied. */ 224166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod map->add_gsub_pause (setup_syllables); 225166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 226f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_bool_feature (HB_TAG('l','o','c','l')); 227a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod /* The Indic specs do not require ccmp, but we apply it here since if 228a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod * there is a use of it, it's typically at the beginning. */ 229f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_bool_feature (HB_TAG('c','c','m','p')); 230f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 231f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 23285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod unsigned int i = 0; 23385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_gsub_pause (initial_reordering); 23485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_BASIC_FEATURES; i++) { 23585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); 2363e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (NULL); 237412b91889d9a1ae477e8b6907d0b9a76e78a6c91Behdad Esfahbod } 2383e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (final_reordering); 23985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_NUM_FEATURES; i++) { 24085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); 24185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 242b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 243b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 244693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 24516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodoverride_features_indic (hb_ot_shape_planner_t *plan) 246d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod{ 247af92b4cc90e4184d5bdd8037c551ed482700114fBehdad Esfahbod /* Uniscribe does not apply 'kern'. */ 248af92b4cc90e4184d5bdd8037c551ed482700114fBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 24916c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true); 2506b389ddc3623d042ded4731f4d62dc354002fdd0Behdad Esfahbod 2516b389ddc3623d042ded4731f4d62dc354002fdd0Behdad Esfahbod plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true); 252d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod} 253d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod 254867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 25585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodstruct would_substitute_feature_t 256a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 25785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag) 258a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 259a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_stage_lookups (0/*GSUB*/, 260a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_feature_stage (0/*GSUB*/, feature_tag), 261a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod &lookups, &count); 262a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 263a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 264a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod inline bool would_substitute (hb_codepoint_t *glyphs, 265a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int glyphs_count, 266b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod bool zero_context, 267a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_face_t *face) const 268a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 269a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 270b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (hb_ot_layout_would_substitute_lookup_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) 271a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return true; 272a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return false; 273a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 274a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 275a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod private: 276a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const hb_ot_map_t::lookup_map_t *lookups; 277a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int count; 278a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 279a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 280a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstruct indic_shape_plan_t 281a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 28285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod ASSERT_POD (); 283914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 284914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const 285914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 286914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod hb_codepoint_t glyph = virama_glyph; 287914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (unlikely (virama_glyph == (hb_codepoint_t) -1)) 288914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 28911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!config->virama || !font->get_glyph (config->virama, 0, &glyph)) 290914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod glyph = 0; 291914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Technically speaking, the spec says we should apply 'locl' to virama too. 292914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * Maybe one day... */ 293914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 294914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Our get_glyph() function needs a font, so we can't get the virama glyph 295914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */ 296914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph; 297914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 298914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 299914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod *pglyph = glyph; 300914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod return glyph != 0; 301914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 30285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 30311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod const indic_config_t *config; 30485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 30585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod bool is_old_spec; 30685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_codepoint_t virama_glyph; 30785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 30885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pref; 30985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t blwf; 31085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pstf; 31185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 31285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_mask_t mask_array[INDIC_NUM_FEATURES]; 313a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 314a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 315a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void * 316a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_create_indic (const hb_ot_shape_plan_t *plan) 317a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 31885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t)); 31985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (unlikely (!indic_plan)) 320a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return NULL; 321a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 32211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[0]; 32311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++) 32411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (plan->props.script == indic_configs[i].script) { 32511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[i]; 32611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 32785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 32811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 32911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.get_chosen_script (0) & 0x000000FF) != '2'); 33011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->virama_glyph = (hb_codepoint_t) -1; 33185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 33285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f')); 33385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f')); 33485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f')); 33585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 33685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) 33785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->mask_array[i] = indic_features[i].is_global ? 0 : plan->map.get_1_mask (indic_features[i].tag); 338a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 33985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod return indic_plan; 340a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 341a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 342a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void 343a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_destroy_indic (void *data) 344a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 345a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod free (data); 346a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 347a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 348a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic indic_position_t 349a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodconsonant_position_from_face (const indic_shape_plan_t *indic_plan, 350a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_codepoint_t *glyphs, unsigned int glyphs_len, 351a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_face_t *face) 352a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 353b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod bool zero_context = indic_plan->is_old_spec ? false : true; 354b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C; 355b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->blwf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C; 356b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->pstf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_POST_C; 357a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return POS_BASE_C; 358a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 359a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 360a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 361166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodenum syllable_type_t { 362166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod consonant_syllable, 363166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod vowel_syllable, 364166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod standalone_cluster, 365166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod broken_cluster, 366166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod non_indic_cluster, 367166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod}; 368166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 369166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod#include "hb-ot-shape-complex-indic-machine.hh" 370166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 371166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 372693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 37316c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodsetup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, 37416c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_buffer_t *buffer, 37516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_font_t *font HB_UNUSED) 37624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 37724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); 37824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); 37924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 38024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod /* We cannot setup masks here. We save information about characters 38124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod * and setup masks later on in a pause-callback. */ 38224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 38324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod unsigned int count = buffer->len; 38424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 38524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod set_indic_properties (buffer->info[i]); 38624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 38724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 388166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 389166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, 390166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font HB_UNUSED, 391166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer) 392166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod{ 393166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod find_syllables (buffer); 394166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod} 395166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 39624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic int 39724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodcompare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 39824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 39924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int a = pa->indic_position(); 40024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int b = pb->indic_position(); 40124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 40224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod return a < b ? -1 : a == b ? 0 : +1; 40324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 40424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 40524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 40624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 40724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic void 4088bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodupdate_consonant_positions (const hb_ot_shape_plan_t *plan, 40985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 41085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer) 4118ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod{ 412a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 4138ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 414a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int consonant_pos = indic_plan->is_old_spec ? 0 : 1; 4158ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_codepoint_t glyphs[2]; 416914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->get_virama_glyph (font, &glyphs[1 - consonant_pos])) 4178ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod { 4188ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_face_t *face = font->face; 4198ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod unsigned int count = buffer->len; 4208ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 4218ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod if (buffer->info[i].indic_position() == POS_BASE_C) { 42224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod glyphs[consonant_pos] = buffer->info[i].codepoint; 423a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, 2, face); 4248ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 4258ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 4268ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod} 4278ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 428867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 4297ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod/* Rules from: 4307ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ 4317ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod 432743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 43385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodinitial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, 434ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 435743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 436914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 437ee58f3bc75d2d071a71b94063bf12205a5871acbBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 438743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 439617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod 440743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 1. Find base consonant: 441743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 442743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The shaping engine finds the base consonant of the syllable, using the 443743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following algorithm: starting from the end of the syllable, move backwards 444743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * until a consonant is found that does not have a below-base or post-base 445743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * form (post-base forms have to follow below-base forms), or that is not a 446743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * pre-base reordering Ra, or arrive at the first consonant. The consonant 447743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * stopped at will be the base. 448743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 449743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o If the syllable starts with Ra + Halant (in a script that has Reph) 450743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 451743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * base consonants. 452743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 453743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 4545e72071062c015237b79fbd0521341a63166a204Behdad Esfahbod unsigned int base = end; 45576b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod bool has_reph = false; 456743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 45776b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod { 458617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 459617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 460617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * base consonants. */ 461617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod unsigned int limit = start; 46285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[RPHF] && 463617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod start + 3 <= end && 464617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod info[start].indic_category() == OT_Ra && 465617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod info[start + 1].indic_category() == OT_H && 46611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (/* TODO Handle other Reph modes. */ 46711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || 46811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ) 4693285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod )) 470617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod { 471617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod limit += 2; 4723285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 4733285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod limit++; 474617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod base = start; 475617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = true; 476617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod }; 47776b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod 47823b0e9d7dc801e11640979af3c2b00649a519bb1Behdad Esfahbod switch (indic_plan->config->base_pos) 4795d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 48011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_LAST: 48111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 48211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> starting from the end of the syllable, move backwards */ 48311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int i = end; 48411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool seen_below = false; 48511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod do { 48611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod i--; 48711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> until a consonant is found */ 48811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i])) 4895d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 49011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> that does not have a below-base or post-base form 49111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * (post-base forms have to follow below-base forms), */ 49211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() != POS_BELOW_C && 49311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (info[i].indic_position() != POS_POST_C || seen_below)) 49411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 49511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 49611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 49711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 49811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() == POS_BELOW_C) 49911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod seen_below = true; 50011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 50111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or that is not a pre-base reordering Ra, 50211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 50311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * IMPLEMENTATION NOTES: 50411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 50511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Our pre-base reordering Ra's are marked POS_BELOW, so will be skipped 50611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * by the logic above already. 50711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 50811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 50911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or arrive at the first consonant. The consonant stopped at will 51011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * be the base. */ 5115d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod base = i; 5125d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 51311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 51411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 51511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* A ZWJ after a Halant stops the base search, and requests an explicit 51611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * half form. 51711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * A ZWJ before a Halant, requests a subjoined form instead, and hence 51811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * search continues. This is particularly important for Bengali 51911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * sequence Ra,H,Ya that shouls form Ya-Phalaa by subjoining Ya. */ 52011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (start < i && 52111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_category() == OT_ZWJ && 52211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i - 1].indic_category() == OT_H) 52311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 52411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 52511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } while (i > limit); 52611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 52711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 5285d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 52911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_FIRST: 53011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 53111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* In scripts without half forms (eg. Khmer), the first consonant is always the base. */ 5325d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 53311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!has_reph) 53411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = limit; 53534c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 53611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Find the last base consonant that is not blocked by ZWJ. If there is 53711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * a ZWJ right before a base consonant, that would request a subjoined form. */ 53811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = limit; i < end; i++) 53911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 54011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 54111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (limit < i && info[i - 1].indic_category() == OT_ZWJ) 54211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 54311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 54411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 54511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 54634c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 54711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Mark all subsequent consonants as below. */ 54811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 54911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 55011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_position() = POS_BELOW_C; 55111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 55211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 55311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 55411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod default: 55511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod abort (); 5565d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 557743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 558617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 559617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 5602278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * base consonants. 5612278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * 5622278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ 5632278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod if (has_reph && base == start && start + 2 == limit) { 564617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* Have no other consonant, so Reph is not formed and Ra becomes base. */ 565617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = false; 566617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod } 5675e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod } 5682278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod 56934c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod if (base < end) 57034c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod info[base].indic_position() = POS_BASE_C; 5713d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 5723d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 573743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 2. Decompose and reorder Matras: 574743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 575743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Each matra and any syllable modifier sign in the cluster are moved to the 576743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * appropriate position relative to the consonant(s) in the cluster. The 577743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * shaping engine decomposes two- or three-part matras into their constituent 578743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * parts before any repositioning. Matra characters are classified by which 579743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * consonant in a conjunct they have affinity for and are reordered to the 580743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following positions: 581743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 582743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o Before first half form in the syllable 583743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After subjoined consonants 584743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After post-form consonant 585743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After main consonant (for above marks) 586743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 587743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 588743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 589743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The normalize() routine has already decomposed matras for us, so we don't 590743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * need to worry about that. 591743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 592743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 593743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 594743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 3. Reorder marks to canonical order: 595743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 596743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Adjacent nukta and halant or nukta and vedic sign are always repositioned 597743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * if necessary, so that the nukta is first. 598743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 599743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 600743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 601743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * We don't need to do this: the normalize() routine already did this for us. 602743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 603743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 604743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 60545d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod /* Reorder characters */ 60645d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 6073c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 608900cf3d449bf36d4f8b1474590cae925fef48fc8Behdad Esfahbod info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position()); 60955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 610075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 611075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].indic_position() = POS_BASE_C; 61245d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 61355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod /* Mark final consonants. A final consonant is one appearing after a matra, 61455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod * like in Khmer. */ 61555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 61655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (info[i].indic_category() == OT_M) { 61755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int j = i + 1; j < end; j++) 61855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (is_consonant (info[j])) { 61955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod info[j].indic_position() = POS_FINAL_C; 62055f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 62155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 62255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 62355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 62455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 625fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod /* Handle beginning Ra */ 6265e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod if (has_reph) 627dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() = POS_RA_TO_BECOME_REPH; 628fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod 629f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* For old-style Indic script tags, move the first post-base Halant after 630f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod * last consonant. */ 631914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->is_old_spec) { 6323c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 633f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (info[i].indic_category() == OT_H) { 634f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod unsigned int j; 635f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod for (j = end - 1; j > i; j--) 636190eb31a16178269aecaf5d2ecc9012f956749f4Behdad Esfahbod if (is_consonant (info[j])) 637f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 638f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (j > i) { 639f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* Move Halant to after last consonant. */ 640f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod hb_glyph_info_t t = info[i]; 641f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); 642f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod info[j] = t; 643f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 644f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 645f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 646f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 647f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod 64881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* Attach misc marks to previous char to move with them. */ 649ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 65081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod indic_position_t last_pos = POS_START; 65181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod for (unsigned int i = start; i < end; i++) 65281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 65381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS))) 65481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 65581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() = last_pos; 65681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if (unlikely (indic_options ().uniscribe_bug_compatible && 65781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_category() == OT_H && 65881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() == POS_PRE_M)) 65981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 66081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* 66181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * Uniscribe doesn't move the Halant with Left Matra. 66281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * TEST: U+092B,U+093F,U+094DE 66381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod */ 664ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod for (unsigned int j = i; j > start; j--) 6656a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[j - 1].indic_position() != POS_PRE_M) { 666ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod info[i].indic_position() = info[j - 1].indic_position(); 667ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod break; 668ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 66981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 67081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } else if (info[i].indic_position() != POS_SMVD) { 67181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod last_pos = (indic_position_t) info[i].indic_position(); 672ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 67381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 674ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 67574ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod /* Re-attach ZWJ, ZWNJ, and halant to next char, for after-base consonants. */ 67674ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod { 67774ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod unsigned int last_halant = end; 67874ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 679deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (is_halant_or_coeng (info[i])) 68074ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod last_halant = i; 68174ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod else if (is_consonant (info[i])) { 68274ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int j = last_halant; j < i; j++) 68381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if (info[j].indic_position() != POS_SMVD) 68481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[j].indic_position() = info[i].indic_position(); 68574ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 68674ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 68745d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 688a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod { 6897b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod /* Things are out-of-control for post base positions, they may shuffle 6907b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * around like crazy, so merge clusters. For pre-base stuff, we handle 6917b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * cluster issues in final reordering. */ 6927b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod buffer->merge_clusters (base, end); 693a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Sit tight, rock 'n roll! */ 694d3637edb248162970e202e9d0671540274192844Behdad Esfahbod hb_bubble_sort (info + start, end - start, compare_indic_order); 695a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Find base again */ 696a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = end; 6973c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < end; i++) 698a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod if (info[i].indic_position() == POS_BASE_C) { 699a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = i; 700a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod break; 701a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 702a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 70345d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 704743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Setup masks now */ 705743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 706281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod { 707281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod hb_mask_t mask; 708281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod 709dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* Reph */ 710668c6046c1b3af3bd316bda0cc8636f2a5e8df42Behdad Esfahbod for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) 71185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[RPHF]; 712dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 713281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Pre-base */ 71485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[HALF]; 7153c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 716281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 717281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Base */ 71820b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = 0; 719075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 720075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].mask |= mask; 721281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Post-base */ 72285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF]; 7233c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 724281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 725281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod } 7269da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 72785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 2 < end) 72817d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod { 729771a8f50289e8fa458cfc3cd84f73a380ce98077Behdad Esfahbod /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ 7308e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i + 1 < end; i++) 7316732d62e78b13842ead9549c97bede25c73976cbBehdad Esfahbod if (is_halant_or_coeng (info[i + (indic_plan->is_old_spec ? 1 : 0)]) && 7326732d62e78b13842ead9549c97bede25c73976cbBehdad Esfahbod info[i + (indic_plan->is_old_spec ? 0 : 1)].indic_category() == OT_Ra) 7338e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 73485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 73585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 7360201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 7370201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod /* Mark the subsequent stuff with 'cfar'. Used in Khmer. 7380201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * Read the feature spec. 7390201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * This allows distinguishing the following cases with MS Khmer fonts: 7400201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+179A,U+17D2,U+1782 7410201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+1782,U+17D2,U+179A 7420201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod */ 7430201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod for (; i < end; i++) 74485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[CFAR]; 7450201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 7468e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 7478e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 74817d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod } 74917d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod 7509da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod /* Apply ZWJ/ZWNJ effects */ 7513c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start + 1; i < end; i++) 7529da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod if (is_joiner (info[i])) { 7539da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod bool non_joiner = info[i].indic_category() == OT_ZWNJ; 7546b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod unsigned int j = i; 7559da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 7569da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod do { 7579da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod j--; 7586b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 75920b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWJ disables CJCT, however, it's mere presence is enough 76020b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod * to disable ligation. No explicit action needed. */ 76120b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod 76220b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWNJ disables HALF. */ 7636b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod if (non_joiner) 76485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[j].mask &= ~indic_plan->mask_array[HALF]; 7656b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 7669da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } while (j > start && !is_consonant (info[j])); 7679da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } 768743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 769743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 770743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 771743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7728bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan, 7739f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 774ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 775743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 776c5306b6861cfaa50af40e8ceb058791fa06d7981Behdad Esfahbod /* We made the vowels look like consonants. So let's call the consonant logic! */ 77785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod initial_reordering_consonant_syllable (plan, buffer, start, end); 778743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 779743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 780743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7818bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, 7829f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 783ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 784743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 78518c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain. 78618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Only if not in compatibility mode that is... */ 78718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 788a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 78918c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod { 79018c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* For dotted-circle, this is what Uniscribe does: 79118c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * If dotted-circle is the last glyph, it just does nothing. 79218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Ie. It doesn't form Reph. */ 79318c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) 79418c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod return; 79518c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod } 79618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 79785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod initial_reordering_consonant_syllable (plan, buffer, start, end); 798743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 799743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 800743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 801b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodinitial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan, 802b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer, 803b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int start, unsigned int end) 804b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 805b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod /* We already inserted dotted-circles, so just call the standalone_cluster. */ 806b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod initial_reordering_standalone_cluster (plan, buffer, start, end); 807b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 808b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 809b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 810327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 811327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 812327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 813743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 814743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 815743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 816743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 817743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 818327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 819743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 820327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_syllable (const hb_ot_shape_plan_t *plan, 821327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer, 822327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start, unsigned int end) 823327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod{ 824327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); 825327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod switch (syllable_type) { 826327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod case consonant_syllable: initial_reordering_consonant_syllable (plan, buffer, start, end); return; 827327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod case vowel_syllable: initial_reordering_vowel_syllable (plan, buffer, start, end); return; 828327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod case standalone_cluster: initial_reordering_standalone_cluster (plan, buffer, start, end); return; 829b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod case broken_cluster: initial_reordering_broken_cluster (plan, buffer, start, end); return; 830327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod case non_indic_cluster: initial_reordering_non_indic_cluster (plan, buffer, start, end); return; 831327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 832327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod} 833327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 834166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic inline void 835b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodinsert_dotted_circles (const hb_ot_shape_plan_t *plan, 836b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_font_t *font, 837b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer) 838b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 839166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Note: This loop is extra overhead, but should not be measurable. */ 840166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod bool has_broken_syllables = false; 841166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod unsigned int count = buffer->len; 842166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod for (unsigned int i = 0; i < count; i++) 843166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) { 844166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod has_broken_syllables = true; 845166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod break; 846166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod } 847166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if (likely (!has_broken_syllables)) 848166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod return; 849166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 850166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 851b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_codepoint_t dottedcircle_glyph; 852b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) 853b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return; 854b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 855b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_glyph_info_t dottedcircle; 856b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = 0x25CC; 857b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod set_indic_properties (dottedcircle); 858b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = dottedcircle_glyph; 859b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 860b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->clear_output (); 861b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 862b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->idx = 0; 863b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int last_syllable = 0; 864b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod while (buffer->idx < buffer->len) 865b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 866b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int syllable = buffer->cur().syllable(); 867b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); 868b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) 869b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 870b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_glyph_info_t info = dottedcircle; 871b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.cluster = buffer->cur().cluster; 872b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.mask = buffer->cur().mask; 873b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.syllable() = buffer->cur().syllable(); 874b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->output_info (info); 875b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod last_syllable = syllable; 876b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 877b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->next_glyph (); 878b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 879b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 880b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->swap_buffers (); 881b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 882b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 883b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 8848bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 88524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod hb_font_t *font, 8863e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 887743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 88885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod update_consonant_positions (plan, font, buffer); 889166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod insert_dotted_circles (plan, font, buffer); 890327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 891327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 892b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int count = buffer->len; 893b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (!count)) return; 894327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last = 0; 895327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 896327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 897327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (last_syllable != info[i].syllable()) { 898327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod initial_reordering_syllable (plan, buffer, last, i); 899327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last = i; 900327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last_syllable = info[last].syllable(); 901327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 902327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod initial_reordering_syllable (plan, buffer, last, count); 903b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 904b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 905743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 90685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodfinal_reordering_syllable (const hb_ot_shape_plan_t *plan, 90785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer, 908ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 909743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 91085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 9114ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 9124ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 913e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod /* 4. Final reordering: 914e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 915e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * After the localized forms and basic shaping forms GSUB features have been 916e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * applied (see below), the shaping engine performs some final glyph 917e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * reordering before applying all the remaining font features to the entire 918e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * cluster. 9194ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 9204ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 9214ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* Find base again */ 9225f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod unsigned int base; 9235f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod for (base = start; base < end; base++) 9245f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (info[base].indic_position() >= POS_BASE_C) { 9255f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (start < base && info[base].indic_position() > POS_BASE_C) 9265f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod base--; 9275f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod break; 9285f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod } 9294ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 9304705a7026900e51f6430f03a73c87f2df035df92Behdad Esfahbod 9314ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder matras: 932e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 933e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base matra character had been reordered before applying basic 934e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * features, the glyph can be moved closer to the main consonant based on 935e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * whether half-forms had been formed. Actual position for the matra is 936e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * defined as “after last standalone halant glyph, after initial matra 937e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * position and before the main consonant”. If ZWJ or ZWNJ follow this 938e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * halant, position is moved after it. 9394ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 9404ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 94165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ 9429d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 94365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we lost track of base, alas, position before last thingy. */ 94465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod unsigned int new_pos = base == end ? base - 2 : base - 1; 94565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 94627bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 94727bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 94827bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * We want to position matra after them. 94965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod */ 95027bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 951e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod { 95265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod while (new_pos > start && 95365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng))))) 95465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos--; 95565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 95665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we found no Halant we are done. 95765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * Otherwise only proceed if the Halant does 95865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * not belong to the Matra itself! */ 95965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (is_halant_or_coeng (info[new_pos]) && 96065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod info[new_pos].indic_position() != POS_PRE_M) 96165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 96265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 96365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) 96465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos++; 96565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 96665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod else 96765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos = start; /* No move. */ 96865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 9699d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod 97027bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M) 97165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 9729d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* Now go see if there's actually any matras... */ 973921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod for (unsigned int i = new_pos; i > start; i--) 9746a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[i - 1].indic_position () == POS_PRE_M) 9759d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 9761a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod unsigned int old_pos = i - 1; 9771a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 9781a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0])); 9791a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod info[new_pos] = tmp; 980921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod new_pos--; 9819d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 9822cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (new_pos, MIN (end, base + 1)); 983abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } else { 984e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod for (unsigned int i = start; i < base; i++) 985abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod if (info[i].indic_position () == POS_PRE_M) { 9862cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (i, MIN (end, base + 1)); 987abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod break; 988abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } 9899d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 9904ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod } 9914ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 9924ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 9934ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder reph: 994e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 995e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Reph’s original position is always at the beginning of the syllable, 996e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * (i.e. it is not reordered at the character reordering stage). However, 997e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * it will be reordered according to the basic-forms shaping results. 998e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Possible positions for reph, depending on the script, are; after main, 999e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * before post-base consonant forms, and after post-base consonant forms. 1000dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 1001dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1002dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* If there's anything after the Ra that has the REPH pos, it ought to be halant. 1003dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Which means that the font has failed to ligate the Reph. In which case, we 1004dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * shouldn't move. */ 1005dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod if (start + 1 < end && 1006dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() == POS_RA_TO_BECOME_REPH && 1007dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH) 1008dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod { 100911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int new_reph_pos; 101011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos = indic_plan->config->reph_pos; 101111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 101211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* XXX Figure out old behavior too */ 101302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1014dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* 1. If reph should be positioned after post-base consonant forms, 1015dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to step 5. 101602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 101711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_POST) 101802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 10199d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_step_5; 102002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 102102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 102202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 2. If the reph repositioning class is not after post-base: target 1023dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is after the first explicit halant glyph between the 1024dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-reph consonant and last main consonant. If ZWJ or ZWNJ 1025dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * are following this halant, position is moved after it. If such 1026dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is found, this is the target position. Otherwise, 1027dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to the next step. 1028dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * 1029dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Note: in old-implementation fonts, where classifications were 1030dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * fixed in shaping engine, there was no case where reph position 1031dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * will be found on this step. 103202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 103302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 103402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = start + 1; 1035deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 103602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 103702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1038deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 103902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 104002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 104102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 104202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 104302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 104402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 104502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 104602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 3. If reph should be repositioned after the main consonant: find the 1047dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first consonant not ligated with main, or find the first 1048dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant that is not a potential pre-base reordering Ra. 104902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 105011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_MAIN) 105102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1052b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos = base; 1053b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod /* XXX Skip potential pre-base reordering Ra. */ 105434ae336f3fae93ef9372881d545c817bce383041Behdad Esfahbod while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN) 1055b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos++; 1056b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod if (new_reph_pos < end) 1057b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod goto reph_move; 105802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 105902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 106002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 4. If reph should be positioned before post-base consonant, find 1061dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-base classified consonant not ligated with main. If no 1062dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant is found, the target position should be before the 1063dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first matra, syllable modifier sign or vedic sign. 106402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 10659d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* This is our take on what step 4 is trying to say (and failing, BADLY). */ 106611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_SUB) 106702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 10689d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos = base; 10699d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod while (new_reph_pos < end && 1070be8b9f5f715f6fb36b98bd33c3303f79cc068f8aBehdad Esfahbod !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD)))) 10719d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos++; 10729d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (new_reph_pos < end) 10739d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_move; 107402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 107502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 107602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 5. If no consonant is found in steps 3 or 4, move reph to a position 1077dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * immediately before the first post-base matra, syllable modifier 1078dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * sign or vedic sign that has a reordering class after the intended 1079dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * reph position. For example, if the reordering position for reph 1080dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * is post-main, it will skip above-base matras that also have a 1081dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * post-main position. 1082dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 108302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_step_5: 108402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1085d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* Copied from step 2. */ 1086d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos = start + 1; 1087d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 1088d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1089d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod 1090d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 1091d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 1092d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 1093d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1094d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod goto reph_move; 1095d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod } 109602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1097dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 109802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 6. Otherwise, reorder reph to the end of the syllable. 109902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 110002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 110102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = end - 1; 110202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD) 110302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 110402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1105892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod /* 1106892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * If the Reph is to be ending up after a Matra,Halant sequence, 1107892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * position it before that Halant so it can interact with the Matra. 1108892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * However, if it's a plain Consonant,Halant we shouldn't do that. 1109892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * Uniscribe doesn't do this. 1110892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * TEST: U+0930,U+094D,U+0915,U+094B,U+094D 1111892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod */ 1112a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (!indic_options ().uniscribe_bug_compatible && 1113deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod unlikely (is_halant_or_coeng (info[new_reph_pos]))) { 111402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod for (unsigned int i = base + 1; i < new_reph_pos; i++) 111502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (info[i].indic_category() == OT_M) { 111602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Ok, got it. */ 111702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 111802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 111902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 112002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 11218df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod } 11228df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod 112302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_move: 112402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1125e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod /* Yay, one big cluster! Merge before moving. */ 1126e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 1127e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod 112802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Move */ 112902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod hb_glyph_info_t reph = info[start]; 113002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0])); 113102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod info[new_reph_pos] = reph; 113202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1133dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod } 1134dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1135dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1136dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* o Reorder pre-base reordering consonants: 1137e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1138e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base reordering consonant is found, reorder it according to 1139e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * the following rules: 1140e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod */ 1141e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 114285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ 114346e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod { 11448e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 114585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) 114678818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod { 11478e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 1. Only reorder a glyph produced by substitution during application 11488e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * of the <pref> feature. (Note that a font may shape a Ra consonant with 11498e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * the feature generally but block it in certain contexts.) 11508e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 115185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (i + 1 == end || (info[i + 1].mask & indic_plan->mask_array[PREF]) == 0) 11528e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 11538e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 11548e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 2. Try to find a target position the same way as for pre-base matra. 11558e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * If it is found, reorder pre-base consonant glyph. 11568e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 11578e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 3. If position is not found, reorder immediately before main 11588e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * consonant. 11598e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 11608e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 11618e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int new_pos = base; 116288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 116388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 116488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * We want to position matra after them. 116588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod */ 116688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1167d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 116888d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod while (new_pos > start && 116988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS))) 117088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 117188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod 117288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* In Khmer coeng model, a V,Ra can go *after* matras. If it goes after a 117388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * split matra, it should be reordered to *before* the left part of such matra. */ 117488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) 117588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 117688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod unsigned int old_pos = i; 117788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod for (unsigned int i = base + 1; i < old_pos; i++) 117888d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (info[i].indic_category() == OT_M) 117988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 118088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 118188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod break; 118288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 118388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 1184d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1185d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod 1186deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) 11878e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 11888e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if (new_pos < end && is_joiner (info[new_pos])) 11898e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos++; 11908e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 11918e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 11928e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int old_pos = i; 1193e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (new_pos, old_pos + 1); 11948e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 11958e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0])); 11968e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[new_pos] = tmp; 11978e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 11988e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 11998e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 12008e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 120178818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod } 120246e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod } 1203eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1204eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1205a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod /* Apply 'init' to the Left Matra if it's a word start. */ 12066a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[start].indic_position () == POS_PRE_M && 1207a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod (!start || 1208eace47b173807d94b29a6490d0bc3c9f8f6168d1Behdad Esfahbod !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & 12092c372b80f6befad69e216e3f218b38640b8cc044Behdad Esfahbod FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))) 121085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[start].mask |= indic_plan->mask_array[INIT]; 1211a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod 1212eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 12138ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod /* 12148ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod * Finish off the clusters and go home! 12158ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod */ 1216decf6ffca475fe01ff3151b7641f629f031137d2Behdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 1217ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 121830c3d5e9fc61b49c2c6ad4e744300edd6f3e0261Behdad Esfahbod /* Uniscribe merges the entire cluster. 121921d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This means, half forms are submerged into the main consonants cluster. 122021d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This is unnecessary, and makes cursor positioning harder, but that's what 122121d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * Uniscribe does. */ 1222e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 122321d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod } 1224ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod} 1225e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1226e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1227ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbodstatic void 12288bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 122985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 12303e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1231ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod{ 1232ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int count = buffer->len; 1233327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (unlikely (!count)) return; 1234ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod 1235ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1236ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int last = 0; 1237cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1238ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1239cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod if (last_syllable != info[i].syllable()) { 124085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, i); 1241ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod last = i; 1242cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod last_syllable = info[last].syllable(); 1243ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod } 124485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, count); 1245e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 124680cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod /* Zero syllables now... */ 124780cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 124880cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod info[i].syllable() = 0; 124980cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod 1250743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); 1251743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); 1252743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1253743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1254743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1255b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic hb_ot_shape_normalization_mode_t 1256b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodnormalization_preference_indic (const hb_ot_shape_plan_t *plan) 1257b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1258b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT; 1259b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1260b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1261693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = 1262693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{ 1263693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod "indic", 1264693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod collect_features_indic, 1265693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod override_features_indic, 1266a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_create_indic, 1267a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_destroy_indic, 12689f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod NULL, /* preprocess_text */ 1269b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod normalization_preference_indic, 1270693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod setup_masks_indic, 12711e7d860613032e40a3f90e2caa2ee5ac44ab8c8cBehdad Esfahbod false, /* zero_width_attached_marks */ 1272693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod}; 1273