hb-ot-shape-complex-indic.cc revision 43b653150081a2f9dc6b7481229ac4cd952575dc
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}, 1268173f23f3f16972c2e8e0a120724533100acfda2Behdad Esfahbod /* Myanmar does not have the "old_indic" behavior, even though it has a "new" tag. */ 1278173f23f3f16972c2e8e0a120724533100acfda2Behdad Esfahbod {HB_SCRIPT_MYANMAR, false, 0x1039,BASE_POS_LAST, REPH_POS_DEFAULT, REPH_MODE_EXPLICIT}, 12811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod}; 12911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 13011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 13111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 13211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod/* 13311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Indic shaper. 13411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 1359ccc6382ba43760167c134c18c1c4ada4b8c3f22Behdad Esfahbod 136eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstruct feature_list_t { 137c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_tag_t tag; 138c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_bool_t is_global; 139eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod}; 140eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 141eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstatic const feature_list_t 14285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodindic_features[] = 143b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 14485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 14585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Basic features. 14685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied in order, one at a time, after initial_reordering. 14785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 148c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('n','u','k','t'), true}, 149e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod {HB_TAG('a','k','h','n'), true}, 150c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('r','p','h','f'), false}, 1511ac075b227090a9ad930dcc1670236c176b27067Behdad Esfahbod {HB_TAG('r','k','r','f'), true}, 152c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('p','r','e','f'), false}, 153c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('h','a','l','f'), false}, 154167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod {HB_TAG('b','l','w','f'), false}, 15529f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod {HB_TAG('a','b','v','f'), false}, 156c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('p','s','t','f'), false}, 1570201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod {HB_TAG('c','f','a','r'), false}, 15820b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod {HB_TAG('c','j','c','t'), true}, 1591d6846db9ebf84561bb30a4e48c6c43184914099Behdad Esfahbod {HB_TAG('v','a','t','u'), true}, 16085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* 16185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Other features. 16285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * These features are applied all at once, after final_reordering. 16385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 16485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('i','n','i','t'), false}, 16585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('p','r','e','s'), true}, 16685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('a','b','v','s'), true}, 16785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('b','l','w','s'), true}, 16885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('p','s','t','s'), true}, 16985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('h','a','l','n'), true}, 17085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod /* Positioning features, though we don't care about the types. */ 17185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('d','i','s','t'), true}, 17285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('a','b','v','m'), true}, 17385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod {HB_TAG('b','l','w','m'), true}, 174c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod}; 175c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod 17685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod/* 17785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod * Must be in the same order as the indic_features array. 17885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod */ 179c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbodenum { 180c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod _NUKT, 181e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod _AKHN, 182c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod RPHF, 183df6d45c693c417bf311e6fa49f18a8558542e525Behdad Esfahbod _RKRF, 184c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PREF, 185c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod HALF, 186167b625d988b74572d6b2f646c285b666b650d49Behdad Esfahbod BLWF, 18729f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod ABVF, 188c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PSTF, 1890201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod CFAR, 19020b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod _CJCT, 19185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _VATU, 19285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 19385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INIT, 19485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PRES, 19585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVS, 19685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWS, 19785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _PSTS, 19885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _HALN, 19985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _DIST, 20085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _ABVM, 20185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod _BLWM, 20285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 20385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_NUM_FEATURES, 20485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */ 205b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod}; 206b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 207743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 208166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan, 209166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font, 210166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer); 211166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 2128bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 213afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 2143e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 215f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbodstatic void 2168bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 217afbcc24be01a64bdb5c05c63880269145fa1d3c8Behdad Esfahbod hb_font_t *font, 2183e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer); 219b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 220693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 22116c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodcollect_features_indic (hb_ot_shape_planner_t *plan) 222b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 22316c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_ot_map_builder_t *map = &plan->map; 22416c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod 225166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Do this before any lookups have been applied. */ 226166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod map->add_gsub_pause (setup_syllables); 227166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 228f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_bool_feature (HB_TAG('l','o','c','l')); 229a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod /* The Indic specs do not require ccmp, but we apply it here since if 230a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod * there is a use of it, it's typically at the beginning. */ 231f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_bool_feature (HB_TAG('c','c','m','p')); 232f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 233f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 23485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod unsigned int i = 0; 23585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_gsub_pause (initial_reordering); 23685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_BASIC_FEATURES; i++) { 23785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); 2383e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (NULL); 239412b91889d9a1ae477e8b6907d0b9a76e78a6c91Behdad Esfahbod } 2403e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (final_reordering); 24185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (; i < INDIC_NUM_FEATURES; i++) { 24285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); 24385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 244b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 245b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 246693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 24716c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodoverride_features_indic (hb_ot_shape_planner_t *plan) 248d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod{ 249af92b4cc90e4184d5bdd8037c551ed482700114fBehdad Esfahbod /* Uniscribe does not apply 'kern'. */ 250af92b4cc90e4184d5bdd8037c551ed482700114fBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 25116c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true); 2526b389ddc3623d042ded4731f4d62dc354002fdd0Behdad Esfahbod 2536b389ddc3623d042ded4731f4d62dc354002fdd0Behdad Esfahbod plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true); 254d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod} 255d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod 256867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 25785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodstruct would_substitute_feature_t 258a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 25985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag) 260a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 261a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_stage_lookups (0/*GSUB*/, 262a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod map->get_feature_stage (0/*GSUB*/, feature_tag), 263a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod &lookups, &count); 264a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 265a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 266a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod inline bool would_substitute (hb_codepoint_t *glyphs, 267a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int glyphs_count, 268b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod bool zero_context, 269a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_face_t *face) const 270a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod { 271a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 272362a990b2246f5448ecb9d600761f710aea7d42dBehdad Esfahbod if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) 273a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return true; 274a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return false; 275a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod } 276a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 277a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod private: 278a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const hb_ot_map_t::lookup_map_t *lookups; 279a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int count; 280a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 281a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 282a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstruct indic_shape_plan_t 283a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 28485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod ASSERT_POD (); 285914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 286914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const 287914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 288914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod hb_codepoint_t glyph = virama_glyph; 289914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (unlikely (virama_glyph == (hb_codepoint_t) -1)) 290914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod { 29111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!config->virama || !font->get_glyph (config->virama, 0, &glyph)) 292914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod glyph = 0; 293914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Technically speaking, the spec says we should apply 'locl' to virama too. 294914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * Maybe one day... */ 295914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 296914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod /* Our get_glyph() function needs a font, so we can't get the virama glyph 297914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */ 298914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph; 299914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 300914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod 301914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod *pglyph = glyph; 302914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod return glyph != 0; 303914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod } 30485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 30511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod const indic_config_t *config; 30685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 30785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod bool is_old_spec; 30885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_codepoint_t virama_glyph; 30985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 310f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod would_substitute_feature_t rphf; 31185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pref; 31285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t blwf; 31385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod would_substitute_feature_t pstf; 31485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 31585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_mask_t mask_array[INDIC_NUM_FEATURES]; 316a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod}; 317a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 318a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void * 319a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_create_indic (const hb_ot_shape_plan_t *plan) 320a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 32185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t)); 32285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (unlikely (!indic_plan)) 323a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return NULL; 324a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 32511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[0]; 32611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++) 32711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (plan->props.script == indic_configs[i].script) { 32811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->config = &indic_configs[i]; 32911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 33085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod } 33111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 332851784f8372004e0a40b698c0cdc2d7db8629aa2Behdad Esfahbod indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2'); 33311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod indic_plan->virama_glyph = (hb_codepoint_t) -1; 33485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 335f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f')); 33685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f')); 33785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f')); 33885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f')); 33985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod 34085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) 34185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod indic_plan->mask_array[i] = indic_features[i].is_global ? 0 : plan->map.get_1_mask (indic_features[i].tag); 342a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 34385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod return indic_plan; 344a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 345a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 346a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic void 347a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahboddata_destroy_indic (void *data) 348a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 349a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod free (data); 350a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 351a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 352a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodstatic indic_position_t 353a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbodconsonant_position_from_face (const indic_shape_plan_t *indic_plan, 354a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_codepoint_t *glyphs, unsigned int glyphs_len, 355a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod hb_face_t *face) 356a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod{ 357b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod bool zero_context = indic_plan->is_old_spec ? false : true; 358b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C; 359b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->blwf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C; 360b5584ee4be46b47e1678acf28426970a6d670b4fBehdad Esfahbod if (indic_plan->pstf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_POST_C; 361a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod return POS_BASE_C; 362a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod} 363a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 364a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod 365166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodenum syllable_type_t { 366166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod consonant_syllable, 367166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod vowel_syllable, 368166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod standalone_cluster, 369166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod broken_cluster, 370166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod non_indic_cluster, 371166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod}; 372166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 373166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod#include "hb-ot-shape-complex-indic-machine.hh" 374166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 375166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 376693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 37716c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodsetup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, 37816c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_buffer_t *buffer, 37916c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_font_t *font HB_UNUSED) 38024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 38124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); 38224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); 38324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 38424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod /* We cannot setup masks here. We save information about characters 38524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod * and setup masks later on in a pause-callback. */ 38624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 38724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod unsigned int count = buffer->len; 38824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 38924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod set_indic_properties (buffer->info[i]); 39024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 39124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 392166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic void 393166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodsetup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, 394166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_font_t *font HB_UNUSED, 395166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod hb_buffer_t *buffer) 396166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod{ 397166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod find_syllables (buffer); 398166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod} 399166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 40024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic int 40124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodcompare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 40224eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod{ 40324eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int a = pa->indic_position(); 40424eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod int b = pb->indic_position(); 40524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 40624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod return a < b ? -1 : a == b ? 0 : +1; 40724eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod} 40824eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 40924eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 41024eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod 41124eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbodstatic void 4128bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodupdate_consonant_positions (const hb_ot_shape_plan_t *plan, 41385fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 41485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer) 4158ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod{ 416a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 4178ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 418a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod unsigned int consonant_pos = indic_plan->is_old_spec ? 0 : 1; 4198ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_codepoint_t glyphs[2]; 420914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->get_virama_glyph (font, &glyphs[1 - consonant_pos])) 4218ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod { 4228ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_face_t *face = font->face; 4238ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod unsigned int count = buffer->len; 4248ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 4258ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod if (buffer->info[i].indic_position() == POS_BASE_C) { 42624eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod glyphs[consonant_pos] = buffer->info[i].codepoint; 427a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, 2, face); 4288ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 4298ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 4308ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod} 4318ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 432867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 4337ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod/* Rules from: 4347ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ 4357ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod 436743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 437f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbodinitial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, 438f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 439f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_buffer_t *buffer, 440ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 441743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 442914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 443ee58f3bc75d2d071a71b94063bf12205a5871acbBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 444743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 445617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod 446743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 1. Find base consonant: 447743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 448743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The shaping engine finds the base consonant of the syllable, using the 449743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following algorithm: starting from the end of the syllable, move backwards 450743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * until a consonant is found that does not have a below-base or post-base 451743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * form (post-base forms have to follow below-base forms), or that is not a 452743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * pre-base reordering Ra, or arrive at the first consonant. The consonant 453743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * stopped at will be the base. 454743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 455743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o If the syllable starts with Ra + Halant (in a script that has Reph) 456743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 457743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * base consonants. 458743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 459743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 4605e72071062c015237b79fbd0521341a63166a204Behdad Esfahbod unsigned int base = end; 46176b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod bool has_reph = false; 462743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 46376b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod { 464617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 465617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 466617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * base consonants. */ 467617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod unsigned int limit = start; 46885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[RPHF] && 469617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod start + 3 <= end && 47011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (/* TODO Handle other Reph modes. */ 47111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || 47211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ) 4733285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod )) 474617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod { 475f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod /* See if it matches the 'rphf' feature. */ 476f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoint}; 477f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face)) 478f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod { 479f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit += 2; 480f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 481f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod limit++; 482f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod base = start; 483f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod has_reph = true; 484f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod } 485617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod }; 48676b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod 48723b0e9d7dc801e11640979af3c2b00649a519bb1Behdad Esfahbod switch (indic_plan->config->base_pos) 4885d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 489d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod default: 490d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod assert (false); 491d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod /* fallthrough */ 492d469fadce8290c7dda559c5927dd19df65f91c1aBehdad Esfahbod 49311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_LAST: 49411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 49511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> starting from the end of the syllable, move backwards */ 49611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int i = end; 49711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod bool seen_below = false; 49811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod do { 49911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod i--; 50011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> until a consonant is found */ 50111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i])) 5025d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 50311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> that does not have a below-base or post-base form 50411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * (post-base forms have to follow below-base forms), */ 50511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() != POS_BELOW_C && 50611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod (info[i].indic_position() != POS_POST_C || seen_below)) 50711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 50811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 50911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 51011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 51111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (info[i].indic_position() == POS_BELOW_C) 51211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod seen_below = true; 51311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 51411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or that is not a pre-base reordering Ra, 51511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 51611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * IMPLEMENTATION NOTES: 51711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * 51811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * Our pre-base reordering Ra's are marked POS_BELOW, so will be skipped 51911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * by the logic above already. 52011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod */ 52111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 52211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* -> or arrive at the first consonant. The consonant stopped at will 52311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * be the base. */ 5245d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod base = i; 5255d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 52611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 52711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 52811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* A ZWJ after a Halant stops the base search, and requests an explicit 52911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * half form. 53011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * A ZWJ before a Halant, requests a subjoined form instead, and hence 53111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * search continues. This is particularly important for Bengali 532c4be9917438c45b972ec76dc68409014110f0837Behdad Esfahbod * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */ 53311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (start < i && 53411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_category() == OT_ZWJ && 53511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i - 1].indic_category() == OT_H) 53611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 53711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 53811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } while (i > limit); 53911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 54011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 5415d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 54211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod case BASE_POS_FIRST: 54311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 54411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* In scripts without half forms (eg. Khmer), the first consonant is always the base. */ 5455d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 54611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (!has_reph) 54711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = limit; 54834c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 54911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Find the last base consonant that is not blocked by ZWJ. If there is 55011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod * a ZWJ right before a base consonant, that would request a subjoined form. */ 55111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = limit; i < end; i++) 55211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 55311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod { 55411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (limit < i && info[i - 1].indic_category() == OT_ZWJ) 55511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 55611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod else 55711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod base = i; 55811b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 55934c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 56011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* Mark all subsequent consonants as below. */ 56111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 56211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 56311b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod info[i].indic_position() = POS_BELOW_C; 56411b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod } 56511b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod break; 5665d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 567743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 568617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 569617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 5702278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * base consonants. 5712278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * 5722278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ 5732278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod if (has_reph && base == start && start + 2 == limit) { 574617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* Have no other consonant, so Reph is not formed and Ra becomes base. */ 575617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = false; 576617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod } 5775e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod } 5782278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod 57934c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod if (base < end) 58034c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod info[base].indic_position() = POS_BASE_C; 5813d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 5823d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 583743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 2. Decompose and reorder Matras: 584743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 585743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Each matra and any syllable modifier sign in the cluster are moved to the 586743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * appropriate position relative to the consonant(s) in the cluster. The 587743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * shaping engine decomposes two- or three-part matras into their constituent 588743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * parts before any repositioning. Matra characters are classified by which 589743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * consonant in a conjunct they have affinity for and are reordered to the 590743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following positions: 591743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 592743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o Before first half form in the syllable 593743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After subjoined consonants 594743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After post-form consonant 595743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After main consonant (for above marks) 596743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 597743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 598743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 599743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The normalize() routine has already decomposed matras for us, so we don't 600743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * need to worry about that. 601743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 602743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 603743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 604743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 3. Reorder marks to canonical order: 605743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 606743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Adjacent nukta and halant or nukta and vedic sign are always repositioned 607743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * if necessary, so that the nukta is first. 608743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 609743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 610743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 611743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * We don't need to do this: the normalize() routine already did this for us. 612743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 613743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 614743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 61545d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod /* Reorder characters */ 61645d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 6173c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 618900cf3d449bf36d4f8b1474590cae925fef48fc8Behdad Esfahbod info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position()); 61955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 620075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 621075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].indic_position() = POS_BASE_C; 62245d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 62355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod /* Mark final consonants. A final consonant is one appearing after a matra, 62455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod * like in Khmer. */ 62555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 62655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (info[i].indic_category() == OT_M) { 62755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int j = i + 1; j < end; j++) 62855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (is_consonant (info[j])) { 62955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod info[j].indic_position() = POS_FINAL_C; 63055f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 63155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 63255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 63355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 63455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 635fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod /* Handle beginning Ra */ 6365e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod if (has_reph) 637dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() = POS_RA_TO_BECOME_REPH; 638fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod 639f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* For old-style Indic script tags, move the first post-base Halant after 640f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod * last consonant. */ 641914ffaa40fcca020f65bacdd709421e9047afd83Behdad Esfahbod if (indic_plan->is_old_spec) { 6423c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 643f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (info[i].indic_category() == OT_H) { 644f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod unsigned int j; 645f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod for (j = end - 1; j > i; j--) 646190eb31a16178269aecaf5d2ecc9012f956749f4Behdad Esfahbod if (is_consonant (info[j])) 647f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 648f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (j > i) { 649f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* Move Halant to after last consonant. */ 650f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod hb_glyph_info_t t = info[i]; 651f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); 652f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod info[j] = t; 653f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 654f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 655f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 656f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 657f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod 65881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* Attach misc marks to previous char to move with them. */ 659ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 66081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod indic_position_t last_pos = POS_START; 66181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod for (unsigned int i = start; i < end; i++) 66281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 66381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS))) 66481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 66581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() = last_pos; 666dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod if (unlikely (info[i].indic_category() == OT_H && 66781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() == POS_PRE_M)) 66881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 66981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* 67081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * Uniscribe doesn't move the Halant with Left Matra. 67181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * TEST: U+092B,U+093F,U+094DE 672dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We follow. This is important for the Sinhala 673dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA 674dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * where U+0DD9 is a left matra and U+0DCA is the virama. 675dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * We don't want to move the virama with the left matra. 676dde5506fd963e3cec27c3389bb1fc092f86d1e06Behdad Esfahbod * TEST: U+0D9A,U+0DDA 67781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod */ 678ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod for (unsigned int j = i; j > start; j--) 6796a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[j - 1].indic_position() != POS_PRE_M) { 680ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod info[i].indic_position() = info[j - 1].indic_position(); 681ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod break; 682ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 68381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 68481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } else if (info[i].indic_position() != POS_SMVD) { 68581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod last_pos = (indic_position_t) info[i].indic_position(); 686ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 68781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 688ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 68974ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod /* Re-attach ZWJ, ZWNJ, and halant to next char, for after-base consonants. */ 69074ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod { 69174ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod unsigned int last_halant = end; 69274ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 693deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (is_halant_or_coeng (info[i])) 69474ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod last_halant = i; 69574ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod else if (is_consonant (info[i])) { 69674ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int j = last_halant; j < i; j++) 69781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if (info[j].indic_position() != POS_SMVD) 69881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[j].indic_position() = info[i].indic_position(); 69974ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 70074ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 70145d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 702a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod { 7037b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod /* Things are out-of-control for post base positions, they may shuffle 7047b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * around like crazy, so merge clusters. For pre-base stuff, we handle 7057b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * cluster issues in final reordering. */ 7067b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod buffer->merge_clusters (base, end); 707a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Sit tight, rock 'n roll! */ 708d3637edb248162970e202e9d0671540274192844Behdad Esfahbod hb_bubble_sort (info + start, end - start, compare_indic_order); 709a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Find base again */ 710a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = end; 7113c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < end; i++) 712a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod if (info[i].indic_position() == POS_BASE_C) { 713a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = i; 714a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod break; 715a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 716a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 71745d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 718743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Setup masks now */ 719743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 720281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod { 721281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod hb_mask_t mask; 722281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod 723dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* Reph */ 724668c6046c1b3af3bd316bda0cc8636f2a5e8df42Behdad Esfahbod for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) 72585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[RPHF]; 726dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 727281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Pre-base */ 72885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[HALF]; 7293c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 730281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 731281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Base */ 73220b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = 0; 733075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 734075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].mask |= mask; 735281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Post-base */ 73685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF]; 7373c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 738281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 739281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod } 7409da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 74185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 2 < end) 74217d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod { 743771a8f50289e8fa458cfc3cd84f73a380ce98077Behdad Esfahbod /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ 74456be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod for (unsigned int i = base + 1; i + 1 < end; i++) { 74556be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint}; 74656be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face)) 7478e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 74885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 74985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i++].mask |= indic_plan->mask_array[PREF]; 7500201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 7510201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod /* Mark the subsequent stuff with 'cfar'. Used in Khmer. 7520201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * Read the feature spec. 7530201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * This allows distinguishing the following cases with MS Khmer fonts: 7540201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+179A,U+17D2,U+1782 7550201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+1782,U+17D2,U+179A 7560201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod */ 7570201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod for (; i < end; i++) 75885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[i].mask |= indic_plan->mask_array[CFAR]; 7590201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 7608e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 7618e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 76256be677781736bbedc80df6f6aaa2b5f0bc4041cBehdad Esfahbod } 76317d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod } 76417d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod 7659da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod /* Apply ZWJ/ZWNJ effects */ 7663c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start + 1; i < end; i++) 7679da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod if (is_joiner (info[i])) { 7689da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod bool non_joiner = info[i].indic_category() == OT_ZWNJ; 7696b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod unsigned int j = i; 7709da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 7719da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod do { 7729da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod j--; 7736b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 77420b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWJ disables CJCT, however, it's mere presence is enough 77520b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod * to disable ligation. No explicit action needed. */ 77620b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod 77720b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWNJ disables HALF. */ 7786b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod if (non_joiner) 77985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[j].mask &= ~indic_plan->mask_array[HALF]; 7806b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 7819da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } while (j > start && !is_consonant (info[j])); 7829da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } 783743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 784743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 785743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 786743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7878bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan, 788f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 7899f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 790ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 791743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 792c5306b6861cfaa50af40e8ceb058791fa06d7981Behdad Esfahbod /* We made the vowels look like consonants. So let's call the consonant logic! */ 793f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 794743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 795743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 796743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 7978bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, 798f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 7999f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 800ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 801743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 80218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain. 80318c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Only if not in compatibility mode that is... */ 80418c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 805a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 80618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod { 80718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* For dotted-circle, this is what Uniscribe does: 80818c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * If dotted-circle is the last glyph, it just does nothing. 80918c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Ie. It doesn't form Reph. */ 81018c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) 81118c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod return; 81218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod } 81318c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 814f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_consonant_syllable (plan, face, buffer, start, end); 815743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 816743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 817743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 818b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodinitial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan, 819f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 820b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer, 821b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int start, unsigned int end) 822b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 823b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod /* We already inserted dotted-circles, so just call the standalone_cluster. */ 824f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_standalone_cluster (plan, face, buffer, start, end); 825b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 826b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 827b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 828327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 829f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face HB_UNUSED, 830327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 831327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 832743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 833743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 834743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 835743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 836743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 837327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 838743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 839327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbodinitial_reordering_syllable (const hb_ot_shape_plan_t *plan, 840f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod hb_face_t *face, 841327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_buffer_t *buffer, 842327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int start, unsigned int end) 843327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod{ 844327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); 845327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod switch (syllable_type) { 846f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; 847f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return; 848f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return; 849f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; 850f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return; 851327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 852327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod} 853327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 854166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbodstatic inline void 855b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodinsert_dotted_circles (const hb_ot_shape_plan_t *plan, 856b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_font_t *font, 857b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_buffer_t *buffer) 858b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 859166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod /* Note: This loop is extra overhead, but should not be measurable. */ 860166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod bool has_broken_syllables = false; 861166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod unsigned int count = buffer->len; 862166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod for (unsigned int i = 0; i < count; i++) 863166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) { 864166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod has_broken_syllables = true; 865166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod break; 866166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod } 867166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod if (likely (!has_broken_syllables)) 868166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod return; 869166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 870166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod 871b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_codepoint_t dottedcircle_glyph; 872b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) 873b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return; 874b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 875f41dc2d35b23220d59d38990bb66f1cbd66a55b3Behdad Esfahbod hb_glyph_info_t dottedcircle = {0}; 876b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = 0x25CC; 877b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod set_indic_properties (dottedcircle); 878b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod dottedcircle.codepoint = dottedcircle_glyph; 879b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 880b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->clear_output (); 881b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 882b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->idx = 0; 883b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int last_syllable = 0; 884b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod while (buffer->idx < buffer->len) 885b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 886b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int syllable = buffer->cur().syllable(); 887b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); 888b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) 889b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod { 890b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod hb_glyph_info_t info = dottedcircle; 891b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.cluster = buffer->cur().cluster; 892b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.mask = buffer->cur().mask; 893b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod info.syllable() = buffer->cur().syllable(); 894b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->output_info (info); 895b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod last_syllable = syllable; 896b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 897b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->next_glyph (); 898b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod } 899b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 900b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod buffer->swap_buffers (); 901b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 902b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 903b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic void 9048bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodinitial_reordering (const hb_ot_shape_plan_t *plan, 90524eacf17c801c66a2d466e8ae02b73f501a26b25Behdad Esfahbod hb_font_t *font, 9063e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 907743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 90885fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod update_consonant_positions (plan, font, buffer); 909166b5cf7ec2d37fb54a909c437ccdec1edaf37aaBehdad Esfahbod insert_dotted_circles (plan, font, buffer); 910327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod 911327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 912b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod unsigned int count = buffer->len; 913b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod if (unlikely (!count)) return; 914327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last = 0; 915327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 916327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 917327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (last_syllable != info[i].syllable()) { 918f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, i); 919327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last = i; 920327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod last_syllable = info[last].syllable(); 921327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod } 922f2c0f59043c93c225274fc0c8177077d16c89d61Behdad Esfahbod initial_reordering_syllable (plan, font->face, buffer, last, count); 923b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 924b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 925743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 92685fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbodfinal_reordering_syllable (const hb_ot_shape_plan_t *plan, 92785fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_buffer_t *buffer, 928ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 929743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 93085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; 9314ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 9324ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 933e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod /* 4. Final reordering: 934e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 935e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * After the localized forms and basic shaping forms GSUB features have been 936e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * applied (see below), the shaping engine performs some final glyph 937e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * reordering before applying all the remaining font features to the entire 938e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * cluster. 9394ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 9404ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 9414ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* Find base again */ 9425f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod unsigned int base; 9435f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod for (base = start; base < end; base++) 9445f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (info[base].indic_position() >= POS_BASE_C) { 9455f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (start < base && info[base].indic_position() > POS_BASE_C) 9465f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod base--; 9475f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod break; 9485f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod } 9494ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 9504705a7026900e51f6430f03a73c87f2df035df92Behdad Esfahbod 9514ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder matras: 952e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 953e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base matra character had been reordered before applying basic 954e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * features, the glyph can be moved closer to the main consonant based on 955e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * whether half-forms had been formed. Actual position for the matra is 956e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * defined as “after last standalone halant glyph, after initial matra 957e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * position and before the main consonant”. If ZWJ or ZWNJ follow this 958e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * halant, position is moved after it. 9594ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 9604ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 96165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ 9629d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 96365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we lost track of base, alas, position before last thingy. */ 96465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod unsigned int new_pos = base == end ? base - 2 : base - 1; 96565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 96627bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 96727bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 96827bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod * We want to position matra after them. 96965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod */ 97027bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 971e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod { 97265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod while (new_pos > start && 97365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng))))) 97465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos--; 97565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 97665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we found no Halant we are done. 97765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * Otherwise only proceed if the Halant does 97865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * not belong to the Matra itself! */ 97965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (is_halant_or_coeng (info[new_pos]) && 98065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod info[new_pos].indic_position() != POS_PRE_M) 98165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 98265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 98365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) 98465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos++; 98565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 98665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod else 98765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos = start; /* No move. */ 98865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 9899d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod 99027bd55bd2ca599d501f10c2fae81861137517e46Behdad Esfahbod if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M) 99165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 9929d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* Now go see if there's actually any matras... */ 993921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod for (unsigned int i = new_pos; i > start; i--) 9946a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[i - 1].indic_position () == POS_PRE_M) 9959d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 9961a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod unsigned int old_pos = i - 1; 9971a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 9981a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0])); 9991a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod info[new_pos] = tmp; 1000921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod new_pos--; 10019d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 10022cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (new_pos, MIN (end, base + 1)); 1003abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } else { 1004e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod for (unsigned int i = start; i < base; i++) 1005abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod if (info[i].indic_position () == POS_PRE_M) { 10062cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (i, MIN (end, base + 1)); 1007abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod break; 1008abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } 10099d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 10104ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod } 10114ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 10124ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 10134ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder reph: 1014e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1015e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Reph’s original position is always at the beginning of the syllable, 1016e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * (i.e. it is not reordered at the character reordering stage). However, 1017e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * it will be reordered according to the basic-forms shaping results. 1018e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Possible positions for reph, depending on the script, are; after main, 1019e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * before post-base consonant forms, and after post-base consonant forms. 1020dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 1021dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1022dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* If there's anything after the Ra that has the REPH pos, it ought to be halant. 1023dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Which means that the font has failed to ligate the Reph. In which case, we 1024dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * shouldn't move. */ 1025dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod if (start + 1 < end && 1026dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() == POS_RA_TO_BECOME_REPH && 1027dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH) 1028dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod { 102911b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod unsigned int new_reph_pos; 103011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod reph_position_t reph_pos = indic_plan->config->reph_pos; 103111b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod 103211b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod /* XXX Figure out old behavior too */ 103302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1034dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* 1. If reph should be positioned after post-base consonant forms, 1035dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to step 5. 103602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 103711b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_POST) 103802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 10399d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_step_5; 104002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 104102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 104202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 2. If the reph repositioning class is not after post-base: target 1043dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is after the first explicit halant glyph between the 1044dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-reph consonant and last main consonant. If ZWJ or ZWNJ 1045dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * are following this halant, position is moved after it. If such 1046dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is found, this is the target position. Otherwise, 1047dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to the next step. 1048dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * 1049dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Note: in old-implementation fonts, where classifications were 1050dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * fixed in shaping engine, there was no case where reph position 1051dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * will be found on this step. 105202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 105302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 105402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = start + 1; 1055deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 105602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 105702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1058deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 105902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 106002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 106102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 106202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 106302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 106402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 106502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 106602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 3. If reph should be repositioned after the main consonant: find the 1067dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first consonant not ligated with main, or find the first 1068dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant that is not a potential pre-base reordering Ra. 106902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 107011b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_MAIN) 107102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1072b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos = base; 1073b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod /* XXX Skip potential pre-base reordering Ra. */ 107434ae336f3fae93ef9372881d545c817bce383041Behdad Esfahbod while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN) 1075b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos++; 1076b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod if (new_reph_pos < end) 1077b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod goto reph_move; 107802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 107902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 108002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 4. If reph should be positioned before post-base consonant, find 1081dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-base classified consonant not ligated with main. If no 1082dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant is found, the target position should be before the 1083dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first matra, syllable modifier sign or vedic sign. 108402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 10859d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* This is our take on what step 4 is trying to say (and failing, BADLY). */ 108611b0e20ba42bf0b17133c3e1087732802bb4f230Behdad Esfahbod if (reph_pos == REPH_POS_AFTER_SUB) 108702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 10889d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos = base; 10899d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod while (new_reph_pos < end && 1090be8b9f5f715f6fb36b98bd33c3303f79cc068f8aBehdad Esfahbod !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD)))) 10919d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos++; 10929d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (new_reph_pos < end) 10939d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_move; 109402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 109502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 109602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 5. If no consonant is found in steps 3 or 4, move reph to a position 1097dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * immediately before the first post-base matra, syllable modifier 1098dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * sign or vedic sign that has a reordering class after the intended 1099dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * reph position. For example, if the reordering position for reph 1100dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * is post-main, it will skip above-base matras that also have a 1101dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * post-main position. 1102dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 110302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_step_5: 110402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1105d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* Copied from step 2. */ 1106d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos = start + 1; 1107d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 1108d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1109d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod 1110d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 1111d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 1112d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 1113d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 1114d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod goto reph_move; 1115d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod } 111602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1117dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 111802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 6. Otherwise, reorder reph to the end of the syllable. 111902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 112002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 112102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = end - 1; 112202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD) 112302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 112402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 1125892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod /* 1126892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * If the Reph is to be ending up after a Matra,Halant sequence, 1127892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * position it before that Halant so it can interact with the Matra. 1128892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * However, if it's a plain Consonant,Halant we shouldn't do that. 1129892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * Uniscribe doesn't do this. 1130892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * TEST: U+0930,U+094D,U+0915,U+094B,U+094D 1131892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod */ 1132a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (!indic_options ().uniscribe_bug_compatible && 1133deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod unlikely (is_halant_or_coeng (info[new_reph_pos]))) { 113402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod for (unsigned int i = base + 1; i < new_reph_pos; i++) 113502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (info[i].indic_category() == OT_M) { 113602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Ok, got it. */ 113702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 113802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 113902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 114002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 11418df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod } 11428df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod 114302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_move: 114402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 1145e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod /* Yay, one big cluster! Merge before moving. */ 1146e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 1147e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod 114802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Move */ 114902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod hb_glyph_info_t reph = info[start]; 115002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0])); 115102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod info[new_reph_pos] = reph; 115202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 1153dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod } 1154dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1155dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 1156dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* o Reorder pre-base reordering consonants: 1157e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 1158e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base reordering consonant is found, reorder it according to 1159e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * the following rules: 1160e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod */ 1161e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 116285fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ 116346e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod { 11648e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 116585fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) 116678818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod { 11678e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 1. Only reorder a glyph produced by substitution during application 11688e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * of the <pref> feature. (Note that a font may shape a Ra consonant with 11698e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * the feature generally but block it in certain contexts.) 11708e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 117185fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod if (i + 1 == end || (info[i + 1].mask & indic_plan->mask_array[PREF]) == 0) 11728e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 11738e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 11748e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 2. Try to find a target position the same way as for pre-base matra. 11758e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * If it is found, reorder pre-base consonant glyph. 11768e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 11778e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 3. If position is not found, reorder immediately before main 11788e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * consonant. 11798e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 11808e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 11818e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int new_pos = base; 118288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* Malayalam / Tamil do not have "half" forms or explicit virama forms. 118388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * The glyphs formed by 'half' are Chillus or ligated explicit viramas. 118488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * We want to position matra after them. 118588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod */ 118688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) 1187d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 118888d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod while (new_pos > start && 118988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS))) 119088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 119188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod 119288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod /* In Khmer coeng model, a V,Ra can go *after* matras. If it goes after a 119388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod * split matra, it should be reordered to *before* the left part of such matra. */ 119488d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) 119588d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 119688d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod unsigned int old_pos = i; 119788d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod for (unsigned int i = base + 1; i < old_pos; i++) 119888d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod if (info[i].indic_category() == OT_M) 119988d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod { 120088d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod new_pos--; 120188d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod break; 120288d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 120388d3c98e309e14c3115825d1d8d40d0b3eec2d97Behdad Esfahbod } 1204d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1205d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod 1206deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) 12078e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 12088e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if (new_pos < end && is_joiner (info[new_pos])) 12098e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos++; 12108e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 12118e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 12128e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int old_pos = i; 1213e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (new_pos, old_pos + 1); 12148e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 12158e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0])); 12168e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[new_pos] = tmp; 12178e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 12188e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 12198e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 12208e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 122178818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod } 122246e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod } 1223eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1224eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1225a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod /* Apply 'init' to the Left Matra if it's a word start. */ 12266a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[start].indic_position () == POS_PRE_M && 1227a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod (!start || 1228eace47b173807d94b29a6490d0bc3c9f8f6168d1Behdad Esfahbod !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & 12292c372b80f6befad69e216e3f218b38640b8cc044Behdad Esfahbod FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))) 123085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod info[start].mask |= indic_plan->mask_array[INIT]; 1231a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod 1232eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 12338ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod /* 12348ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod * Finish off the clusters and go home! 12358ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod */ 1236decf6ffca475fe01ff3151b7641f629f031137d2Behdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 1237ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 123830c3d5e9fc61b49c2c6ad4e744300edd6f3e0261Behdad Esfahbod /* Uniscribe merges the entire cluster. 123921d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This means, half forms are submerged into the main consonants cluster. 124021d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This is unnecessary, and makes cursor positioning harder, but that's what 124121d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * Uniscribe does. */ 1242e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 124321d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod } 1244ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod} 1245e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1246e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1247ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbodstatic void 12488bb5deba9630d35878eb6edb4643ecfabf99f15fBehdad Esfahbodfinal_reordering (const hb_ot_shape_plan_t *plan, 124985fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod hb_font_t *font, 12503e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod hb_buffer_t *buffer) 1251ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod{ 1252ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int count = buffer->len; 1253327d14ef188396006d54af976506ab6f8bb2869aBehdad Esfahbod if (unlikely (!count)) return; 1254ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod 1255ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1256ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int last = 0; 1257cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1258ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1259cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod if (last_syllable != info[i].syllable()) { 126085fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, i); 1261ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod last = i; 1262cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod last_syllable = info[last].syllable(); 1263ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod } 126485fc6c483f6d734febbe39270e84701a651f01f1Behdad Esfahbod final_reordering_syllable (plan, buffer, last, count); 1265e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 126680cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod /* Zero syllables now... */ 126780cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 126880cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod info[i].syllable() = 0; 126980cd92326f8a3f48a7821e720e8ecb2072e73286Behdad Esfahbod 1270743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); 1271743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); 1272743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1273743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1274743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1275b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbodstatic hb_ot_shape_normalization_mode_t 12760736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbodnormalization_preference_indic (const hb_segment_properties_t *props) 1277b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod{ 1278b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT; 1279b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod} 1280b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod 1281eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1282eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahboddecompose_indic (const hb_ot_shape_normalize_context_t *c, 12830736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t ab, 12840736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *a, 12850736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *b) 12860736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 12870736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod switch (ab) 12880736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 12890736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Don't decompose these. */ 12900736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0931 : return false; 12910736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0B94 : return false; 12920736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 12930736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 12940736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* 12950736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod * Decompose split matras that don't have Unicode decompositions. 12960736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod */ 12970736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 12980736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true; 12990736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true; 13000736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true; 13010736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true; 13020736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true; 13030736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true; 13040736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true; 13050736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1925 : *a = 0x1920; *b= 0x1923; return true; 13060736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1926 : *a = 0x1920; *b= 0x1924; return true; 13070736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true; 13080736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1112E : *a = 0x11127; *b= 0x11131; return true; 13090736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1112F : *a = 0x11127; *b= 0x11132; return true; 13100736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#if 0 13110736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* This one has no decomposition in Unicode, but needs no decomposition either. */ 13120736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* case 0x0AC9 : return false; */ 13130736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x0B57 : *a = no decomp, -> RIGHT; return true; 13140736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x1C29 : *a = no decomp, -> LEFT; return true; 13150736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0xA9C0 : *a = no decomp, -> RIGHT; return true; 13160736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod case 0x111BF : *a = no decomp, -> ABOVE; return true; 13170736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#endif 13180736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 13190736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 132043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod if ((ab == 0x0DDA || hb_in_range<hb_codepoint_t> (ab, 0x0DDC, 0x0DDE))) 13210736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod { 132243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* 132343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Sinhala split matras... Let the fun begin. 132443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 132543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * These four characters have Unicode decompositions. However, Uniscribe 132643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * decomposes them "Khmer-style", that is, it uses the character itself to 132743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * get the second half. The first half of all four decompositions is always 132843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * U+0DD9. 132943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 133043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are 133143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * broken with Uniscribe. But we need to support them. As such, we only 133243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * do the Uniscribe-style decomposition if the character is transformed into 133343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * its "sec.half" form by the 'pstf' feature. Otherwise, we fall back to 133443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Unicode decomposition. 133543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 133643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Note that we can't unconditionally use Unicode decomposition. That would 133743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * break some other fonts, that are designed to work with Uniscribe, and 133843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * don't have positioning features for the Unicode-style decomposition. 133943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * 134043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod * Argh... 134143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod */ 134243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 134343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data; 134443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 134543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod hb_codepoint_t glyph; 134643b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod 134743b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible || 134843b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod (c->font->get_glyph (ab, 0, &glyph) && 134943b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face))) 135043b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod { 135143b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod /* Ok, safe to use Uniscribe-style decomposition. */ 135243b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *a = 0x0DD9; 135343b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod *b = ab; 135443b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod return true; 135543b653150081a2f9dc6b7481229ac4cd952575dcBehdad Esfahbod } 13560736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod } 13570736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1358eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->decompose (ab, a, b); 13590736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 13600736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1361eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 1362eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodcompose_indic (const hb_ot_shape_normalize_context_t *c, 13630736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t a, 13640736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t b, 13650736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *ab) 13660736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod{ 13670736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Avoid recomposing split matras. */ 1368eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a))) 13690736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod return false; 13700736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 13710736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod /* Composition-exclusion exceptions that we want to recompose. */ 13720736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; } 13730736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1374eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->compose (a, b, ab); 13750736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod} 13760736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 13770736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 1378693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = 1379693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{ 1380693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod "indic", 1381693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod collect_features_indic, 1382693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod override_features_indic, 1383a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_create_indic, 1384a8c6da90f4c6e8d27a3a1b758a55476776d9f750Behdad Esfahbod data_destroy_indic, 13859f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod NULL, /* preprocess_text */ 1386b85800f9de8976a7418ef9df467d3080c6ab0199Behdad Esfahbod normalization_preference_indic, 13870736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod decompose_indic, 13880736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod compose_indic, 1389693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod setup_masks_indic, 13901e7d860613032e40a3f90e2caa2ee5ac44ab8c8cBehdad Esfahbod false, /* zero_width_attached_marks */ 1391865745b5b87236651f5663cae3461db9cb505eedBehdad Esfahbod false, /* fallback_position */ 1392693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod}; 1393